Exemplo n.º 1
0
def infer_parents_subscript(
    subscript_node: nodes.Subscript, ctx: context.InferenceContext | None = None
) -> Iterator[bases.Instance]:
    if isinstance(subscript_node.slice, nodes.Const):
        path_cls = next(_extract_single_node(PATH_TEMPLATE).infer())
        return iter([path_cls.instantiate_class()])

    raise UseInferenceDefault
Exemplo n.º 2
0
 def test_infer_property(self):
     class_with_property = _extract_single_node("""
     class Something:
         def getter():
             return 5
         asd = property(getter) #@
     """)
     inferred_property = list(class_with_property.value.infer())[0]
     self.assertTrue(isinstance(inferred_property, objects.Property))
     self.assertTrue(hasattr(inferred_property, "args"))
Exemplo n.º 3
0
def test_recursion_during_inference(mocked) -> None:
    """Check that we don't crash if we hit the recursion limit during inference."""
    node: nodes.Call = _extract_single_node(
        """
    from module import something
    something()
    """
    )
    with pytest.raises(InferenceError) as error:
        next(node.infer())
    assert error.value.message.startswith("RecursionError raised")
Exemplo n.º 4
0
 def test_sys_modules(self) -> None:
     """Test that we can gather the items of a living dict object."""
     node = _extract_single_node(
         """
     import sys
     sys.modules
     """
     )
     inferred = list(node.infer())
     assert len(inferred) == 1
     assert isinstance(inferred[0], nodes.Dict)
     assert inferred[0].items
Exemplo n.º 5
0
 def test_sys_builtin_module_names(self) -> None:
     """Test that we can gather the elements of a living tuple object."""
     node = _extract_single_node(
         """
     import sys
     sys.builtin_module_names
     """
     )
     inferred = list(node.infer())
     assert len(inferred) == 1
     assert isinstance(inferred[0], nodes.Tuple)
     assert inferred[0].elts
Exemplo n.º 6
0
def infer_typing_alias(
    node: Call, ctx: context.InferenceContext | None = None
) -> Iterator[ClassDef]:
    """
    Infers the call to _alias function
    Insert ClassDef, with same name as aliased class,
    in mro to simulate _GenericAlias.

    :param node: call node
    :param context: inference context
    """
    if (
        not isinstance(node.parent, Assign)
        or not len(node.parent.targets) == 1
        or not isinstance(node.parent.targets[0], AssignName)
    ):
        raise UseInferenceDefault
    try:
        res = next(node.args[0].infer(context=ctx))
    except StopIteration as e:
        raise InferenceError(node=node.args[0], context=context) from e

    assign_name = node.parent.targets[0]

    class_def = ClassDef(
        name=assign_name.name,
        lineno=assign_name.lineno,
        col_offset=assign_name.col_offset,
        parent=node.parent,
    )
    if res != Uninferable and isinstance(res, ClassDef):
        # Only add `res` as base if it's a `ClassDef`
        # This isn't the case for `typing.Pattern` and `typing.Match`
        class_def.postinit(bases=[res], body=[], decorators=None)

    maybe_type_var = node.args[1]
    if (
        not PY39_PLUS
        and not (isinstance(maybe_type_var, Tuple) and not maybe_type_var.elts)
        or PY39_PLUS
        and isinstance(maybe_type_var, Const)
        and maybe_type_var.value > 0
    ):
        # If typing alias is subscriptable, add `__class_getitem__` to ClassDef
        func_to_add = _extract_single_node(CLASS_GETITEM_TEMPLATE)
        class_def.locals["__class_getitem__"] = [func_to_add]
    else:
        # If not, make sure that `__class_getitem__` access is forbidden.
        # This is an issue in cases where the aliased class implements it,
        # but the typing alias isn't subscriptable. E.g., `typing.ByteString` for PY39+
        _forbid_class_getitem_access(class_def)
    return iter([class_def])
Exemplo n.º 7
0
def infer_pattern_match(node: nodes.Call,
                        ctx: context.InferenceContext | None = None):
    """Infer re.Pattern and re.Match as classes. For PY39+ add `__class_getitem__`."""
    class_def = nodes.ClassDef(
        name=node.parent.targets[0].name,
        lineno=node.lineno,
        col_offset=node.col_offset,
        parent=node.parent,
    )
    if PY39_PLUS:
        func_to_add = _extract_single_node(CLASS_GETITEM_TEMPLATE)
        class_def.locals["__class_getitem__"] = [func_to_add]
    return iter([class_def])
Exemplo n.º 8
0
def infer_typedDict(  # pylint: disable=invalid-name
    node: FunctionDef, ctx: context.InferenceContext | None = None
) -> Iterator[ClassDef]:
    """Replace TypedDict FunctionDef with ClassDef."""
    class_def = ClassDef(
        name="TypedDict",
        lineno=node.lineno,
        col_offset=node.col_offset,
        parent=node.parent,
    )
    class_def.postinit(bases=[extract_node("dict")], body=[], decorators=None)
    func_to_add = _extract_single_node("dict")
    class_def.locals["__call__"] = [func_to_add]
    return iter([class_def])
Exemplo n.º 9
0
def infer_enum(
        node: nodes.Call,
        context: InferenceContext | None = None) -> Iterator[bases.Instance]:
    """Specific inference function for enum Call node."""
    enum_meta = _extract_single_node("""
    class EnumMeta(object):
        'docstring'
        def __call__(self, node):
            class EnumAttribute(object):
                name = ''
                value = 0
            return EnumAttribute()
        def __iter__(self):
            class EnumAttribute(object):
                name = ''
                value = 0
            return [EnumAttribute()]
        def __reversed__(self):
            class EnumAttribute(object):
                name = ''
                value = 0
            return (EnumAttribute, )
        def __next__(self):
            return next(iter(self))
        def __getitem__(self, attr):
            class Value(object):
                @property
                def name(self):
                    return ''
                @property
                def value(self):
                    return attr

            return Value()
        __members__ = ['']
    """)
    class_node = infer_func_form(node, [enum_meta], context=context,
                                 enum=True)[0]
    return iter([class_node.instantiate_class()])
Exemplo n.º 10
0
def infer_typing_attr(
    node: Subscript, ctx: context.InferenceContext | None = None
) -> Iterator[ClassDef]:
    """Infer a typing.X[...] subscript"""
    try:
        value = next(node.value.infer())  # type: ignore[union-attr] # value shouldn't be None for Subscript.
    except (InferenceError, StopIteration) as exc:
        raise UseInferenceDefault from exc

    if not value.qname().startswith("typing.") or value.qname() in TYPING_ALIAS:
        # If typing subscript belongs to an alias handle it separately.
        raise UseInferenceDefault

    if isinstance(value, ClassDef) and value.qname() in {
        "typing.Generic",
        "typing.Annotated",
        "typing_extensions.Annotated",
    }:
        # typing.Generic and typing.Annotated (PY39) are subscriptable
        # through __class_getitem__. Since astroid can't easily
        # infer the native methods, replace them for an easy inference tip
        func_to_add = _extract_single_node(CLASS_GETITEM_TEMPLATE)
        value.locals["__class_getitem__"] = [func_to_add]
        if (
            isinstance(node.parent, ClassDef)
            and node in node.parent.bases
            and getattr(node.parent, "__cache", None)
        ):
            # node.parent.slots is evaluated and cached before the inference tip
            # is first applied. Remove the last result to allow a recalculation of slots
            cache = node.parent.__cache  # type: ignore[attr-defined] # Unrecognized getattr
            if cache.get(node.parent.slots) is not None:
                del cache[node.parent.slots]
        return iter([value])

    node = extract_node(TYPING_TYPE_TEMPLATE.format(value.qname().split(".")[-1]))
    return node.infer(context=ctx)
Exemplo n.º 11
0
def infer_special_alias(
    node: Call, ctx: context.InferenceContext | None = None
) -> Iterator[ClassDef]:
    """Infer call to tuple alias as new subscriptable class typing.Tuple."""
    if not (
        isinstance(node.parent, Assign)
        and len(node.parent.targets) == 1
        and isinstance(node.parent.targets[0], AssignName)
    ):
        raise UseInferenceDefault
    try:
        res = next(node.args[0].infer(context=ctx))
    except StopIteration as e:
        raise InferenceError(node=node.args[0], context=context) from e

    assign_name = node.parent.targets[0]
    class_def = ClassDef(
        name=assign_name.name,
        parent=node.parent,
    )
    class_def.postinit(bases=[res], body=[], decorators=None)
    func_to_add = _extract_single_node(CLASS_GETITEM_TEMPLATE)
    class_def.locals["__class_getitem__"] = [func_to_add]
    return iter([class_def])
Exemplo n.º 12
0
 def test_string_format(self, format_string: str) -> None:
     node: nodes.Call = _extract_single_node(format_string)
     inferred = next(node.infer())
     assert isinstance(inferred, nodes.Const)
     assert inferred.value == "My name is Daniel, I'm 12"
Exemplo n.º 13
0
 def test_string_format_with_specs(self) -> None:
     node: nodes.Call = _extract_single_node(
         """"My name is {}, I'm {:.2f}".format("Daniel", 12)""")
     inferred = next(node.infer())
     assert isinstance(inferred, nodes.Const)
     assert inferred.value == "My name is Daniel, I'm 12.00"
Exemplo n.º 14
0
 def test_string_format_uninferable(self, format_string: str) -> None:
     node: nodes.Call = _extract_single_node(format_string)
     inferred = next(node.infer())
     assert inferred is util.Uninferable
Exemplo n.º 15
0
def infer_old_typedDict(  # pylint: disable=invalid-name
    node: ClassDef, ctx: context.InferenceContext | None = None
) -> Iterator[ClassDef]:
    func_to_add = _extract_single_node("dict")
    node.locals["__call__"] = [func_to_add]
    return iter([node])