diff --git a/changelog.d/3243.deprecation.rst b/changelog.d/3243.deprecation.rst new file mode 100644 index 0000000000..067bf29f69 --- /dev/null +++ b/changelog.d/3243.deprecation.rst @@ -0,0 +1,3 @@ +Added a deprecation warning when `setuptools.find_packages()` includes +a package in the reserved top-level package name list (e.g. ``tests``) +-- by :user:`mgorny`. diff --git a/setuptools/discovery.py b/setuptools/discovery.py index 95c3c7f83e..45f75acafc 100644 --- a/setuptools/discovery.py +++ b/setuptools/discovery.py @@ -44,12 +44,15 @@ from pathlib import Path from typing import TYPE_CHECKING from typing import Callable, Dict, Iterator, Iterable, List, Optional, Tuple, Union +import warnings import _distutils_hack.override # noqa: F401 from distutils import log from distutils.util import convert_path +import setuptools + _Path = Union[str, os.PathLike] _Filter = Callable[[str], bool] StrIter = Iterator[str] @@ -148,6 +151,13 @@ def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter # Should this package be included? if include(package) and not exclude(package): + top_package = package.split(".")[0] + if top_package in FlatLayoutPackageFinder._EXCLUDE: + warnings.warn( + f"{top_package!r} is a reserved package name. " + "Please add it to find_package(exclude=...)", + setuptools.SetuptoolsDeprecationWarning, + ) yield package # Keep searching subdirectories, as there may be more packages diff --git a/setuptools/tests/test_find_packages.py b/setuptools/tests/test_find_packages.py index efcce924e5..570d2623dd 100644 --- a/setuptools/tests/test_find_packages.py +++ b/setuptools/tests/test_find_packages.py @@ -7,6 +7,7 @@ import pytest +import setuptools from setuptools import find_packages from setuptools import find_namespace_packages from setuptools.discovery import FlatLayoutPackageFinder @@ -157,13 +158,17 @@ def test_pep420_ns_package(self): self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg']) def test_pep420_ns_package_no_includes(self): - packages = find_namespace_packages( - self.dist_dir, exclude=['pkg.subpkg.assets']) + with pytest.warns(setuptools.SetuptoolsDeprecationWarning, + match="'docs' is a reserved package name"): + packages = find_namespace_packages( + self.dist_dir, exclude=['pkg.subpkg.assets']) self._assert_packages( packages, ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg']) def test_pep420_ns_package_no_includes_or_excludes(self): - packages = find_namespace_packages(self.dist_dir) + with pytest.warns(setuptools.SetuptoolsDeprecationWarning, + match="'docs' is a reserved package name"): + packages = find_namespace_packages(self.dist_dir) expected = [ 'docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg', 'pkg.subpkg.assets'] self._assert_packages(packages, expected)