Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test failures on Python 3.13 with astroid 3.0.2 #2349

Open
limburgher opened this issue Dec 14, 2023 · 4 comments
Open

Test failures on Python 3.13 with astroid 3.0.2 #2349

limburgher opened this issue Dec 14, 2023 · 4 comments

Comments

@limburgher
Copy link
Contributor

=================================== FAILURES ===================================
___________ test_dataclasses_subscript_inference_recursion_error_39 ____________

@pytest.mark.skipif(
    not PY39_PLUS,
    reason="Exact inference with dataclasses (replace function) in python3.9",
)
def test_dataclasses_subscript_inference_recursion_error_39():
    code = """
    from dataclasses import dataclass, replace

    @dataclass
    class ProxyConfig:
        auth: str = "/auth"


    a = ProxyConfig("")
    test_dict = {"proxy" : {"auth" : "", "bla" : "f"}}

    foo = test_dict['proxy']
    replace(a, **test_dict['proxy']) # This fails
    """
    node = extract_node(code)
    infer_val = util.safe_infer(node)
  assert isinstance(infer_val, Instance)

E assert False
E + where False = isinstance(Uninferable, Instance)

tests/test_inference.py:6731: AssertionError
_______________ TypingBrain.test_typing_annotated_subscriptable ________________

self = <tests.brain.test_brain.TypingBrain testMethod=test_typing_annotated_subscriptable>

@test_utils.require_version(minver="3.9")
def test_typing_annotated_subscriptable(self):
    """Test typing.Annotated is subscriptable with __class_getitem__"""
    node = builder.extract_node(
        """
    import typing
    typing.Annotated[str, "data"]
    """
    )
    inferred = next(node.infer())
    assert isinstance(inferred, nodes.ClassDef)
  assert isinstance(inferred.getattr("__class_getitem__")[0], nodes.FunctionDef)

tests/brain/test_brain.py:641:


self = <ClassDef.Annotated l.10 at 0x7faefc93e120>, name = 'class_getitem'
context = None, class_context = True

def getattr(
    self,
    name: str,
    context: InferenceContext | None = None,
    class_context: bool = True,
) -> list[InferenceResult]:
    """Get an attribute from this class, using Python's attribute semantic.

    This method doesn't look in the :attr:`instance_attrs` dictionary
    since it is done by an :class:`Instance` proxy at inference time.
    It may return an :class:`Uninferable` object if
    the attribute has not been
    found, but a ``__getattr__`` or ``__getattribute__`` method is defined.
    If ``class_context`` is given, then it is considered that the
    attribute is accessed from a class context,
    e.g. ClassDef.attribute, otherwise it might have been accessed
    from an instance as well. If ``class_context`` is used in that
    case, then a lookup in the implicit metaclass and the explicit
    metaclass will be done.

    :param name: The attribute to look for.

    :param class_context: Whether the attribute can be accessed statically.

    :returns: The attribute.

    :raises AttributeInferenceError: If the attribute cannot be inferred.
    """
    if not name:
        raise AttributeInferenceError(target=self, attribute=name, context=context)

    # don't modify the list in self.locals!
    values: list[InferenceResult] = list(self.locals.get(name, []))
    for classnode in self.ancestors(recurs=True, context=context):
        values += classnode.locals.get(name, [])

    if name in self.special_attributes and class_context and not values:
        result = [self.special_attributes.lookup(name)]
        if name == "__bases__":
            # Need special treatment, since they are mutable
            # and we need to return all the values.
            result += values
        return result

    if class_context:
        values += self._metaclass_lookup_attribute(name, context)

    # Remove AnnAssigns without value, which are not attributes in the purest sense.
    for value in values.copy():
        if isinstance(value, node_classes.AssignName):
            stmt = value.statement()
            if isinstance(stmt, node_classes.AnnAssign) and stmt.value is None:
                values.pop(values.index(value))

    if not values:
      raise AttributeInferenceError(target=self, attribute=name, context=context)

E astroid.exceptions.AttributeInferenceError: 'class_getitem' not found on <ClassDef.Annotated l.10 at 0x7faefc93e120>.

astroid/nodes/scoped_nodes/scoped_nodes.py:2425: AttributeInferenceError
=========================== short test summary info ============================
FAILED tests/test_inference.py::test_dataclasses_subscript_inference_recursion_error_39
FAILED tests/brain/test_brain.py::TypingBrain::test_typing_annotated_subscriptable
=========== 2 failed, 1581 passed, 77 skipped, 16 xfailed in 18.03s ============

@DanielNoord
Copy link
Collaborator

We're running our CI against 3.12 so I don't fully understand what is different about your environment that could cause these failures.

@limburgher limburgher changed the title Test failures on Python 3.12 with astroid 3.0.2 Test failures on Python 3.13 with astroid 3.0.2 Dec 15, 2023
@limburgher
Copy link
Contributor Author

Apologies, I meant 3.13.

@Pierre-Sassoulas
Copy link
Member

From experience a lot can change in the first alphas, fixing things for a feature that will disappear later is a waste of time (also possibly add untestable warts in the codebase) so I would wait for betas and availability of an image in github pipelines to actually start fixing astroid/pylint for python 3.13.

@frenzymadness
Copy link

I've tried to analyze at least one of the failures because the code of astroid is very complex nad my knowledge of it is limited.

The failure of tests/test_inference.py::test_dataclasses_subscript_inference_recursion_error_39 is caused by this change in CPython: python/cpython@6f3c138

In Python 3.12.2, when analyzing the replace function in dataclasses module, astroid finds the return node on line 1579.

But in Python 3.13.0a5, the replace function calls a new _replace function, astroid finds return node on line 1548 and marks it as Uninferable.

With your help, I might be able to go deeper and investigate also other failures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants