From 564e9c6427a743d9a92c40d8e79fe0a30037e517 Mon Sep 17 00:00:00 2001 From: bahtya Date: Wed, 8 Apr 2026 18:08:10 +0800 Subject: [PATCH 1/2] fix: exclude setuptools.tests from wheel distribution The exclude patterns '*.tests' and '*.tests.*' match packages named like 'foo.tests' but do not match 'setuptools/tests' because that directory is a subpackage of setuptools, not a top-level package matching the glob. Add explicit 'setuptools.tests' and 'setuptools.tests.*' to the exclude list so test files are not included in the wheel. Fixes #5212 Signed-off-by: bahtya --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 3439f861bc..9b734d0427 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -206,6 +206,8 @@ include = [ exclude = [ "*.tests", "*.tests.*", + "setuptools.tests", + "setuptools.tests.*", ] namespaces = true From 6967c66498468b5677c9ab65f3aaa76ad90c87d2 Mon Sep 17 00:00:00 2001 From: Bahtya Date: Thu, 23 Apr 2026 01:07:45 +0800 Subject: [PATCH 2/2] Revert redundant exclude patterns, add tests verifying glob patterns work The existing exclude patterns `*.tests` and `*.tests.*` already correctly exclude `setuptools.tests` and its subpackages via fnmatch glob matching. The explicit `setuptools.tests` and `setuptools.tests.*` patterns were redundant. Add TestGlobExcludePatterns to verify the glob exclude patterns work as expected, addressing the maintainer's review feedback. Bahtya Signed-off-by: Bahtya --- pyproject.toml | 2 -- setuptools/tests/test_find_packages.py | 41 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9b734d0427..3439f861bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -206,8 +206,6 @@ include = [ exclude = [ "*.tests", "*.tests.*", - "setuptools.tests", - "setuptools.tests.*", ] namespaces = true diff --git a/setuptools/tests/test_find_packages.py b/setuptools/tests/test_find_packages.py index 9fd9f8f663..e5b2ec3c9a 100644 --- a/setuptools/tests/test_find_packages.py +++ b/setuptools/tests/test_find_packages.py @@ -211,6 +211,47 @@ def test_unwanted_directories_not_included(self, tmp_path, example): assert set(found_packages) == set(expected_packages) +class TestGlobExcludePatterns: + """Verify that glob-style exclude patterns (e.g. ``*.tests``) correctly + exclude nested test packages. See pypa/setuptools#5214.""" + + @pytest.mark.parametrize( + "pattern, package", + [ + ("*.tests", "setuptools.tests"), + ("*.tests", "pkg.tests"), + ("*.tests.*", "setuptools.tests.config"), + ("*.tests.*", "pkg.tests.sub"), + ], + ) + def test_star_dot_tests_excludes_nested_packages(self, pattern, package): + """``*.tests`` and ``*.tests.*`` should match nested test packages.""" + from fnmatch import fnmatchcase + + assert fnmatchcase(package, pattern), ( + f"{pattern!r} should match {package!r}" + ) + + def test_wildcard_exclude_patterns_in_find_namespace_packages(self, tmp_path): + """End-to-end check: ``find_namespace_packages(exclude=['*.tests', '*.tests.*'])`` + should not return ``pkg.tests`` or ``pkg.tests.sub``.""" + ensure_files(tmp_path, [ + "pkg/__init__.py", + "pkg/tests/__init__.py", + "pkg/tests/sub/__init__.py", + "pkg/other/__init__.py", + ]) + packages = find_namespace_packages( + str(tmp_path), + include=["pkg*"], + exclude=["*.tests", "*.tests.*"], + ) + assert "pkg" in packages + assert "pkg.other" in packages + assert "pkg.tests" not in packages + assert "pkg.tests.sub" not in packages + + def ensure_files(root_path, files): for file in files: path = root_path / file