summaryrefslogtreecommitdiff
path: root/astroid/brain
diff options
context:
space:
mode:
authorhippo91 <guillaume.peillex@gmail.com>2021-02-07 16:29:50 +0100
committerGitHub <noreply@github.com>2021-02-07 16:29:50 +0100
commitd60eb5e207427599fe2f4a8d44e4cb0bebcf3c9f (patch)
treeafca46ee9a4b30effa5a6d36657b64b7f492c651 /astroid/brain
parent529cd943ea05e1c263b3e07366973bc9a32ff171 (diff)
parent599fe72a0c0e07e2a7720237c40800aa3c611708 (diff)
downloadastroid-git-d60eb5e207427599fe2f4a8d44e4cb0bebcf3c9f.tar.gz
Merge branch 'master' into master
Diffstat (limited to 'astroid/brain')
-rw-r--r--astroid/brain/brain_builtin_inference.py2
-rw-r--r--astroid/brain/brain_collections.py8
-rw-r--r--astroid/brain/brain_numpy_core_umath.py2
-rw-r--r--astroid/brain/brain_six.py39
-rw-r--r--astroid/brain/brain_subprocess.py7
-rw-r--r--astroid/brain/brain_type.py64
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
+ )