diff options
| author | hippo91 <guillaume.peillex@gmail.com> | 2021-02-07 16:29:50 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-02-07 16:29:50 +0100 |
| commit | d60eb5e207427599fe2f4a8d44e4cb0bebcf3c9f (patch) | |
| tree | afca46ee9a4b30effa5a6d36657b64b7f492c651 /astroid/brain | |
| parent | 529cd943ea05e1c263b3e07366973bc9a32ff171 (diff) | |
| parent | 599fe72a0c0e07e2a7720237c40800aa3c611708 (diff) | |
| download | astroid-git-d60eb5e207427599fe2f4a8d44e4cb0bebcf3c9f.tar.gz | |
Merge branch 'master' into master
Diffstat (limited to 'astroid/brain')
| -rw-r--r-- | astroid/brain/brain_builtin_inference.py | 2 | ||||
| -rw-r--r-- | astroid/brain/brain_collections.py | 8 | ||||
| -rw-r--r-- | astroid/brain/brain_numpy_core_umath.py | 2 | ||||
| -rw-r--r-- | astroid/brain/brain_six.py | 39 | ||||
| -rw-r--r-- | astroid/brain/brain_subprocess.py | 7 | ||||
| -rw-r--r-- | astroid/brain/brain_type.py | 64 |
6 files changed, 122 insertions, 0 deletions
diff --git a/astroid/brain/brain_builtin_inference.py b/astroid/brain/brain_builtin_inference.py index 0008244c..b7659cc9 100644 --- a/astroid/brain/brain_builtin_inference.py +++ b/astroid/brain/brain_builtin_inference.py @@ -223,6 +223,8 @@ def _container_generic_transform(arg, context, klass, iterables, build_elts): # TODO: Does not handle deduplication for sets. elts = [] for element in arg.elts: + if not element: + continue inferred = helpers.safe_infer(element, context=context) if inferred: evaluated_object = nodes.EvaluatedObject( diff --git a/astroid/brain/brain_collections.py b/astroid/brain/brain_collections.py index 6594e0c7..229969c5 100644 --- a/astroid/brain/brain_collections.py +++ b/astroid/brain/brain_collections.py @@ -4,6 +4,7 @@ # Copyright (c) 2017 Derek Gustafson <degustaf@gmail.com> # Copyright (c) 2018 Ioana Tagirta <ioana.tagirta@gmail.com> # Copyright (c) 2019 Hugo van Kemenade <hugovk@users.noreply.github.com> +# Copyright (c) 2021 Julien Palard <julien@palard.fr> # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER @@ -12,6 +13,9 @@ import sys import astroid +PY39 = sys.version_info >= (3, 9) + + def _collections_transform(): return astroid.parse( """ @@ -61,6 +65,10 @@ def _deque_mock(): def __mul__(self, other): pass def __imul__(self, other): pass def __rmul__(self, other): pass""" + if PY39: + base_deque_class += """ + @classmethod + def __class_getitem__(self, item): pass""" return base_deque_class diff --git a/astroid/brain/brain_numpy_core_umath.py b/astroid/brain/brain_numpy_core_umath.py index 1955e80e..73613b86 100644 --- a/astroid/brain/brain_numpy_core_umath.py +++ b/astroid/brain/brain_numpy_core_umath.py @@ -106,6 +106,7 @@ def numpy_core_umath_transform(): trunc = FakeUfuncOneArg() # Two args functions with optional kwargs + add = FakeUfuncTwoArgs() bitwise_and = FakeUfuncTwoArgs() bitwise_or = FakeUfuncTwoArgs() bitwise_xor = FakeUfuncTwoArgs() @@ -133,6 +134,7 @@ def numpy_core_umath_transform(): logical_xor = FakeUfuncTwoArgs() maximum = FakeUfuncTwoArgs() minimum = FakeUfuncTwoArgs() + multiply = FakeUfuncTwoArgs() nextafter = FakeUfuncTwoArgs() not_equal = FakeUfuncTwoArgs() power = FakeUfuncTwoArgs() diff --git a/astroid/brain/brain_six.py b/astroid/brain/brain_six.py index 389037f2..a998213f 100644 --- a/astroid/brain/brain_six.py +++ b/astroid/brain/brain_six.py @@ -22,6 +22,7 @@ from astroid import nodes SIX_ADD_METACLASS = "six.add_metaclass" +SIX_WITH_METACLASS = "six.with_metaclass" def _indent(text, prefix, predicate=None): @@ -190,6 +191,39 @@ def transform_six_add_metaclass(node): return node +def _looks_like_nested_from_six_with_metaclass(node): + if len(node.bases) != 1: + return False + base = node.bases[0] + if not isinstance(base, nodes.Call): + return False + try: + if hasattr(base.func, "expr"): + # format when explicit 'six.with_metaclass' is used + mod = base.func.expr.name + func = base.func.attrname + func = "{}.{}".format(mod, func) + else: + # format when 'with_metaclass' is used directly (local import from six) + # check reference module to avoid 'with_metaclass' name clashes + mod = base.parent.parent + import_from = mod.locals["with_metaclass"][0] + func = "{}.{}".format(import_from.modname, base.func.name) + except (AttributeError, KeyError, IndexError): + return False + return func == SIX_WITH_METACLASS + + +def transform_six_with_metaclass(node): + """Check if the given class node is defined with *six.with_metaclass* + + If so, inject its argument as the metaclass of the underlying class. + """ + call = node.bases[0] + node._metaclass = call.args[0] + node.bases = call.args[1:] + + register_module_extender(MANAGER, "six", six_moves_transform) register_module_extender( MANAGER, "requests.packages.urllib3.packages.six", six_moves_transform @@ -200,3 +234,8 @@ MANAGER.register_transform( transform_six_add_metaclass, _looks_like_decorated_with_six_add_metaclass, ) +MANAGER.register_transform( + nodes.ClassDef, + transform_six_with_metaclass, + _looks_like_nested_from_six_with_metaclass, +) diff --git a/astroid/brain/brain_subprocess.py b/astroid/brain/brain_subprocess.py index bc35704f..c19b32b1 100644 --- a/astroid/brain/brain_subprocess.py +++ b/astroid/brain/brain_subprocess.py @@ -14,6 +14,7 @@ import textwrap import astroid +PY39 = sys.version_info >= (3, 9) PY37 = sys.version_info >= (3, 7) PY36 = sys.version_info >= (3, 6) @@ -147,6 +148,12 @@ def _subprocess_transform(): "py3_args": py3_args, } ) + if PY39: + code += """ + @classmethod + def __class_getitem__(cls, item): + pass + """ init_lines = textwrap.dedent(init).splitlines() indented_init = "\n".join(" " * 4 + line for line in init_lines) diff --git a/astroid/brain/brain_type.py b/astroid/brain/brain_type.py new file mode 100644 index 00000000..4e82813f --- /dev/null +++ b/astroid/brain/brain_type.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +""" +Astroid hooks for type support. + +Starting from python3.9, type object behaves as it had __class_getitem__ method. +However it was not possible to simply add this method inside type's body, otherwise +all types would also have this method. In this case it would have been possible +to write str[int]. +Guido Van Rossum proposed a hack to handle this in the interpreter: +https://github.com/python/cpython/blob/master/Objects/abstract.c#L186-L189 + +This brain follows the same logic. It is no wise to add permanently the __class_getitem__ method +to the type object. Instead we choose to add it only in the case of a subscript node +which inside name node is type. +Doing this type[int] is allowed whereas str[int] is not. + +Thanks to Lukasz Langa for fruitful discussion. +""" +import sys + +from astroid import MANAGER, extract_node, inference_tip, nodes + + +PY39 = sys.version_info >= (3, 9) + + +def _looks_like_type_subscript(node): + """ + Try to figure out if a Name node is used inside a type related subscript + + :param node: node to check + :type node: astroid.node_classes.NodeNG + :return: true if the node is a Name node inside a type related subscript + :rtype: bool + """ + if isinstance(node, nodes.Name) and isinstance(node.parent, nodes.Subscript): + return node.name == "type" + return False + + +def infer_type_sub(node, context=None): + """ + Infer a type[...] subscript + + :param node: node to infer + :type node: astroid.node_classes.NodeNG + :param context: inference context + :type context: astroid.context.InferenceContext + :return: the inferred node + :rtype: nodes.NodeNG + """ + class_src = """ + class type: + def __class_getitem__(cls, key): + return cls + """ + node = extract_node(class_src) + return node.infer(context=context) + + +if PY39: + MANAGER.register_transform( + nodes.Name, inference_tip(infer_type_sub), _looks_like_type_subscript + ) |
