diff --git a/ChangeLog b/ChangeLog index 66dd914c73..0091e20eb6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,12 +9,21 @@ Release date: TBA -What's New in astroid 3.2.3? +What's New in astroid 3.2.4? ============================ Release date: TBA +What's New in astroid 3.2.3? +============================ +Release date: 2024-07-11 + +* Fix ``AssertionError`` when inferring a property consisting of a partial function. + +Closes pylint-dev/pylint#9214 + + What's New in astroid 3.2.2? ============================ Release date: 2024-05-20 diff --git a/astroid/__pkginfo__.py b/astroid/__pkginfo__.py index ecdef3b2ce..175cd05f41 100644 --- a/astroid/__pkginfo__.py +++ b/astroid/__pkginfo__.py @@ -2,5 +2,5 @@ # For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt -__version__ = "3.2.2" +__version__ = "3.2.3" version = __version__ diff --git a/astroid/nodes/node_classes.py b/astroid/nodes/node_classes.py index 708b51a009..22bb4da81b 100644 --- a/astroid/nodes/node_classes.py +++ b/astroid/nodes/node_classes.py @@ -1057,6 +1057,8 @@ def _format_args( annotations = [] if defaults is not None: default_offset = len(args) - len(defaults) + else: + default_offset = None packed = itertools.zip_longest(args, annotations) for i, (arg, annotation) in enumerate(packed): if arg.name in skippable_names: @@ -1071,7 +1073,7 @@ def _format_args( default_sep = " = " values.append(argname) - if defaults is not None and i >= default_offset: + if default_offset is not None and i >= default_offset: if defaults[i - default_offset] is not None: values[-1] += default_sep + defaults[i - default_offset].as_string() return ", ".join(values) diff --git a/astroid/nodes/scoped_nodes/scoped_nodes.py b/astroid/nodes/scoped_nodes/scoped_nodes.py index 0f1f16479a..dc48a43c71 100644 --- a/astroid/nodes/scoped_nodes/scoped_nodes.py +++ b/astroid/nodes/scoped_nodes/scoped_nodes.py @@ -1557,8 +1557,6 @@ def infer_yield_result(self, context: InferenceContext | None = None): :returns: What the function yields :rtype: iterable(NodeNG or Uninferable) or None """ - # pylint: disable=not-an-iterable - # https://github.com/pylint-dev/astroid/issues/1015 for yield_ in self.nodes_of_class(node_classes.Yield): if yield_.value is None: const = node_classes.Const(None) @@ -2541,6 +2539,10 @@ def igetattr( elif isinstance(inferred, objects.Property): function = inferred.function if not class_context: + if not context.callcontext: + context.callcontext = CallContext( + args=function.args.arguments, callee=function + ) # Through an instance so we can solve the property yield from function.infer_call_result( caller=self, context=context diff --git a/requirements_dev.txt b/requirements_dev.txt index ee1c41bc96..4949455f52 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -3,6 +3,6 @@ # Tools used during development, prefer running these with pre-commit black pre-commit -pylint +pylint>=3.2.0 mypy ruff diff --git a/requirements_full.txt b/requirements_full.txt index e8196e629d..1780bc89d3 100644 --- a/requirements_full.txt +++ b/requirements_full.txt @@ -4,7 +4,7 @@ # Packages used to run additional tests attrs nose -numpy>=1.17.0; python_version<"3.12" +numpy>=1.17.0,<2; python_version<"3.12" python-dateutil PyQt6 regex diff --git a/tbump.toml b/tbump.toml index 7d413f1aca..eb010a1738 100644 --- a/tbump.toml +++ b/tbump.toml @@ -1,7 +1,7 @@ github_url = "https://github.com/pylint-dev/astroid" [version] -current = "3.2.2" +current = "3.2.3" regex = ''' ^(?P0|[1-9]\d*) \. diff --git a/tests/test_builder.py b/tests/test_builder.py index 84ac65e099..23a5a83836 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -777,7 +777,7 @@ def test_module_base_props(self) -> None: with self.assertRaises(StatementMissing): with pytest.warns(DeprecationWarning) as records: self.assertEqual(module.statement(future=True), module) - assert len(records) == 1 + assert len(records) == 1 with self.assertRaises(StatementMissing): module.statement() diff --git a/tests/test_regrtest.py b/tests/test_regrtest.py index 45f241f8cf..101e1d4417 100644 --- a/tests/test_regrtest.py +++ b/tests/test_regrtest.py @@ -477,3 +477,22 @@ def test_recursion_during_inference(mocked) -> None: with pytest.raises(InferenceError) as error: next(node.infer()) assert error.value.message.startswith("RecursionError raised") + + +def test_regression_missing_callcontext() -> None: + node: nodes.Attribute = _extract_single_node( + textwrap.dedent( + """ + import functools + + class MockClass: + def _get_option(self, option): + return "mystr" + + enabled = property(functools.partial(_get_option, option='myopt')) + + MockClass().enabled + """ + ) + ) + assert node.inferred()[0].value == "mystr"