From 875651b8021a27488685fba52250a594fa277f2a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 22 Sep 2024 13:28:47 +0000 Subject: [PATCH 1/5] [Backport maintenance/3.3.x] Address pylint 3.3 messages (#2577) * Address pylint 3.3 messages (#2575) (cherry picked from commit 706fcdbe43230900c4425f5b8896b114be4c1024) --- astroid/bases.py | 8 +++----- astroid/exceptions.py | 2 +- astroid/nodes/_base_nodes.py | 2 +- astroid/nodes/node_classes.py | 4 ++-- astroid/typing.py | 2 +- pylintrc | 3 +++ 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/astroid/bases.py b/astroid/bases.py index 4a684cf1fe..4a0d152656 100644 --- a/astroid/bases.py +++ b/astroid/bases.py @@ -147,7 +147,7 @@ def _infer_stmts( stmts: Iterable[InferenceResult], context: InferenceContext | None, frame: nodes.NodeNG | BaseInstance | None = None, -) -> collections.abc.Generator[InferenceResult, None, None]: +) -> collections.abc.Generator[InferenceResult]: """Return an iterator on statements inferred by each statement in *stmts*.""" inferred = False constraint_failed = False @@ -354,7 +354,7 @@ def infer_binary_op( other: InferenceResult, context: InferenceContext, method: SuccessfulInferenceResult, - ) -> Generator[InferenceResult, None, None]: + ) -> Generator[InferenceResult]: return method.infer_call_result(self, context) def __repr__(self) -> str: @@ -491,9 +491,7 @@ def _infer_builtin_new( self, caller: SuccessfulInferenceResult | None, context: InferenceContext, - ) -> collections.abc.Generator[ - nodes.Const | Instance | UninferableBase, None, None - ]: + ) -> collections.abc.Generator[nodes.Const | Instance | UninferableBase]: if not isinstance(caller, nodes.Call): return if not caller.args: diff --git a/astroid/exceptions.py b/astroid/exceptions.py index dd78a81ffe..126acb954d 100644 --- a/astroid/exceptions.py +++ b/astroid/exceptions.py @@ -230,7 +230,7 @@ class InferenceError(ResolveError): # pylint: disable=too-many-instance-attribu context: InferenceContext object. """ - def __init__( # pylint: disable=too-many-arguments + def __init__( # pylint: disable=too-many-arguments, too-many-positional-arguments self, message: str = "Inference failed for {node!r}.", node: InferenceResult | None = None, diff --git a/astroid/nodes/_base_nodes.py b/astroid/nodes/_base_nodes.py index 96c3c1c06d..2d210f17af 100644 --- a/astroid/nodes/_base_nodes.py +++ b/astroid/nodes/_base_nodes.py @@ -42,7 +42,7 @@ InferenceContext, InferenceContext, ], - list[partial[Generator[InferenceResult, None, None]]], + list[partial[Generator[InferenceResult]]], ] diff --git a/astroid/nodes/node_classes.py b/astroid/nodes/node_classes.py index 1924c78eba..5ce00e3d6e 100644 --- a/astroid/nodes/node_classes.py +++ b/astroid/nodes/node_classes.py @@ -82,7 +82,7 @@ def _is_const(value) -> bool: ] InferBinaryOperation = Callable[ [_NodesT, Optional[InferenceContext]], - Generator[Union[InferenceResult, _BadOpMessageT], None, None], + Generator[Union[InferenceResult, _BadOpMessageT]], ] InferLHS = Callable[ [_NodesT, Optional[InferenceContext]], @@ -737,7 +737,7 @@ def __init__( self.vararg_node = vararg_node self.kwarg_node = kwarg_node - # pylint: disable=too-many-arguments + # pylint: disable=too-many-arguments, too-many-positional-arguments def postinit( self, args: list[AssignName] | None, diff --git a/astroid/typing.py b/astroid/typing.py index 27d95c21fb..77cc120306 100644 --- a/astroid/typing.py +++ b/astroid/typing.py @@ -76,7 +76,7 @@ class AstroidManagerBrain(TypedDict): "InferenceContext", SuccessfulInferenceResult, ], - Generator[InferenceResult, None, None], + Generator[InferenceResult], ] diff --git a/pylintrc b/pylintrc index 76aa73716c..d605bc4826 100644 --- a/pylintrc +++ b/pylintrc @@ -301,6 +301,9 @@ exclude-protected=_asdict,_fields,_replace,_source,_make # Maximum number of arguments for function / method max-args=10 +# Maximum number of positional arguments for function / method. +max-positional-arguments=8 + # Argument names that match this expression will be ignored. Default to name # with leading underscore From 1915cc36e1758780c102b1793525b985c9780d4f Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Sun, 22 Sep 2024 09:39:58 -0400 Subject: [PATCH 2/5] Fix `manager.clear_cache()` not fully clearing the module cache (#2572) (#2573) (cherry picked from commit 58286a1bbe55f41dc2eca0ae61755d030654f093) Co-authored-by: Akhil Kamat --- ChangeLog | 2 ++ astroid/manager.py | 2 ++ tests/test_manager.py | 26 +++++++++++++++++++ tests/testdata/python3/data/cache/__init__.py | 0 tests/testdata/python3/data/cache/a.py | 1 + 5 files changed, 31 insertions(+) create mode 100644 tests/testdata/python3/data/cache/__init__.py create mode 100644 tests/testdata/python3/data/cache/a.py diff --git a/ChangeLog b/ChangeLog index 1ad303a154..6d7911cd1d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,7 +13,9 @@ What's New in astroid 3.3.4? ============================ Release date: TBA +* Fix bug with ``manager.clear_cache()`` not fully clearing cache + Refs https://github.com/pylint-dev/pylint/pull/9932#issuecomment-2364985551 What's New in astroid 3.3.3? ============================ diff --git a/astroid/manager.py b/astroid/manager.py index e7c2c806f7..e5398c45a9 100644 --- a/astroid/manager.py +++ b/astroid/manager.py @@ -464,6 +464,8 @@ def clear_cache(self) -> None: _invalidate_cache() # inference context cache self.astroid_cache.clear() + self._mod_file_cache.clear() + # NB: not a new TransformVisitor() AstroidManager.brain["_transform"].transforms = collections.defaultdict(list) diff --git a/tests/test_manager.py b/tests/test_manager.py index 34ddd06d4a..9a7bbdb7ef 100644 --- a/tests/test_manager.py +++ b/tests/test_manager.py @@ -491,6 +491,32 @@ def test_clear_cache_clears_other_lru_caches(self) -> None: # less equal because the "baseline" might have had multiple calls to bootstrap() self.assertLessEqual(cleared_cache.currsize, baseline_cache.currsize) + def test_file_cache_after_clear_cache(self) -> None: + """Test to mimic the behavior of how pylint lints file and + ensure clear cache clears everything stored in the cache. + See https://github.com/pylint-dev/pylint/pull/9932#issuecomment-2364985551 + for more information. + """ + orig_sys_path = sys.path[:] + try: + search_path = resources.RESOURCE_PATH + sys.path.insert(0, search_path) + node = astroid.MANAGER.ast_from_file(resources.find("data/cache/a.py")) + self.assertEqual(node.name, "cache.a") + + # This import from statement should succeed and update the astroid cache + importfrom_node = astroid.extract_node("from cache import a") + importfrom_node.do_import_module(importfrom_node.modname) + finally: + sys.path = orig_sys_path + + astroid.MANAGER.clear_cache() + + importfrom_node = astroid.extract_node("from cache import a") + # Try import from again after clear cache, this should raise an error + with self.assertRaises(AstroidBuildingError): + importfrom_node.do_import_module(importfrom_node.modname) + def test_brain_plugins_reloaded_after_clearing_cache(self) -> None: astroid.MANAGER.clear_cache() format_call = astroid.extract_node("''.format()") diff --git a/tests/testdata/python3/data/cache/__init__.py b/tests/testdata/python3/data/cache/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/testdata/python3/data/cache/a.py b/tests/testdata/python3/data/cache/a.py new file mode 100644 index 0000000000..9ddc377f39 --- /dev/null +++ b/tests/testdata/python3/data/cache/a.py @@ -0,0 +1 @@ +""" Test for clear cache. Doesn't need anything here""" From 97871e9489316ffac09348fe655f6571a21c4d3d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 22 Sep 2024 13:46:54 +0000 Subject: [PATCH 3/5] Check for empty format specs (#2574) (#2576) (cherry picked from commit a679550d3dc87edaa35b334771527cba5102a373) Co-authored-by: Nick Drozd --- ChangeLog | 5 +++++ astroid/nodes/node_classes.py | 3 +++ tests/test_inference.py | 8 ++++++++ 3 files changed, 16 insertions(+) diff --git a/ChangeLog b/ChangeLog index 6d7911cd1d..1f6ee6d560 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,6 +17,11 @@ Release date: TBA Refs https://github.com/pylint-dev/pylint/pull/9932#issuecomment-2364985551 +* Fix a crash from inferring empty format specs. + + Closes pylint-dev/pylint#9945 + + What's New in astroid 3.3.3? ============================ Release date: 2024-09-20 diff --git a/astroid/nodes/node_classes.py b/astroid/nodes/node_classes.py index 5ce00e3d6e..48326e2194 100644 --- a/astroid/nodes/node_classes.py +++ b/astroid/nodes/node_classes.py @@ -4779,6 +4779,9 @@ def _infer( def _infer_from_values( cls, nodes: list[NodeNG], context: InferenceContext | None = None, **kwargs: Any ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: + if not nodes: + yield + return if len(nodes) == 1: yield from nodes[0]._infer(context, **kwargs) return diff --git a/tests/test_inference.py b/tests/test_inference.py index 185ee0f650..daa5613565 100644 --- a/tests/test_inference.py +++ b/tests/test_inference.py @@ -7380,3 +7380,11 @@ def test_sys_argv_uninferable() -> None: sys_argv_value = list(a._infer()) assert len(sys_argv_value) == 1 assert sys_argv_value[0] is Uninferable + + +def test_empty_format_spec() -> None: + """Regression test for https://github.com/pylint-dev/pylint/issues/9945.""" + node = extract_node('f"{x:}"') + assert isinstance(node, nodes.JoinedStr) + + assert list(node.infer()) == [util.Uninferable] From c51f510e4ad4a354335c5dc9cce827670de6f5d4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 14:03:44 -0400 Subject: [PATCH 4/5] Fix issue when inferring single-node or non-const JoinedStr (#2578) (#2579) (cherry picked from commit 8585ce64d2e53aeb556e3c49b866571f1276f9cb) Co-authored-by: Eric Vergnaud --- ChangeLog | 4 ++++ astroid/nodes/node_classes.py | 34 ++++++++++++++++------------------ tests/test_inference.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1f6ee6d560..d5f5207030 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,10 @@ What's New in astroid 3.3.4? ============================ Release date: TBA +* Fix regression with f-string inference. + + Closes pylint-dev/pylint#9947 + * Fix bug with ``manager.clear_cache()`` not fully clearing cache Refs https://github.com/pylint-dev/pylint/pull/9932#issuecomment-2364985551 diff --git a/astroid/nodes/node_classes.py b/astroid/nodes/node_classes.py index 48326e2194..6845ca99c1 100644 --- a/astroid/nodes/node_classes.py +++ b/astroid/nodes/node_classes.py @@ -4676,32 +4676,30 @@ def get_children(self): def _infer( self, context: InferenceContext | None = None, **kwargs: Any ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: - if self.format_spec is None: - yield from self.value.infer(context, **kwargs) - return + format_specs = Const("") if self.format_spec is None else self.format_spec uninferable_already_generated = False - for format_spec in self.format_spec.infer(context, **kwargs): + for format_spec in format_specs.infer(context, **kwargs): if not isinstance(format_spec, Const): if not uninferable_already_generated: yield util.Uninferable uninferable_already_generated = True continue for value in self.value.infer(context, **kwargs): + value_to_format = value if isinstance(value, Const): - try: - formatted = format(value.value, format_spec.value) - yield Const( - formatted, - lineno=self.lineno, - col_offset=self.col_offset, - end_lineno=self.end_lineno, - end_col_offset=self.end_col_offset, - ) - continue - except (ValueError, TypeError): - # happens when format_spec.value is invalid - pass # fall through - if not uninferable_already_generated: + value_to_format = value.value + try: + formatted = format(value_to_format, format_spec.value) + yield Const( + formatted, + lineno=self.lineno, + col_offset=self.col_offset, + end_lineno=self.end_lineno, + end_col_offset=self.end_col_offset, + ) + continue + except (ValueError, TypeError): + # happens when format_spec.value is invalid yield util.Uninferable uninferable_already_generated = True continue diff --git a/tests/test_inference.py b/tests/test_inference.py index daa5613565..acc8a2b1f8 100644 --- a/tests/test_inference.py +++ b/tests/test_inference.py @@ -19,6 +19,7 @@ import pytest from astroid import ( + Assign, Const, Slice, Uninferable, @@ -7388,3 +7389,33 @@ def test_empty_format_spec() -> None: assert isinstance(node, nodes.JoinedStr) assert list(node.infer()) == [util.Uninferable] + + +@pytest.mark.parametrize( + "source, expected", + [ + ( + """ +class Cls: + # pylint: disable=too-few-public-methods + pass + +c_obj = Cls() + +s1 = f'{c_obj!r}' #@ +""", + "<__main__.Cls", + ), + ("s1 = f'{5}' #@", "5"), + ], +) +def test_joined_str_returns_string(source, expected) -> None: + """Regression test for https://github.com/pylint-dev/pylint/issues/9947.""" + node = extract_node(source) + assert isinstance(node, Assign) + target = node.targets[0] + assert target + inferred = list(target.inferred()) + assert len(inferred) == 1 + assert isinstance(inferred[0], Const) + inferred[0].value.startswith(expected) From 6042e585859420ff98a9f9c2f383a3f3e54f567a Mon Sep 17 00:00:00 2001 From: Jacob Walls Date: Mon, 23 Sep 2024 14:04:59 -0400 Subject: [PATCH 5/5] Bump astroid to 3.3.4, update changelog --- ChangeLog | 8 +++++++- astroid/__pkginfo__.py | 2 +- tbump.toml | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index d5f5207030..de225b18c8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,10 +9,16 @@ Release date: TBA -What's New in astroid 3.3.4? +What's New in astroid 3.3.5? ============================ Release date: TBA + + +What's New in astroid 3.3.4? +============================ +Release date: 2024-09-23 + * Fix regression with f-string inference. Closes pylint-dev/pylint#9947 diff --git a/astroid/__pkginfo__.py b/astroid/__pkginfo__.py index 5308ae2a47..1ade3f2033 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.3.3" +__version__ = "3.3.4" version = __version__ diff --git a/tbump.toml b/tbump.toml index 4b3f2f246a..d0bf2b3041 100644 --- a/tbump.toml +++ b/tbump.toml @@ -1,7 +1,7 @@ github_url = "https://github.com/pylint-dev/astroid" [version] -current = "3.3.3" +current = "3.3.4" regex = ''' ^(?P0|[1-9]\d*) \.