summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhippo91 <guillaume.peillex@gmail.com>2021-01-19 20:46:30 +0100
committerhippo91 <guillaume.peillex@gmail.com>2021-01-19 20:46:30 +0100
commitf184c8af7581b6d1c56270f1eb66254175978595 (patch)
tree270051e58f9b62b3febf4db1c2d15645e7281af0
parentc89ccb7396e89557925ab2972611b93367f400c3 (diff)
downloadastroid-git-f184c8af7581b6d1c56270f1eb66254175978595.tar.gz
Adds doc
-rw-r--r--astroid/brain/brain_type.py45
-rw-r--r--tests/unittest_brain.py9
2 files changed, 45 insertions, 9 deletions
diff --git a/astroid/brain/brain_type.py b/astroid/brain/brain_type.py
index f32c6c77..951d6bf3 100644
--- a/astroid/brain/brain_type.py
+++ b/astroid/brain/brain_type.py
@@ -1,4 +1,21 @@
# -*- 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 (
@@ -10,20 +27,30 @@ from astroid import (
def _looks_like_type_subscript(node):
- """Try to figure out if a Subscript node *might* be a typing-related subscript"""
- if isinstance(node, nodes.Name):
+ """
+ Try to figure out if a Name node is used inside a type related subscript
+
+ :param node: node to check
+ :type node: nodes.Name
+ :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"
- if isinstance(node, nodes.Subscript):
- if isinstance(node.value, Name) and node.value.name == "type":
- return True
return False
def infer_type_sub(node, context=None):
- """Infer a typing.X[...] subscript"""
- sub_node = node.parent
- if not isinstance(sub_node, nodes.Subscript):
- raise UseInferenceDefault
+ """
+ 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):
diff --git a/tests/unittest_brain.py b/tests/unittest_brain.py
index 0190ed3f..443fcb49 100644
--- a/tests/unittest_brain.py
+++ b/tests/unittest_brain.py
@@ -940,6 +940,10 @@ class IOBrainTest(unittest.TestCase):
@test_utils.require_version("3.9")
class TypeBrain(unittest.TestCase):
def test_type_subscript(self):
+ """
+ Check that type object has the __class_getitem__ method
+ when it is used as a subscript
+ """
src = builder.extract_node(
"""
a: type[int] = int
@@ -952,6 +956,11 @@ class TypeBrain(unittest.TestCase):
self.assertIsInstance(meth_inf, astroid.FunctionDef)
def test_invalid_type_subscript(self):
+ """
+ Check that a type (str for example) that inherits
+ from type does not have __class_getitem__ method even
+ when it is used as a subscript
+ """
src = builder.extract_node(
"""
a: str[int] = "abc"