From ec4ca648f1b118ef44aefe859e4228ba405fba9d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 21:08:12 +0000 Subject: [PATCH 1/5] Fix release note typo (#9969) (#9971) (cherry picked from commit 0972ba526d9ab010441f936fbcd034e18389cf27) Co-authored-by: Jacob Walls --- doc/whatsnew/3/3.3/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/whatsnew/3/3.3/index.rst b/doc/whatsnew/3/3.3/index.rst index 0faf140c77..9b47c852ab 100644 --- a/doc/whatsnew/3/3.3/index.rst +++ b/doc/whatsnew/3/3.3/index.rst @@ -66,7 +66,7 @@ New Checks Closes #9099 (`#9099 `_) -- Add `using-exception-group-in-unsupported-version` and +- Add `using-exception-groups-in-unsupported-version` and `using-generic-type-syntax-in-unsupported-version` for uses of Python 3.11+ or 3.12+ features on lower supported versions provided with `--py-version`. From ea8ed7e0ea84c2e3d58e98f0b38010625eff99a9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 6 Oct 2024 08:14:51 -0400 Subject: [PATCH 2/5] Bump astroid to 3.3.5 (#10004) (#10005) --- pyproject.toml | 2 +- requirements_test_min.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f4dc647e18..4dfbd99dfe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ dependencies = [ # Also upgrade requirements_test_min.txt. # Pinned to dev of second minor update to allow editable installs and fix primer issues, # see https://github.com/pylint-dev/astroid/issues/1341 - "astroid>=3.3.4,<=3.4.0-dev0", + "astroid>=3.3.5,<=3.4.0-dev0", "isort>=4.2.5,<6,!=5.13.0", "mccabe>=0.6,<0.8", "tomli>=1.1.0;python_version<'3.11'", diff --git a/requirements_test_min.txt b/requirements_test_min.txt index 06e60ed7b7..c14b34b837 100644 --- a/requirements_test_min.txt +++ b/requirements_test_min.txt @@ -1,6 +1,6 @@ .[testutils,spelling] # astroid dependency is also defined in pyproject.toml -astroid==3.3.4 # Pinned to a specific version for tests +astroid==3.3.5 # Pinned to a specific version for tests typing-extensions~=4.12 py~=1.11.0 pytest~=8.3 From 5597aae8757a70abf8eb7842b4f1c575aaf7ac47 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 21:10:44 +0100 Subject: [PATCH 3/5] Fix source root not recognized (#10036) (#10083) (cherry picked from commit be530855265e6548ce1e5db54b2e3dd95448f45a) Co-authored-by: Julfried <51880314+Julfried@users.noreply.github.com> --- doc/whatsnew/fragments/10026.bugfix | 3 +++ pylint/lint/expand_modules.py | 2 +- tests/pyreverse/test_main.py | 36 +++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 doc/whatsnew/fragments/10026.bugfix diff --git a/doc/whatsnew/fragments/10026.bugfix b/doc/whatsnew/fragments/10026.bugfix new file mode 100644 index 0000000000..3a80c19309 --- /dev/null +++ b/doc/whatsnew/fragments/10026.bugfix @@ -0,0 +1,3 @@ +Fixes the issue with --source-root option not working when the source files are in a subdirectory of the source root (e.g. when using a /src layout). + +Closes #10026 diff --git a/pylint/lint/expand_modules.py b/pylint/lint/expand_modules.py index f40bdeea5b..a7d31dea6b 100644 --- a/pylint/lint/expand_modules.py +++ b/pylint/lint/expand_modules.py @@ -33,7 +33,7 @@ def discover_package_path(modulepath: str, source_roots: Sequence[str]) -> str: # Look for a source root that contains the module directory for source_root in source_roots: source_root = os.path.realpath(os.path.expanduser(source_root)) - if os.path.commonpath([source_root, dirname]) == source_root: + if os.path.commonpath([source_root, dirname]) in [dirname, source_root]: return source_root # Fall back to legacy discovery by looking for __init__.py upwards as diff --git a/tests/pyreverse/test_main.py b/tests/pyreverse/test_main.py index e8e46df2c1..59fcab16f4 100644 --- a/tests/pyreverse/test_main.py +++ b/tests/pyreverse/test_main.py @@ -65,6 +65,42 @@ def test_project_root_in_sys_path() -> None: assert sys.path == [PROJECT_ROOT_DIR] +def test_discover_package_path_source_root_as_parent(tmp_path: Any) -> None: + """Test discover_package_path when source root is a parent of the module.""" + # Create this temporary structure: + # /tmp_path/ + # └── project/ + # └── my-package/ + # └── __init__.py + project_dir = tmp_path / "project" + package_dir = project_dir / "mypackage" + package_dir.mkdir(parents=True) + (package_dir / "__init__.py").touch() + + # Test with project_dir as source root (parent of package) + result = discover_package_path(str(package_dir), [str(project_dir)]) + assert result == str(project_dir) + + +def test_discover_package_path_source_root_as_child(tmp_path: Any) -> None: + """Test discover_package_path when source root is a child of the module.""" + # Create this temporary structure: + # /tmp_path/ + # └── project/ + # └── src/ + # └── my-package/ + # └── __init__.py + project_dir = tmp_path / "project" + src_dir = project_dir / "src" + package_dir = src_dir / "mypackage" + package_dir.mkdir(parents=True) + (package_dir / "__init__.py").touch() + + # Test with src_dir as source root (child of project) + result = discover_package_path(str(project_dir), [str(src_dir)]) + assert result == str(src_dir) + + @mock.patch("pylint.pyreverse.main.Linker", new=mock.MagicMock()) @mock.patch("pylint.pyreverse.main.DiadefsHandler", new=mock.MagicMock()) @mock.patch("pylint.pyreverse.main.writer") From 621ecf68c9cfda6fcd64c082c59d545556814ca6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 24 Nov 2024 15:39:30 +0100 Subject: [PATCH 4/5] Fix `potential-index-error` false positive when iterable contains starred element (#10097) (#10098) (cherry picked from commit 3e9e613bf5e84c9078466c8650209079a4e8ce4b) Co-authored-by: Zen Lee <53538590+zenlyj@users.noreply.github.com> --- doc/whatsnew/fragments/10076.false_positive | 4 ++++ pylint/checkers/variables.py | 15 ++++++++++++- tests/functional/p/potential_index_error.py | 23 ++++++++++++++++++++ tests/functional/p/potential_index_error.txt | 5 +++++ 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 doc/whatsnew/fragments/10076.false_positive diff --git a/doc/whatsnew/fragments/10076.false_positive b/doc/whatsnew/fragments/10076.false_positive new file mode 100644 index 0000000000..298f448873 --- /dev/null +++ b/doc/whatsnew/fragments/10076.false_positive @@ -0,0 +1,4 @@ +Fix a false positive for `potential-index-error` when an indexed iterable +contains a starred element that evaluates to more than one item. + +Closes #10076 diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 47f6b92d6e..d293e77de7 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -3356,6 +3356,19 @@ def visit_subscript(self, node: nodes.Subscript) -> None: self._check_potential_index_error(node, inferred_slice) + def _inferred_iterable_length(self, iterable: nodes.Tuple | nodes.List) -> int: + length = 0 + for elt in iterable.elts: + if not isinstance(elt, nodes.Starred): + length += 1 + continue + unpacked = utils.safe_infer(elt.value) + if isinstance(unpacked, nodes.BaseContainer): + length += len(unpacked.elts) + else: + length += 1 + return length + def _check_potential_index_error( self, node: nodes.Subscript, inferred_slice: nodes.NodeNG | None ) -> None: @@ -3369,7 +3382,7 @@ def _check_potential_index_error( # If the node.value is a Tuple or List without inference it is defined in place if isinstance(node.value, (nodes.Tuple, nodes.List)): # Add 1 because iterables are 0-indexed - if len(node.value.elts) < inferred_slice.value + 1: + if self._inferred_iterable_length(node.value) < inferred_slice.value + 1: self.add_message( "potential-index-error", node=node, confidence=INFERENCE ) diff --git a/tests/functional/p/potential_index_error.py b/tests/functional/p/potential_index_error.py index 4d3c48d75d..71c025a767 100644 --- a/tests/functional/p/potential_index_error.py +++ b/tests/functional/p/potential_index_error.py @@ -23,3 +23,26 @@ def my_func(): # Test that we don't crash on more complicated indices/slices # We do not raise here (currently) print([1, 2, 3][2:3]) + + +# Test for cases with unpacking operation +my_list = ["foo", "bar"] +my_set = {"foo", "bar"} +my_tuple = ("foo", "bar") +my_iterable = (*my_list, *my_set, *my_tuple, *("foo", "bar")) +my_non_iterable = None + +print([*my_list][1]) +print([*my_list][2]) # [potential-index-error] + +print([*my_set][1]) +print([*my_set][2]) # [potential-index-error] + +print((*my_tuple,)[1]) +print((*my_tuple,)[2]) # [potential-index-error] + +print((*my_iterable,)[7]) +print((*my_iterable,)[8]) # [potential-index-error] + +print((*my_non_iterable,)[0]) +print((*my_non_iterable,)[1]) # [potential-index-error] diff --git a/tests/functional/p/potential_index_error.txt b/tests/functional/p/potential_index_error.txt index 2340f81737..fc99227ec9 100644 --- a/tests/functional/p/potential_index_error.txt +++ b/tests/functional/p/potential_index_error.txt @@ -1,3 +1,8 @@ potential-index-error:6:6:6:18::Invalid index for iterable length:INFERENCE potential-index-error:7:6:7:18::Invalid index for iterable length:INFERENCE potential-index-error:8:6:8:22::Invalid index for iterable length:INFERENCE +potential-index-error:36:6:36:19::Invalid index for iterable length:INFERENCE +potential-index-error:39:6:39:18::Invalid index for iterable length:INFERENCE +potential-index-error:42:6:42:21::Invalid index for iterable length:INFERENCE +potential-index-error:45:6:45:24::Invalid index for iterable length:INFERENCE +potential-index-error:48:6:48:28::Invalid index for iterable length:INFERENCE From a5a1bc3a9602d08f15ac90ad12f5b25bde375613 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Sun, 1 Dec 2024 19:37:20 +0100 Subject: [PATCH 5/5] Bump pylint to 3.3.2, update changelog (#10088) --- doc/whatsnew/3/3.3/index.rst | 24 +++++++++++++++++++++ doc/whatsnew/fragments/10026.bugfix | 3 --- doc/whatsnew/fragments/10076.false_positive | 4 ---- examples/pylintrc | 2 +- examples/pyproject.toml | 2 +- pylint/__pkginfo__.py | 2 +- tbump.toml | 2 +- towncrier.toml | 2 +- 8 files changed, 29 insertions(+), 12 deletions(-) delete mode 100644 doc/whatsnew/fragments/10026.bugfix delete mode 100644 doc/whatsnew/fragments/10076.false_positive diff --git a/doc/whatsnew/3/3.3/index.rst b/doc/whatsnew/3/3.3/index.rst index 9b47c852ab..179f6e8d9c 100644 --- a/doc/whatsnew/3/3.3/index.rst +++ b/doc/whatsnew/3/3.3/index.rst @@ -14,6 +14,30 @@ Summary -- Release highlights .. towncrier release notes start +What's new in Pylint 3.3.2? +--------------------------- +Release date: 2024-12-01 + + +False Positives Fixed +--------------------- + +- Fix a false positive for `potential-index-error` when an indexed iterable + contains a starred element that evaluates to more than one item. + + Closes #10076 (`#10076 `_) + + + +Other Bug Fixes +--------------- + +- Fixes the issue with --source-root option not working when the source files are in a subdirectory of the source root (e.g. when using a /src layout). + + Closes #10026 (`#10026 `_) + + + What's new in Pylint 3.3.1? --------------------------- Release date: 2024-09-24 diff --git a/doc/whatsnew/fragments/10026.bugfix b/doc/whatsnew/fragments/10026.bugfix deleted file mode 100644 index 3a80c19309..0000000000 --- a/doc/whatsnew/fragments/10026.bugfix +++ /dev/null @@ -1,3 +0,0 @@ -Fixes the issue with --source-root option not working when the source files are in a subdirectory of the source root (e.g. when using a /src layout). - -Closes #10026 diff --git a/doc/whatsnew/fragments/10076.false_positive b/doc/whatsnew/fragments/10076.false_positive deleted file mode 100644 index 298f448873..0000000000 --- a/doc/whatsnew/fragments/10076.false_positive +++ /dev/null @@ -1,4 +0,0 @@ -Fix a false positive for `potential-index-error` when an indexed iterable -contains a starred element that evaluates to more than one item. - -Closes #10076 diff --git a/examples/pylintrc b/examples/pylintrc index a26254c199..97064b3e95 100644 --- a/examples/pylintrc +++ b/examples/pylintrc @@ -93,7 +93,7 @@ prefer-stubs=no # Minimum Python version to use for version dependent checks. Will default to # the version used to run pylint. -py-version=3.10 +py-version=3.12 # Discover python modules and packages in the file system subtree. recursive=no diff --git a/examples/pyproject.toml b/examples/pyproject.toml index a647cbb577..ec4790b26f 100644 --- a/examples/pyproject.toml +++ b/examples/pyproject.toml @@ -83,7 +83,7 @@ persistent = true # Minimum Python version to use for version dependent checks. Will default to the # version used to run pylint. -py-version = "3.10" +py-version = "3.12" # Discover python modules and packages in the file system subtree. # recursive = diff --git a/pylint/__pkginfo__.py b/pylint/__pkginfo__.py index 1e68b60ea4..9ed79f3d4a 100644 --- a/pylint/__pkginfo__.py +++ b/pylint/__pkginfo__.py @@ -9,7 +9,7 @@ from __future__ import annotations -__version__ = "3.3.1" +__version__ = "3.3.2" def get_numversion_from_version(v: str) -> tuple[int, int, int]: diff --git a/tbump.toml b/tbump.toml index 35de0dbe91..a07de7ba04 100644 --- a/tbump.toml +++ b/tbump.toml @@ -1,7 +1,7 @@ github_url = "https://github.com/pylint-dev/pylint" [version] -current = "3.3.1" +current = "3.3.2" regex = ''' ^(?P0|[1-9]\d*) \. diff --git a/towncrier.toml b/towncrier.toml index 9908fbeb0c..e289bc8ffc 100644 --- a/towncrier.toml +++ b/towncrier.toml @@ -1,5 +1,5 @@ [tool.towncrier] -version = "3.3.1" +version = "3.3.2" directory = "doc/whatsnew/fragments" filename = "doc/whatsnew/3/3.3/index.rst" template = "doc/whatsnew/fragments/_template.rst"