From 823f0d1dde9270efb0ec0fb3d8fbcc99db71361f Mon Sep 17 00:00:00 2001 From: MiguelMarcelino Date: Thu, 22 Sep 2022 19:51:12 +0100 Subject: [PATCH 1/3] Fix inference bug with If node --- py2many/inference.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/py2many/inference.py b/py2many/inference.py index 1f041da8b..8155e9ec4 100644 --- a/py2many/inference.py +++ b/py2many/inference.py @@ -958,6 +958,12 @@ def _visit_val_branch(self, node: ast.If, ann, ann_node_id): ann_node.annotation = ast.Name(id="None") for n in node.orelse: self.visit(n) + else: + node.test.annotation = ann + for n in node.body: + self.visit(n) + for n in node.orelse: + self.visit(n) def _visit_none_branch(self, node: ast.If, ann, ann_node_id): if self._is_optional(ann): @@ -969,6 +975,12 @@ def _visit_none_branch(self, node: ast.If, ann, ann_node_id): ann_node.annotation = ann.slice for n in node.orelse: self.visit(n) + else: + node.test.annotation = ann + for n in node.body: + self.visit(n) + for n in node.orelse: + self.visit(n) def _is_optional(self, annotation): is_optional = lambda x: get_id(x) == "Optional" From ac11b642b575c32f5893c59aad5722d0552454d8 Mon Sep 17 00:00:00 2001 From: MiguelMarcelino Date: Thu, 22 Sep 2022 19:53:14 +0100 Subject: [PATCH 2/3] Improve translation of Boolean Operations --- py2many/cli.py | 4 +-- pyjl/plugins.py | 3 ++ pyjl/rewriters.py | 89 +++++++++++++++++++++++++++++++++------------- pyjl/transpiler.py | 4 +++ 4 files changed, 74 insertions(+), 26 deletions(-) diff --git a/py2many/cli.py b/py2many/cli.py index e66f84b30..3e73df31d 100755 --- a/py2many/cli.py +++ b/py2many/cli.py @@ -63,7 +63,7 @@ JuliaImportRewriter, JuliaAugAssignRewriter, JuliaGeneratorRewriter, - JuliaConditionRewriter, + JuliaBoolOpRewriter, JuliaIndexingRewriter, JuliaMainRewriter, JuliaMethodCallRewriter, @@ -520,7 +520,7 @@ def julia_settings(args, env=os.environ): JuliaClassWrapper(), JuliaMethodCallRewriter(), JuliaAugAssignRewriter(), - JuliaConditionRewriter(), + JuliaBoolOpRewriter(), VariableScopeRewriter(), JuliaIORewriter(), JuliaArbitraryPrecisionRewriter(), diff --git a/pyjl/plugins.py b/pyjl/plugins.py index 44b6d19d1..43a2831f2 100644 --- a/pyjl/plugins.py +++ b/pyjl/plugins.py @@ -950,6 +950,9 @@ def visit_isinstance(self, node: ast.Call, vargs: list[str], kwargs: list[tuple[ is_pycall_import = JuliaTranspilerPlugins._check_pycall_import(self, vargs[1]) if is_pycall_import: return f"pybuiltin(:isinstance)({vargs[0]}, {self._map_type(vargs[1])})" + elif isinstance(node.args[1], ast.Tuple): + elts = list(map(lambda x: self._map_type(self.visit(x)), node.args[1].elts)) + return f"isa({vargs[0]}, Union{{{', '.join(elts)}}})" return f"isa({vargs[0]}, {self._map_type(vargs[1])})" def visit_issubclass(self, node: ast.Call, vargs: list[str], kwargs: list[tuple[str,str]]): diff --git a/pyjl/rewriters.py b/pyjl/rewriters.py index 33e9eb9d7..635a9e1f1 100644 --- a/pyjl/rewriters.py +++ b/pyjl/rewriters.py @@ -393,7 +393,7 @@ def visit_Assign(self, node: ast.Assign) -> Any: return node -class JuliaConditionRewriter(ast.NodeTransformer): +class JuliaBoolOpRewriter(ast.NodeTransformer): """Rewrites condition checks to Julia compatible ones All checks that perform equality checks with the literal '1' have to be converted to equality checks with true""" @@ -422,32 +422,73 @@ def _generic_test_visit(self, node): return node annotation = getattr(node.test, "annotation", None) - ann_id = get_id(annotation) - if ann_id == "int" or ann_id == "float": - node.test = self._build_compare(node.test, - ast.NotEq(), 0) - - if hasattr(node.test, "annotation"): - type_str: str = get_ann_repr(node.test.annotation, sep=SEP) - match = re.match(r"^Optional|^list|^List|^tuple|^Tuple", type_str) \ - if type_str else False - if match: + ann_id = get_ann_repr(annotation, sep=SEP) + if ann_id: + if ann_id == "int" or ann_id == "float": + node.test = self._build_compare(node.test, + [ast.NotEq()], [ast.Constant(value=0)]) + elif re.match(r"^list|^List", ann_id): + # Compare with empty list + node.test = self._build_compare(node.test, + [ast.IsNot()], [ast.List(elts=[])]) + elif re.match(r"^tuple|^Tuple", ann_id): + # Compare with empty tuple + node.test = self._build_compare(node.test, + [ast.IsNot()], [ast.Tuple(elts=[])]) + elif re.match(r"^Optional", ann_id): + # Compare with type None node.test = self._build_compare(node.test, - ast.IsNot(), None) + [ast.IsNot()], [ast.Constant(value=None)]) + else: + node.test = self._build_runtime_comparison(node) + else: + node.test = self._build_runtime_comparison(node) - def _build_compare(self, node, op, comp_value): + def _build_compare(self, node, ops, comp_values): + for comp_value in comp_values: + ast.fix_missing_locations(comp_value) + comp_value.scopes = node.scopes return ast.Compare( - left = node, - ops = [op], - comparators = [ - ast.Constant( - comp_value, - lineno = node.lineno, - col_offset = node.col_offset, - scopes = node.scopes)], - lineno = node.lineno, - col_offset = node.col_offset, - scopes = node.scopes) + left = node, + ops = ops, + comparators = comp_values, + lineno = node.lineno, + col_offset = node.col_offset, + scopes = node.scopes) + + def _build_runtime_comparison(self, node): + # Perform dynamic comparison + instance_check = lambda args: ast.Call( + func = ast.Name(id="isinstance"), + args = args, + keywords = [], + scopes = getattr(node, "scopes", None)) + test_node = ast.BoolOp( + op = ast.Or(), + values = [ + ast.BoolOp( + op = ast.And(), + values = [ + instance_check([node.test, + ast.Tuple(elts=[ast.Name(id="int"), ast.Name(id="float")])]), + self._build_compare(node.test, [ast.NotEq()], [ast.Constant(value=0)])]), + ast.BoolOp( + op = ast.And(), + values = [ + instance_check([node.test, ast.Name(id="tuple")]), + self._build_compare(node.test, [ast.NotEq()], [ast.Tuple(elts=[])])]), + ast.BoolOp( + op = ast.And(), + values = [ + instance_check([node.test, ast.Name(id="list")]), + self._build_compare(node.test, [ast.NotEq()], [ast.List(elts=[])])]), + ast.BoolOp( + op = ast.And(), + values = [self._build_compare(node.test, [ast.Is()], [ast.Constant(value=None)])]) + ] + ) + ast.fix_missing_locations(node.test) + return test_node def visit_Compare(self, node: ast.Compare) -> Any: # Julia comparisons with 'None' use Henry Baker's EGAL predicate diff --git a/pyjl/transpiler.py b/pyjl/transpiler.py index bb2d0b1a0..c5f692fa9 100644 --- a/pyjl/transpiler.py +++ b/pyjl/transpiler.py @@ -1308,6 +1308,10 @@ def visit_Nonlocal(self, node: ast.Nonlocal) -> str: names = ", ".join(node.names) return f"# Not Supported\n# nonlocal {names}" + def visit_BoolOp(self, node): + op = self.visit(node.op) + return f"({op.join([self.visit(v) for v in node.values])})" + ###################################################### #################### Julia Nodes ##################### ###################################################### From a8df62efea5416cf463ed4250d4c4fb4ccfd3d68 Mon Sep 17 00:00:00 2001 From: MiguelMarcelino Date: Thu, 22 Sep 2022 19:57:52 +0100 Subject: [PATCH 3/3] Check for module presence of least used external modules --- pyjl/external/modules/ctypes.py | 83 ++++++++++++++------------ pyjl/external/modules/gzip.py | 22 ++++--- pyjl/external/modules/pandas.py | 31 ++++++---- pyjl/external/modules/pyproj.py | 27 +++++---- pyjl/external/modules/requests_mock.py | 29 +++++---- pyjl/external/modules/shapely.py | 35 +++++------ pyjl/external/modules/shutil.py | 25 ++++---- pyjl/external/modules/tqdm.py | 15 +++-- pyjl/external/modules/zipfile.py | 15 +++-- 9 files changed, 158 insertions(+), 124 deletions(-) diff --git a/pyjl/external/modules/ctypes.py b/pyjl/external/modules/ctypes.py index 9d75e2bcf..40719a946 100644 --- a/pyjl/external/modules/ctypes.py +++ b/pyjl/external/modules/ctypes.py @@ -108,36 +108,7 @@ def visit_Libdl(self, node: ast.Call, vargs: list[str], kwargs: list[tuple[str,s "LPCWSTR": lambda node, vargs, kwargs: f"isa({vargs[0]}, String) ? Cwstring(pointer(transcode(Cwchar_t, {vargs[0]}))) : Cwstring(Ptr{{Cwchar_t}}({vargs[0]}))" } -if sys.platform.startswith('win32'): - # Import windows ctypes modules - from builtins import WindowsError - from ctypes import wintypes - - WIN_SMALL_DISPATCH_MAP = { - "GetLastError": lambda node, vargs, kwargs: "Base.Libc.GetLastError" - if getattr(node, "is_attr", None) - else "Base.Libc.GetLastError()", - "ctypes.GetLastError": lambda node, vargs, kwargs: "Base.Libc.GetLastError" - if getattr(node, "is_attr", None) - else "Base.Libc.GetLastError()", - } - - SMALL_DISPATCH_MAP = GENERIC_SMALL_DISPATCH_MAP | WIN_SMALL_DISPATCH_MAP - - WIN_DISPATCH_TABLE = { - ctypes.WinDLL: (JuliaExternalModulePlugins.visit_load_library, True), - ctypes.windll.LoadLibrary: (JuliaExternalModulePlugins.visit_load_library, True), - # ctypes.WinDLL: (JuliaExternalModulePlugins.visit_windll, True), - # ctypes.GetLastError: (lambda self, node, vargs, kwargs: "Base.Libc.GetLastError", True), - ctypes.FormatError: (lambda self, node, vargs, kwargs: f"Base.Libc.FormatMessage({', '.join(vargs)})", True), - wintypes: (JuliaExternalModulePlugins.visit_wintypes, True), - } - FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = GENERIC_DISPATCH_TABLE | WIN_DISPATCH_TABLE -else: - FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = GENERIC_DISPATCH_TABLE - - -EXTERNAL_TYPE_MAP = { +GENERIC_EXTERNAL_TYPE_MAP = { ctypes.c_int: lambda self: "Cint", ctypes.c_int8: lambda self: "Cint", ctypes.c_int16: lambda self: "Cint", @@ -168,26 +139,64 @@ def visit_Libdl(self, node: ast.Call, vargs: list[str], kwargs: list[tuple[str,s ctypes.c_wchar_p: lambda self: "Cwstring", # Ptr{Cwchar_t} ctypes.c_void_p: lambda self: "Ptr{Cvoid}", ctypes.CDLL: lambda self: "", # TODO: Temporary - ctypes.WinDLL: lambda self: "", ctypes.py_object: lambda self: "Ptr{Cvoid}", } - -FUNC_TYPE_MAP = { +GENERIC_FUNC_TYPE_MAP = { ctypes.cdll.LoadLibrary: lambda self, node, vargs, kwargs: "ctypes.CDLL", - ctypes.windll.LoadLibrary: lambda self, node, vargs, kwargs: "ctypes.WinDLL", ctypes.CDLL: lambda self, node, vargs, kwargs: "ctypes.CDLL", - ctypes.WinDLL: lambda self, node, vargs, kwargs: "ctypes.WinDLL", ctypes.PyDLL: lambda self, node, vargs, kwargs: "ctypes.CDLL", # Hack, for now # Why invalid syntax??? # ctypes.cast: lambda self, node, vargs, kwargs: ast.unparse(vargs[1]) if vargs else "ctypes.cast", ctypes.cast: lambda self, node, vargs, kwargs: "ctypes._SimpleCData", - ctypes.WINFUNCTYPE: lambda self, node, vargs, kwargs: "PyObject", ctypes.POINTER: lambda self, node, vargs, kwargs: "ctypes.POINTER", - WindowsError: lambda self, node, vargs, kwargs: "OSError", } IGNORED_MODULE_SET = set([ "ctypes", "ctypes.wintypes" ]) + +if sys.platform.startswith('win32'): + # Import windows ctypes modules + from builtins import WindowsError + from ctypes import wintypes + + WIN_SMALL_DISPATCH_MAP = { + "GetLastError": lambda node, vargs, kwargs: "Base.Libc.GetLastError" + if getattr(node, "is_attr", None) + else "Base.Libc.GetLastError()", + "ctypes.GetLastError": lambda node, vargs, kwargs: "Base.Libc.GetLastError" + if getattr(node, "is_attr", None) + else "Base.Libc.GetLastError()", + } + + SMALL_DISPATCH_MAP = GENERIC_SMALL_DISPATCH_MAP | WIN_SMALL_DISPATCH_MAP + + WIN_DISPATCH_TABLE = { + ctypes.WinDLL: (JuliaExternalModulePlugins.visit_load_library, True), + ctypes.windll.LoadLibrary: (JuliaExternalModulePlugins.visit_load_library, True), + # ctypes.WinDLL: (JuliaExternalModulePlugins.visit_windll, True), + # ctypes.GetLastError: (lambda self, node, vargs, kwargs: "Base.Libc.GetLastError", True), + ctypes.FormatError: (lambda self, node, vargs, kwargs: f"Base.Libc.FormatMessage({', '.join(vargs)})", True), + wintypes: (JuliaExternalModulePlugins.visit_wintypes, True), + } + + WIN_EXTERNAL_TYPE_MAP = { + ctypes.WinDLL: lambda self: "", + } + + WIN_FUNC_TYPE_MAP = { + ctypes.windll.LoadLibrary: lambda self, node, vargs, kwargs: "ctypes.WinDLL", + ctypes.WinDLL: lambda self, node, vargs, kwargs: "ctypes.WinDLL", + ctypes.WINFUNCTYPE: lambda self, node, vargs, kwargs: "PyObject", + WindowsError: lambda self, node, vargs, kwargs: "OSError", + } + + FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = GENERIC_DISPATCH_TABLE | WIN_DISPATCH_TABLE + EXTERNAL_TYPE_MAP = WIN_EXTERNAL_TYPE_MAP | GENERIC_EXTERNAL_TYPE_MAP + FUNC_TYPE_MAP = WIN_FUNC_TYPE_MAP + GENERIC_FUNC_TYPE_MAP +else: + FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = GENERIC_DISPATCH_TABLE + EXTERNAL_TYPE_MAP = GENERIC_EXTERNAL_TYPE_MAP + FUNC_TYPE_MAP = GENERIC_FUNC_TYPE_MAP diff --git a/pyjl/external/modules/gzip.py b/pyjl/external/modules/gzip.py index 0facb948c..8d12190f3 100644 --- a/pyjl/external/modules/gzip.py +++ b/pyjl/external/modules/gzip.py @@ -1,7 +1,11 @@ import ast -import gzip from typing import Callable, Dict, Tuple, Union +try: + import gzip +except ImportError: + gzip = None + class JuliaExternalModulePlugins: def visit_gzipopen(self, node: ast.Call, vargs: list[str], kwargs: list[tuple[str,str]]): @@ -30,14 +34,14 @@ def visit_gzipBadGzipFile(self, node: ast.Call, vargs: list[str], kwargs: list[t def _generic_gzip_visit(self): self._usings.add("GZip") +if gzip: + FuncType = Union[Callable, str] -FuncType = Union[Callable, str] - -FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { - gzip.open: (JuliaExternalModulePlugins.visit_gzipopen, True), - gzip.compress: (JuliaExternalModulePlugins.visit_gzipcompress, True), - gzip.decompress: (JuliaExternalModulePlugins.visit_gzipdecompress, True), - gzip.BadGzipFile: (JuliaExternalModulePlugins.visit_gzipBadGzipFile, True), -} + FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { + gzip.open: (JuliaExternalModulePlugins.visit_gzipopen, True), + gzip.compress: (JuliaExternalModulePlugins.visit_gzipcompress, True), + gzip.decompress: (JuliaExternalModulePlugins.visit_gzipdecompress, True), + gzip.BadGzipFile: (JuliaExternalModulePlugins.visit_gzipBadGzipFile, True), + } IGNORED_MODULE_SET = set(["gzip"]) diff --git a/pyjl/external/modules/pandas.py b/pyjl/external/modules/pandas.py index 83961c2f7..8e0b95f14 100644 --- a/pyjl/external/modules/pandas.py +++ b/pyjl/external/modules/pandas.py @@ -1,7 +1,11 @@ import ast -from typing import BinaryIO, Callable, Dict, Tuple, Union -import pandas +from typing import Callable, Dict, Tuple, Union + +try: + import pandas +except: + pandas = None class JuliaExternalModulePlugins: def visit_pandas_readcsv(t_self, node: ast.Call, vargs: list[str]): @@ -23,17 +27,18 @@ def visit_pandas_dataframe_sum(t_self, node: ast.Call, vargs: list[str]): def _visit_pandas(t_self): t_self._usings.add("Pandas") -FuncType = Union[Callable, str] - -FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { - pandas.read_csv: (JuliaExternalModulePlugins.visit_pandas_readcsv, False), - pandas.DataFrame.groupby: (JuliaExternalModulePlugins.visit_pandas_groupby, False), - pandas.DataFrame.to_excel: (JuliaExternalModulePlugins.visit_pandas_toexcel, False), - pandas.core.groupby.generic.DataFrameGroupBy.sum: ( - JuliaExternalModulePlugins.visit_pandas_dataframe_sum, - False, - ), -} +if pandas: + FuncType = Union[Callable, str] + + FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { + pandas.read_csv: (JuliaExternalModulePlugins.visit_pandas_readcsv, False), + pandas.DataFrame.groupby: (JuliaExternalModulePlugins.visit_pandas_groupby, False), + pandas.DataFrame.to_excel: (JuliaExternalModulePlugins.visit_pandas_toexcel, False), + pandas.core.groupby.generic.DataFrameGroupBy.sum: ( + JuliaExternalModulePlugins.visit_pandas_dataframe_sum, + False, + ), + } IGNORED_MODULE_SET = set([ "pandas" diff --git a/pyjl/external/modules/pyproj.py b/pyjl/external/modules/pyproj.py index 3b6c469da..552a5ef9c 100644 --- a/pyjl/external/modules/pyproj.py +++ b/pyjl/external/modules/pyproj.py @@ -26,16 +26,17 @@ def visit_transform(self, node: ast.Call, vargs: list[str], kwargs: list[tuple[s return f"pyproj.transform({', '.join(vargs)})" \ if vargs else "pyproj.transform" -FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { - pyproj.Proj: (JuliaExternalModulePlugins.visit_proj, True), - pyproj.transform: (JuliaExternalModulePlugins.visit_transform, True), -} - -EXTERNAL_TYPE_MAP = { - pyproj.Proj: lambda self: JuliaExternalModulePlugins.visit_proj(self, None, [], []), - pyproj.transform: lambda self: JuliaExternalModulePlugins.visit_transform(self, None, [], []), -} - -IGNORED_MODULE_SET = set([ - "pyproj" -]) \ No newline at end of file +if pyproj: + FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { + pyproj.Proj: (JuliaExternalModulePlugins.visit_proj, True), + pyproj.transform: (JuliaExternalModulePlugins.visit_transform, True), + } + + EXTERNAL_TYPE_MAP = { + pyproj.Proj: lambda self: JuliaExternalModulePlugins.visit_proj(self, None, [], []), + pyproj.transform: lambda self: JuliaExternalModulePlugins.visit_transform(self, None, [], []), + } + + IGNORED_MODULE_SET = set([ + "pyproj" + ]) \ No newline at end of file diff --git a/pyjl/external/modules/requests_mock.py b/pyjl/external/modules/requests_mock.py index 9d9a0efd9..6c73e6e76 100644 --- a/pyjl/external/modules/requests_mock.py +++ b/pyjl/external/modules/requests_mock.py @@ -1,10 +1,14 @@ import ast from pyjl.helpers import pycall_import -import requests_mock from typing import Callable, Dict, Tuple, Union FuncType = Union[Callable, str] +try: + import requests_mock +except ImportError: + requests_mock = None + class JuliaExternalModulePlugins(): def visit_mock(self, node: ast.Call, vargs: list[str], kwargs: list[tuple[str,str]]): pycall_import(self, node, "requests_mock") @@ -18,16 +22,17 @@ def visit_mocker_get(self, node: ast.Call, vargs: list[str], kwargs: list[tuple[ kwargs_str = [f"{kw[0]}={kw[1]}" for kw in kwargs] return f"{func_name}({', '.join(vargs[1:])}, {', '.join(kwargs_str)})" -FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { - requests_mock.mock: (JuliaExternalModulePlugins.visit_mock, True), - requests_mock.Mocker.get: (JuliaExternalModulePlugins.visit_mocker_get, True), - # requests_mock.mock.get -} +if requests_mock: + FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { + requests_mock.mock: (JuliaExternalModulePlugins.visit_mock, True), + requests_mock.Mocker.get: (JuliaExternalModulePlugins.visit_mocker_get, True), + # requests_mock.mock.get + } -IGNORED_MODULE_SET = { - "requests_mock" -} + IGNORED_MODULE_SET = { + "requests_mock" + } -FUNC_TYPE_MAP = { - requests_mock.mock: lambda self, node, vargs, kwargs: "requests_mock.Mocker", -} \ No newline at end of file + FUNC_TYPE_MAP = { + requests_mock.mock: lambda self, node, vargs, kwargs: "requests_mock.Mocker", + } \ No newline at end of file diff --git a/pyjl/external/modules/shapely.py b/pyjl/external/modules/shapely.py index 8bee6ba6a..0f9521ad7 100644 --- a/pyjl/external/modules/shapely.py +++ b/pyjl/external/modules/shapely.py @@ -28,20 +28,21 @@ def visit_point(self, node: ast.Call, vargs: list[str], kwargs: list[tuple[str,s return f"shapely_geo.Point({', '.join(vargs)})" \ if vargs else "shapely_geo.Point" -FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { - BaseGeometry: (JuliaExternalModulePlugins.visit_basegeometry, True), - transform: (JuliaExternalModulePlugins.visit_transform, True), - Point: (JuliaExternalModulePlugins.visit_point, True), -} - -IGNORED_MODULE_SET = set([ - "shapely", - "shapely.geometry", - "shapely.geometry.base", - "shapely.ops", -]) - -EXTERNAL_TYPE_MAP = { - BaseGeometry: lambda self: JuliaExternalModulePlugins.visit_basegeometry(self, None, [], []), - Point: lambda self: JuliaExternalModulePlugins.visit_point(self, None, [], []), -} +if shapely: + FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { + BaseGeometry: (JuliaExternalModulePlugins.visit_basegeometry, True), + transform: (JuliaExternalModulePlugins.visit_transform, True), + Point: (JuliaExternalModulePlugins.visit_point, True), + } + + IGNORED_MODULE_SET = set([ + "shapely", + "shapely.geometry", + "shapely.geometry.base", + "shapely.ops", + ]) + + EXTERNAL_TYPE_MAP = { + BaseGeometry: lambda self: JuliaExternalModulePlugins.visit_basegeometry(self, None, [], []), + Point: lambda self: JuliaExternalModulePlugins.visit_point(self, None, [], []), + } diff --git a/pyjl/external/modules/shutil.py b/pyjl/external/modules/shutil.py index 2388bfae9..fc34d63a2 100644 --- a/pyjl/external/modules/shutil.py +++ b/pyjl/external/modules/shutil.py @@ -1,16 +1,19 @@ -import shutil from typing import Callable, Dict, Tuple, Union +try: + import shutil +except ImportError: + shutil = None -FuncType = Union[Callable, str] - -FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { - shutil.rmtree: (lambda self, node, vargs, kwargs: f"Base.Filesystem.rm({vargs[0]}, recursive=True)", True), - shutil.copy: (lambda self, node, vargs, kwargs: f"Base.Filesystem.cp({vargs[0]}, {vargs[1]}, follow_symlinks={vargs[2]}, force=true)" - if len(vargs) == 3 else f"Base.Filesystem.cp({vargs[0]}, {vargs[1]}, force=true)", True), - shutil.move: (lambda self, node, vargs, kwargs: f"Base.Filesystem.mv({vargs[0]}, {vargs[1]})", True), - shutil.chown: (lambda self, node, vargs, kwargs: f"Base.Filesystem.chown({vargs[0]}, {vargs[1]}, {vargs[2]})" - if len(vargs) == 3 else "Base.Filesystem.chown", True), -} +if shutil: + FuncType = Union[Callable, str] + FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { + shutil.rmtree: (lambda self, node, vargs, kwargs: f"Base.Filesystem.rm({vargs[0]}, recursive=True)", True), + shutil.copy: (lambda self, node, vargs, kwargs: f"Base.Filesystem.cp({vargs[0]}, {vargs[1]}, follow_symlinks={vargs[2]}, force=true)" + if len(vargs) == 3 else f"Base.Filesystem.cp({vargs[0]}, {vargs[1]}, force=true)", True), + shutil.move: (lambda self, node, vargs, kwargs: f"Base.Filesystem.mv({vargs[0]}, {vargs[1]})", True), + shutil.chown: (lambda self, node, vargs, kwargs: f"Base.Filesystem.chown({vargs[0]}, {vargs[1]}, {vargs[2]})" + if len(vargs) == 3 else "Base.Filesystem.chown", True), + } IGNORED_MODULE_SET = set([ "shutil" diff --git a/pyjl/external/modules/tqdm.py b/pyjl/external/modules/tqdm.py index dd2a075a4..cf46598a9 100644 --- a/pyjl/external/modules/tqdm.py +++ b/pyjl/external/modules/tqdm.py @@ -1,7 +1,10 @@ import ast -import tqdm from typing import Callable, Dict, Tuple, Union +try: + import tqdm +except ImportError: + tqdm = None class JuliaExternalModulePlugins(): def visit_tqdm(self, node: ast.Call, vargs: list[str], kwargs: list[tuple[str,str]]): @@ -9,11 +12,11 @@ def visit_tqdm(self, node: ast.Call, vargs: list[str], kwargs: list[tuple[str,st # Using tqdm alias (Identical to using ProgressBar) return f"tqdm({', '.join(vargs)})" +if tqdm: + FuncType = Union[Callable, str] -FuncType = Union[Callable, str] - -FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { - tqdm.tqdm: (JuliaExternalModulePlugins.visit_tqdm, True), -} + FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { + tqdm.tqdm: (JuliaExternalModulePlugins.visit_tqdm, True), + } IGNORED_MODULE_SET = set(["tqdm"]) \ No newline at end of file diff --git a/pyjl/external/modules/zipfile.py b/pyjl/external/modules/zipfile.py index cd3a52773..09b4d71fa 100644 --- a/pyjl/external/modules/zipfile.py +++ b/pyjl/external/modules/zipfile.py @@ -1,15 +1,18 @@ import ast -import zipfile - from typing import Callable, Dict, Tuple, Union +try: + import zipfile +except ImportError: + zipfile = None class JuliaExternalModulePlugins: def visit_zipfile(t_self, node: ast.Call, vargs: list[str]): t_self._usings.add("ZipFile") return f"ZipFile.Reader({vargs[0]})" -FuncType = Union[Callable, str] +if zipfile: + FuncType = Union[Callable, str] -FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { - zipfile.ZipFile: (JuliaExternalModulePlugins.visit_zipfile, False), -} \ No newline at end of file + FUNC_DISPATCH_TABLE: Dict[FuncType, Tuple[Callable, bool]] = { + zipfile.ZipFile: (JuliaExternalModulePlugins.visit_zipfile, False), + } \ No newline at end of file