diff --git a/changelog.d/3262.deprecation.rst b/changelog.d/3262.deprecation.rst new file mode 100644 index 0000000000..e668b226e6 --- /dev/null +++ b/changelog.d/3262.deprecation.rst @@ -0,0 +1,8 @@ +Formally added deprecation messages for ``namespace_packages``. +The methodology that uses ``pkg_resources`` and ``namespace_packages`` for +creating namespaces was already discouraged by the :doc:`setuptools docs +` and the +:doc:`Python Packaging User Guide `, +therefore this change just make the deprecation more official. +Users can consider migrating to native/implicit namespaces (as introduced in +:pep:`420`). diff --git a/docs/references/keywords.rst b/docs/references/keywords.rst index f231b2b8ee..d36630000f 100644 --- a/docs/references/keywords.rst +++ b/docs/references/keywords.rst @@ -353,6 +353,11 @@ extensions). .. _keyword/namespace_packages: ``namespace_packages`` + .. warning:: + ``namespace_packages`` is deprecated in favor of native/implicit + namespaces (:pep:`420`). Check :doc:`the Python Packaging User Guide + ` for more information. + A list of strings naming the project's "namespace packages". A namespace package is a package that may be split across multiple project distributions. For example, Zope 3's ``zope`` package is a namespace diff --git a/docs/userguide/declarative_config.rst b/docs/userguide/declarative_config.rst index 52379dbf1c..2a65e6e367 100644 --- a/docs/userguide/declarative_config.rst +++ b/docs/userguide/declarative_config.rst @@ -210,7 +210,7 @@ packages find:, find_namespace:, list-comma [# package_dir dict package_data section [#opt-1]_ exclude_package_data section -namespace_packages list-comma +namespace_packages list-comma [#opt-5]_ py_modules list-comma 34.4.0 data_files section 40.6.0 [#opt-4]_ ======================= =================================== =============== ========= @@ -243,6 +243,10 @@ data_files section 40.6.0 [# .. [#opt-4] ``data_files`` is deprecated and should be avoided. Please check :doc:`/userguide/datafiles` for more information. +.. [#opt-5] ``namespace_packages`` is deprecated in favour of native/implicit + namespaces (:pep:`420`). Check :doc:`the Python Packaging User Guide + ` for more information. + Compatibility with other tools ============================== diff --git a/docs/userguide/pyproject_config.rst b/docs/userguide/pyproject_config.rst index 7b8f8104fe..8558f5d79d 100644 --- a/docs/userguide/pyproject_config.rst +++ b/docs/userguide/pyproject_config.rst @@ -94,7 +94,7 @@ Key Value Type (TOML) Notes ``py-modules`` array See tip below ``packages`` array or ``find`` directive See tip below ``package-dir`` table/inline-table Used when explicitly listing ``packages`` -``namespace-packages`` array Not necessary if you use :pep:`420` +``namespace-packages`` array **Deprecated** - Use implicit namespaces instead (:pep:`420`) ``package-data`` table/inline-table See :doc:`/userguide/datafiles` ``include-package-data`` boolean ``True`` by default ``exclude-package-data`` table/inline-table diff --git a/setuptools/config/_apply_pyprojecttoml.py b/setuptools/config/_apply_pyprojecttoml.py index 002cc4b809..4b4ed9dff1 100644 --- a/setuptools/config/_apply_pyprojecttoml.py +++ b/setuptools/config/_apply_pyprojecttoml.py @@ -16,6 +16,8 @@ from typing import (TYPE_CHECKING, Any, Callable, Dict, List, Optional, Set, Tuple, Type, Union) +from setuptools._deprecation_warning import SetuptoolsDeprecationWarning + if TYPE_CHECKING: from setuptools._importlib import metadata # noqa from setuptools.dist import Distribution # noqa @@ -75,6 +77,12 @@ def _apply_tool_table(dist: "Distribution", config: dict, filename: _Path): for field, value in tool_table.items(): norm_key = json_compatible_key(field) + + if norm_key in TOOL_TABLE_DEPRECATIONS: + suggestion = TOOL_TABLE_DEPRECATIONS[norm_key] + msg = f"The parameter `{norm_key}` is deprecated, {suggestion}" + warnings.warn(msg, SetuptoolsDeprecationWarning) + norm_key = TOOL_TABLE_RENAMES.get(norm_key, norm_key) _set_config(dist, norm_key, value) @@ -307,6 +315,9 @@ def _acessor(obj): } TOOL_TABLE_RENAMES = {"script_files": "scripts"} +TOOL_TABLE_DEPRECATIONS = { + "namespace_packages": "consider using implicit namespaces instead (PEP 420)." +} SETUPTOOLS_PATCHES = {"long_description_content_type", "project_urls", "provides_extras", "license_file", "license_files"} diff --git a/setuptools/config/setupcfg.py b/setuptools/config/setupcfg.py index d485a8bba8..b2d5c34609 100644 --- a/setuptools/config/setupcfg.py +++ b/setuptools/config/setupcfg.py @@ -12,6 +12,7 @@ from distutils.errors import DistutilsOptionError, DistutilsFileError from setuptools.extern.packaging.version import Version, InvalidVersion from setuptools.extern.packaging.specifiers import SpecifierSet +from setuptools._deprecation_warning import SetuptoolsDeprecationWarning from . import expand @@ -507,7 +508,7 @@ def parsers(self): parse_list, "The requires parameter is deprecated, please use " "install_requires for runtime dependencies.", - DeprecationWarning, + SetuptoolsDeprecationWarning, ), 'obsoletes': parse_list, 'classifiers': self._get_parser_compound(parse_file, parse_list), @@ -516,7 +517,7 @@ def parsers(self): exclude_files_parser('license_file'), "The license_file parameter is deprecated, " "use license_files instead.", - DeprecationWarning, + SetuptoolsDeprecationWarning, ), 'license_files': parse_list, 'description': parse_file, @@ -584,7 +585,12 @@ def parsers(self): 'scripts': parse_list, 'eager_resources': parse_list, 'dependency_links': parse_list, - 'namespace_packages': parse_list, + 'namespace_packages': self._deprecated_config_handler( + parse_list, + "The namespace_packages parameter is deprecated, " + "consider using implicit namespaces instead (PEP 420).", + SetuptoolsDeprecationWarning, + ), 'install_requires': parse_list_semicolon, 'setup_requires': parse_list_semicolon, 'tests_require': parse_list_semicolon, diff --git a/setuptools/dist.py b/setuptools/dist.py index 5507167d30..37021ac7a1 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -280,6 +280,11 @@ def check_nsp(dist, attr, value): nsp, parent, ) + msg = ( + "The namespace_packages parameter is deprecated, " + "consider using implicit namespaces instead (PEP 420).", + ) + warnings.warn(msg, SetuptoolsDeprecationWarning) def check_extras(dist, attr, value): diff --git a/setuptools/tests/config/test_apply_pyprojecttoml.py b/setuptools/tests/config/test_apply_pyprojecttoml.py index 28643f0caf..2194197f82 100644 --- a/setuptools/tests/config/test_apply_pyprojecttoml.py +++ b/setuptools/tests/config/test_apply_pyprojecttoml.py @@ -6,6 +6,7 @@ import io import re import tarfile +from inspect import cleandoc from pathlib import Path from unittest.mock import Mock from zipfile import ZipFile @@ -14,6 +15,7 @@ from ini2toml.api import Translator import setuptools # noqa ensure monkey patch to metadata +from setuptools._deprecation_warning import SetuptoolsDeprecationWarning from setuptools.dist import Distribution from setuptools.config import setupcfg, pyprojecttoml from setuptools.config import expand @@ -211,6 +213,21 @@ def test_license_and_license_files(tmp_path): assert dist.metadata.license == "LicenseRef-Proprietary\n" +class TestDeprecatedFields: + def test_namespace_packages(self, tmp_path): + pyproject = tmp_path / "pyproject.toml" + config = """ + [project] + name = "myproj" + version = "42" + [tool.setuptools] + namespace-packages = ["myproj.pkg"] + """ + pyproject.write_text(cleandoc(config), encoding="utf-8") + with pytest.warns(SetuptoolsDeprecationWarning, match="namespace_packages"): + pyprojecttoml.apply_configuration(makedist(tmp_path), pyproject) + + class TestPresetField: def pyproject(self, tmp_path, dynamic, extra_content=""): content = f"[project]\nname = 'proj'\ndynamic = {dynamic!r}\n" diff --git a/setuptools/tests/config/test_setupcfg.py b/setuptools/tests/config/test_setupcfg.py index 1f35f83630..904b1ef80a 100644 --- a/setuptools/tests/config/test_setupcfg.py +++ b/setuptools/tests/config/test_setupcfg.py @@ -7,6 +7,7 @@ import pytest from distutils.errors import DistutilsOptionError, DistutilsFileError +from setuptools._deprecation_warning import SetuptoolsDeprecationWarning from setuptools.dist import Distribution, _Distribution from setuptools.config.setupcfg import ConfigHandler, read_configuration from ..textwrap import DALS @@ -409,7 +410,7 @@ def test_deprecated_config_handlers(self, tmpdir): 'requires = some, requirement\n', ) - with pytest.deprecated_call(): + with pytest.warns(SetuptoolsDeprecationWarning, match="requires"): with get_dist(tmpdir) as dist: metadata = dist.metadata @@ -518,7 +519,8 @@ def test_basic(self, tmpdir): 'python_requires = >=1.0, !=2.8\n' 'py_modules = module1, module2\n', ) - with get_dist(tmpdir) as dist: + deprec = pytest.warns(SetuptoolsDeprecationWarning, match="namespace_packages") + with deprec, get_dist(tmpdir) as dist: assert dist.zip_safe assert dist.include_package_data assert dist.package_dir == {'': 'src', 'b': 'c'} @@ -572,7 +574,8 @@ def test_multiline(self, tmpdir): ' http://some.com/here/1\n' ' http://some.com/there/2\n', ) - with get_dist(tmpdir) as dist: + deprec = pytest.warns(SetuptoolsDeprecationWarning, match="namespace_packages") + with deprec, get_dist(tmpdir) as dist: assert dist.package_dir == {'': 'src', 'b': 'c'} assert dist.packages == ['pack_a', 'pack_b.subpack'] assert dist.namespace_packages == ['pack1', 'pack2']