diff --git a/.gitignore b/.gitignore index 66d64d3e5d..cf3045d5bd 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ astroid.egg-info/ .cache/ .eggs/ .pytest_cache/ +*.c +*.so diff --git a/astroid/__init__.py b/astroid/__init__.pyx similarity index 100% rename from astroid/__init__.py rename to astroid/__init__.pyx diff --git a/astroid/__pkginfo__.py b/astroid/__pkginfo__.py index ea8708400d..32761618cb 100644 --- a/astroid/__pkginfo__.py +++ b/astroid/__pkginfo__.py @@ -31,6 +31,7 @@ "wrapt", 'typing;python_version<"3.5"', 'typed-ast>=1.3.0;implementation_name== "cpython"', + 'Cython' ] # pylint: disable=redefined-builtin; why license is a builtin anyway? diff --git a/astroid/_ast.py b/astroid/_ast.pyx similarity index 100% rename from astroid/_ast.py rename to astroid/_ast.pyx diff --git a/astroid/arguments.py b/astroid/arguments.pyx similarity index 100% rename from astroid/arguments.py rename to astroid/arguments.pyx diff --git a/astroid/as_string.py b/astroid/as_string.pyx similarity index 100% rename from astroid/as_string.py rename to astroid/as_string.pyx diff --git a/astroid/bases.py b/astroid/bases.pyx similarity index 100% rename from astroid/bases.py rename to astroid/bases.pyx diff --git a/astroid/brain/brain_argparse.py b/astroid/brain/brain_argparse.pyx similarity index 100% rename from astroid/brain/brain_argparse.py rename to astroid/brain/brain_argparse.pyx diff --git a/astroid/brain/brain_attrs.py b/astroid/brain/brain_attrs.pyx similarity index 100% rename from astroid/brain/brain_attrs.py rename to astroid/brain/brain_attrs.pyx diff --git a/astroid/brain/brain_builtin_inference.py b/astroid/brain/brain_builtin_inference.pyx similarity index 100% rename from astroid/brain/brain_builtin_inference.py rename to astroid/brain/brain_builtin_inference.pyx diff --git a/astroid/brain/brain_collections.py b/astroid/brain/brain_collections.pyx similarity index 100% rename from astroid/brain/brain_collections.py rename to astroid/brain/brain_collections.pyx diff --git a/astroid/brain/brain_curses.py b/astroid/brain/brain_curses.pyx similarity index 100% rename from astroid/brain/brain_curses.py rename to astroid/brain/brain_curses.pyx diff --git a/astroid/brain/brain_dateutil.py b/astroid/brain/brain_dateutil.pyx similarity index 100% rename from astroid/brain/brain_dateutil.py rename to astroid/brain/brain_dateutil.pyx diff --git a/astroid/brain/brain_fstrings.py b/astroid/brain/brain_fstrings.pyx similarity index 100% rename from astroid/brain/brain_fstrings.py rename to astroid/brain/brain_fstrings.pyx diff --git a/astroid/brain/brain_functools.py b/astroid/brain/brain_functools.pyx similarity index 100% rename from astroid/brain/brain_functools.py rename to astroid/brain/brain_functools.pyx diff --git a/astroid/brain/brain_gi.py b/astroid/brain/brain_gi.pyx similarity index 100% rename from astroid/brain/brain_gi.py rename to astroid/brain/brain_gi.pyx diff --git a/astroid/brain/brain_hashlib.py b/astroid/brain/brain_hashlib.pyx similarity index 100% rename from astroid/brain/brain_hashlib.py rename to astroid/brain/brain_hashlib.pyx diff --git a/astroid/brain/brain_io.py b/astroid/brain/brain_io.pyx similarity index 100% rename from astroid/brain/brain_io.py rename to astroid/brain/brain_io.pyx diff --git a/astroid/brain/brain_mechanize.py b/astroid/brain/brain_mechanize.pyx similarity index 100% rename from astroid/brain/brain_mechanize.py rename to astroid/brain/brain_mechanize.pyx diff --git a/astroid/brain/brain_multiprocessing.py b/astroid/brain/brain_multiprocessing.pyx similarity index 100% rename from astroid/brain/brain_multiprocessing.py rename to astroid/brain/brain_multiprocessing.pyx diff --git a/astroid/brain/brain_namedtuple_enum.py b/astroid/brain/brain_namedtuple_enum.pyx similarity index 100% rename from astroid/brain/brain_namedtuple_enum.py rename to astroid/brain/brain_namedtuple_enum.pyx diff --git a/astroid/brain/brain_nose.py b/astroid/brain/brain_nose.pyx similarity index 100% rename from astroid/brain/brain_nose.py rename to astroid/brain/brain_nose.pyx diff --git a/astroid/brain/brain_numpy.py b/astroid/brain/brain_numpy.pyx similarity index 100% rename from astroid/brain/brain_numpy.py rename to astroid/brain/brain_numpy.pyx diff --git a/astroid/brain/brain_pkg_resources.py b/astroid/brain/brain_pkg_resources.pyx similarity index 100% rename from astroid/brain/brain_pkg_resources.py rename to astroid/brain/brain_pkg_resources.pyx diff --git a/astroid/brain/brain_pytest.py b/astroid/brain/brain_pytest.pyx similarity index 100% rename from astroid/brain/brain_pytest.py rename to astroid/brain/brain_pytest.pyx diff --git a/astroid/brain/brain_qt.py b/astroid/brain/brain_qt.pyx similarity index 100% rename from astroid/brain/brain_qt.py rename to astroid/brain/brain_qt.pyx diff --git a/astroid/brain/brain_random.py b/astroid/brain/brain_random.pyx similarity index 100% rename from astroid/brain/brain_random.py rename to astroid/brain/brain_random.pyx diff --git a/astroid/brain/brain_re.py b/astroid/brain/brain_re.pyx similarity index 100% rename from astroid/brain/brain_re.py rename to astroid/brain/brain_re.pyx diff --git a/astroid/brain/brain_six.py b/astroid/brain/brain_six.pyx similarity index 100% rename from astroid/brain/brain_six.py rename to astroid/brain/brain_six.pyx diff --git a/astroid/brain/brain_ssl.py b/astroid/brain/brain_ssl.pyx similarity index 100% rename from astroid/brain/brain_ssl.py rename to astroid/brain/brain_ssl.pyx diff --git a/astroid/brain/brain_subprocess.py b/astroid/brain/brain_subprocess.pyx similarity index 100% rename from astroid/brain/brain_subprocess.py rename to astroid/brain/brain_subprocess.pyx diff --git a/astroid/brain/brain_threading.py b/astroid/brain/brain_threading.pyx similarity index 100% rename from astroid/brain/brain_threading.py rename to astroid/brain/brain_threading.pyx diff --git a/astroid/brain/brain_typing.py b/astroid/brain/brain_typing.pyx similarity index 100% rename from astroid/brain/brain_typing.py rename to astroid/brain/brain_typing.pyx diff --git a/astroid/brain/brain_uuid.py b/astroid/brain/brain_uuid.pyx similarity index 100% rename from astroid/brain/brain_uuid.py rename to astroid/brain/brain_uuid.pyx diff --git a/astroid/builder.py b/astroid/builder.pyx similarity index 100% rename from astroid/builder.py rename to astroid/builder.pyx diff --git a/astroid/context.py b/astroid/context.pyx similarity index 100% rename from astroid/context.py rename to astroid/context.pyx diff --git a/astroid/decorators.py b/astroid/decorators.pyx similarity index 100% rename from astroid/decorators.py rename to astroid/decorators.pyx diff --git a/astroid/exceptions.py b/astroid/exceptions.pyx similarity index 100% rename from astroid/exceptions.py rename to astroid/exceptions.pyx diff --git a/astroid/helpers.py b/astroid/helpers.pyx similarity index 100% rename from astroid/helpers.py rename to astroid/helpers.pyx diff --git a/astroid/inference.py b/astroid/inference.pyx similarity index 97% rename from astroid/inference.py rename to astroid/inference.pyx index 16346a77e8..677f94c5fb 100644 --- a/astroid/inference.py +++ b/astroid/inference.pyx @@ -35,6 +35,7 @@ from astroid.interpreter import dunder_lookup from astroid import protocols from astroid import util +cimport cython MANAGER = manager.AstroidManager() @@ -42,7 +43,7 @@ # .infer method ############################################################### - +@cython.binding(True) def infer_end(self, context=None): """inference's end for node such as Module, ClassDef, FunctionDef, Const... @@ -77,6 +78,7 @@ def _infer_sequence_helper(node, context=None): @decorators.raise_if_nothing_inferred +@cython.binding(True) def infer_sequence(self, context=None): if not any(isinstance(e, nodes.Starred) for e in self.elts): yield self @@ -95,6 +97,7 @@ def infer_sequence(self, context=None): nodes.Set._infer = infer_sequence +@cython.binding(True) def infer_map(self, context=None): if not any(isinstance(k, nodes.DictUnpack) for k, _ in self.items): yield self @@ -171,7 +174,7 @@ def _higher_function_scope(node): return current.parent return None - +@cython.binding(True) def infer_name(self, context=None): """infer a Name: use name lookup rules""" frame, stmts = self.lookup(self.name) @@ -200,6 +203,7 @@ def infer_name(self, context=None): @decorators.raise_if_nothing_inferred @decorators.path_wrapper +@cython.binding(True) def infer_call(self, context=None): """infer a Call node by trying to guess what the function returns""" callcontext = contextmod.copy_context(context) @@ -227,6 +231,7 @@ def infer_call(self, context=None): @decorators.raise_if_nothing_inferred @decorators.path_wrapper +@cython.binding(True) def infer_import(self, context=None, asname=True): """infer an Import node: return the imported module/object""" name = context.lookupname @@ -247,6 +252,7 @@ def infer_import(self, context=None, asname=True): @decorators.raise_if_nothing_inferred @decorators.path_wrapper +@cython.binding(True) def infer_import_from(self, context=None, asname=True): """infer a ImportFrom node: return the imported module/object""" name = context.lookupname @@ -274,6 +280,7 @@ def infer_import_from(self, context=None, asname=True): nodes.ImportFrom._infer = infer_import_from +@decorators.raise_if_nothing_inferred def infer_attribute(self, context=None): """infer an Attribute node by using getattr on the associated object""" for owner in self.expr.infer(context): @@ -319,6 +326,7 @@ def infer_attribute(self, context=None): @decorators.raise_if_nothing_inferred @decorators.path_wrapper +@cython.binding(True) def infer_global(self, context=None): if context.lookupname is None: raise exceptions.InferenceError(node=self, context=context) @@ -337,6 +345,7 @@ def infer_global(self, context=None): @decorators.raise_if_nothing_inferred +@cython.binding(True) def infer_subscript(self, context=None): """Inference for subscripts @@ -399,6 +408,7 @@ def infer_subscript(self, context=None): @decorators.raise_if_nothing_inferred @decorators.path_wrapper +@cython.binding(True) def _infer_boolop(self, context=None): """Infer a boolean operation (and / or / not). @@ -455,7 +465,7 @@ def _infer_boolop(self, context=None): # UnaryOp, BinOp and AugAssign inferences - +@cython.binding(True) def _filter_operation_errors(self, infer_callable, context, error): for result in infer_callable(self, context): if isinstance(result, error): @@ -467,6 +477,7 @@ def _filter_operation_errors(self, infer_callable, context, error): yield result +@cython.binding(True) def _infer_unaryop(self, context=None): """Infer what an UnaryOp should return when evaluated.""" for operand in self.operand.infer(context): @@ -523,6 +534,7 @@ def _infer_unaryop(self, context=None): @decorators.raise_if_nothing_inferred @decorators.path_wrapper +@cython.binding(True) def infer_unaryop(self, context=None): """Infer what an UnaryOp should return when evaluated.""" yield from _filter_operation_errors( @@ -535,9 +547,9 @@ def infer_unaryop(self, context=None): nodes.UnaryOp._infer = infer_unaryop -def _is_not_implemented(const): +def _is_not_implemented(const_node): """Check if the given const node is NotImplemented.""" - return isinstance(const, nodes.Const) and const.value is NotImplemented + return isinstance(const_node, nodes.Const) and const_node.value is NotImplemented def _invoke_binop_inference(instance, opnode, op, other, context, method_name): @@ -730,6 +742,7 @@ def _infer_binary_operation(left, right, binary_opnode, context, flow_factory): yield util.BadBinaryOperationMessage(left_type, binary_opnode.op, right_type) +@cython.binding(True) def _infer_binop(self, context): """Binary operation inference logic.""" left = self.left @@ -757,6 +770,7 @@ def _infer_binop(self, context): @decorators.yes_if_nothing_inferred @decorators.path_wrapper +@cython.binding(True) def infer_binop(self, context=None): return _filter_operation_errors( self, _infer_binop, context, util.BadBinaryOperationMessage @@ -767,6 +781,7 @@ def infer_binop(self, context=None): nodes.BinOp._infer = infer_binop +@cython.binding(True) def _infer_augassign(self, context=None): """Inference logic for augmented binary operations.""" if context is None: @@ -796,6 +811,7 @@ def _infer_augassign(self, context=None): @decorators.raise_if_nothing_inferred @decorators.path_wrapper +@cython.binding(True) def infer_augassign(self, context=None): return _filter_operation_errors( self, _infer_augassign, context, util.BadBinaryOperationMessage @@ -809,6 +825,7 @@ def infer_augassign(self, context=None): @decorators.raise_if_nothing_inferred +@cython.binding(True) def infer_arguments(self, context=None): name = context.lookupname if name is None: @@ -821,6 +838,7 @@ def infer_arguments(self, context=None): @decorators.raise_if_nothing_inferred @decorators.path_wrapper +@cython.binding(True) def infer_assign(self, context=None): """infer a AssignName/AssignAttr: need to inspect the RHS part of the assign node @@ -839,6 +857,7 @@ def infer_assign(self, context=None): @decorators.raise_if_nothing_inferred @decorators.path_wrapper +@cython.binding(True) def infer_empty_node(self, context=None): if not self.has_underlying_object(): yield util.Uninferable @@ -853,6 +872,7 @@ def infer_empty_node(self, context=None): @decorators.raise_if_nothing_inferred +@cython.binding(True) def infer_index(self, context=None): return self.value.infer(context) @@ -861,6 +881,7 @@ def infer_index(self, context=None): # TODO: move directly into bases.Instance when the dependency hell # will be solved. +@cython.binding(True) def instance_getitem(self, index, context=None): # Rewrap index to Const for this case new_context = contextmod.bind_context_to_node(context, self) diff --git a/astroid/interpreter/_import/spec.py b/astroid/interpreter/_import/spec.pyx similarity index 100% rename from astroid/interpreter/_import/spec.py rename to astroid/interpreter/_import/spec.pyx diff --git a/astroid/interpreter/_import/util.py b/astroid/interpreter/_import/util.pyx similarity index 100% rename from astroid/interpreter/_import/util.py rename to astroid/interpreter/_import/util.pyx diff --git a/astroid/interpreter/dunder_lookup.py b/astroid/interpreter/dunder_lookup.pyx similarity index 100% rename from astroid/interpreter/dunder_lookup.py rename to astroid/interpreter/dunder_lookup.pyx diff --git a/astroid/interpreter/objectmodel.py b/astroid/interpreter/objectmodel.pyx similarity index 100% rename from astroid/interpreter/objectmodel.py rename to astroid/interpreter/objectmodel.pyx diff --git a/astroid/manager.py b/astroid/manager.pyx similarity index 100% rename from astroid/manager.py rename to astroid/manager.pyx diff --git a/astroid/mixins.py b/astroid/mixins.pyx similarity index 100% rename from astroid/mixins.py rename to astroid/mixins.pyx diff --git a/astroid/modutils.py b/astroid/modutils.pyx similarity index 100% rename from astroid/modutils.py rename to astroid/modutils.pyx diff --git a/astroid/node_classes.py b/astroid/node_classes.pyx similarity index 100% rename from astroid/node_classes.py rename to astroid/node_classes.pyx diff --git a/astroid/nodes.py b/astroid/nodes.pyx similarity index 100% rename from astroid/nodes.py rename to astroid/nodes.pyx diff --git a/astroid/objects.py b/astroid/objects.pyx similarity index 100% rename from astroid/objects.py rename to astroid/objects.pyx diff --git a/astroid/protocols.py b/astroid/protocols.pyx similarity index 98% rename from astroid/protocols.py rename to astroid/protocols.pyx index bf497ff101..9596100054 100644 --- a/astroid/protocols.py +++ b/astroid/protocols.pyx @@ -23,6 +23,7 @@ import collections import operator as operator_mod import sys +cimport cython import itertools @@ -124,6 +125,7 @@ def _infer_unary_op(obj, op): @decorators.yes_if_nothing_inferred +@cython.binding(True) def const_infer_binary_op(self, opnode, operator, other, context, _): not_implemented = nodes.Const(NotImplemented) if isinstance(other, nodes.Const): @@ -148,6 +150,7 @@ def const_infer_binary_op(self, opnode, operator, other, context, _): nodes.Const.infer_binary_op = const_infer_binary_op +@cython.binding(True) def _multiply_seq_by_int(self, opnode, other, context): node = self.__class__(parent=opnode) filtered_elts = ( @@ -172,6 +175,7 @@ def _filter_uninferable_nodes(elts, context): @decorators.yes_if_nothing_inferred +@cython.binding(True) def tl_infer_binary_op(self, opnode, operator, other, context, method): not_implemented = nodes.Const(NotImplemented) if isinstance(other, self.__class__) and operator == "+": @@ -204,6 +208,7 @@ def tl_infer_binary_op(self, opnode, operator, other, context, method): @decorators.yes_if_nothing_inferred +@cython.binding(True) def instance_class_infer_binary_op(self, opnode, operator, other, context, method): return method.infer_call_result(self, context) @@ -267,6 +272,7 @@ def _resolve_looppart(parts, assign_path, context): @decorators.raise_if_nothing_inferred +@cython.binding(True) def for_assigned_stmts(self, node=None, context=None, assign_path=None): if isinstance(self, nodes.AsyncFor) or getattr(self, "is_async", False): # Skip inferring of async code for now @@ -284,6 +290,7 @@ def for_assigned_stmts(self, node=None, context=None, assign_path=None): nodes.Comprehension.assigned_stmts = for_assigned_stmts +@cython.binding(True) def sequence_assigned_stmts(self, node=None, context=None, assign_path=None): if assign_path is None: assign_path = [] @@ -306,7 +313,7 @@ def sequence_assigned_stmts(self, node=None, context=None, assign_path=None): nodes.Tuple.assigned_stmts = sequence_assigned_stmts nodes.List.assigned_stmts = sequence_assigned_stmts - +@cython.binding(True) def assend_assigned_stmts(self, node=None, context=None, assign_path=None): return self.parent.assigned_stmts(node=self, context=context) @@ -315,6 +322,7 @@ def assend_assigned_stmts(self, node=None, context=None, assign_path=None): nodes.AssignAttr.assigned_stmts = assend_assigned_stmts +@cython.binding(True) def _arguments_infer_argname(self, name, context): # arguments information may be missing, in which case we can't do anything # more @@ -360,6 +368,7 @@ def _arguments_infer_argname(self, name, context): yield util.Uninferable +@cython.binding(True) def arguments_assigned_stmts(self, node=None, context=None, assign_path=None): if context.callcontext: # reset call context/name @@ -375,6 +384,7 @@ def arguments_assigned_stmts(self, node=None, context=None, assign_path=None): @decorators.raise_if_nothing_inferred +@cython.binding(True) def assign_assigned_stmts(self, node=None, context=None, assign_path=None): if not assign_path: yield self.value @@ -386,6 +396,7 @@ def assign_assigned_stmts(self, node=None, context=None, assign_path=None): return dict(node=self, unknown=node, assign_path=assign_path, context=context) +@cython.binding(True) def assign_annassigned_stmts(self, node=None, context=None, assign_path=None): for inferred in assign_assigned_stmts(self, node, context, assign_path): if inferred is None: @@ -440,6 +451,7 @@ def _resolve_assignment_parts(parts, assign_path, context): @decorators.raise_if_nothing_inferred +@cython.binding(True) def excepthandler_assigned_stmts(self, node=None, context=None, assign_path=None): for assigned in node_classes.unpack_infer(self.type): if isinstance(assigned, nodes.ClassDef): @@ -452,6 +464,7 @@ def excepthandler_assigned_stmts(self, node=None, context=None, assign_path=None nodes.ExceptHandler.assigned_stmts = excepthandler_assigned_stmts +@cython.binding(True) def _infer_context_manager(self, mgr, context): inferred = next(mgr.infer(context=context)) if isinstance(inferred, bases.Generator): @@ -500,6 +513,7 @@ def _infer_context_manager(self, mgr, context): @decorators.raise_if_nothing_inferred +@cython.binding(True) def with_assigned_stmts(self, node=None, context=None, assign_path=None): """Infer names and other nodes from a *with* statement. @@ -573,6 +587,7 @@ def __enter__(self): @decorators.yes_if_nothing_inferred +@cython.binding(True) def starred_assigned_stmts(self, node=None, context=None, assign_path=None): """ Arguments: diff --git a/astroid/raw_building.py b/astroid/raw_building.pyx similarity index 99% rename from astroid/raw_building.py rename to astroid/raw_building.pyx index 60000fdba5..d0055a7a4f 100644 --- a/astroid/raw_building.py +++ b/astroid/raw_building.pyx @@ -22,6 +22,7 @@ import os import sys import types +cimport cython from astroid import bases from astroid import manager @@ -74,7 +75,7 @@ def attach_dummy_node(node, name, runtime_object=_marker): enode.object = runtime_object _attach_local_node(node, enode, name) - +@cython.binding(True) def _has_underlying_object(self): return self.object is not None and self.object is not _marker @@ -377,8 +378,8 @@ def imported_member(self, node, member, name): _CONST_PROXY = {} # TODO : find a nicer way to handle this situation; -def _set_proxied(const): - return _CONST_PROXY[const.value.__class__] +def _set_proxied(_const): + return _CONST_PROXY[_const.value.__class__] def _astroid_bootstrapping(): @@ -440,5 +441,4 @@ def _astroid_bootstrapping(): builder.object_build(cls, _type) astroid_builtin[_type.__name__] = cls - _astroid_bootstrapping() diff --git a/astroid/rebuilder.py b/astroid/rebuilder.pyx similarity index 100% rename from astroid/rebuilder.py rename to astroid/rebuilder.pyx diff --git a/astroid/scoped_nodes.py b/astroid/scoped_nodes.pyx similarity index 100% rename from astroid/scoped_nodes.py rename to astroid/scoped_nodes.pyx diff --git a/astroid/test_utils.py b/astroid/test_utils.pyx similarity index 100% rename from astroid/test_utils.py rename to astroid/test_utils.pyx diff --git a/astroid/tests/__init__.py b/astroid/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/astroid/transforms.py b/astroid/transforms.pyx similarity index 100% rename from astroid/transforms.py rename to astroid/transforms.pyx diff --git a/astroid/util.py b/astroid/util.pyx similarity index 100% rename from astroid/util.py rename to astroid/util.pyx diff --git a/setup.py b/setup.py index 2ad90aac01..f38998da70 100644 --- a/setup.py +++ b/setup.py @@ -15,6 +15,7 @@ from setuptools import setup, find_packages from setuptools.command import easy_install from setuptools.command import install_lib +from Cython.Build import cythonize real_path = os.path.realpath(__file__) @@ -45,6 +46,7 @@ def install(): setup_requires=['pytest-runner'], test_suite='test', tests_require=['pytest'], + ext_modules=cythonize(["astroid/*.pyx", "astroid/interpreter/*.pyx", "astroid/interpreter/_import/*.pyx", "astroid/brain/*.pyx"], compiler_directives={'language_level': '3'}) )