diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2e0e55cf43..f214cb148d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -81,6 +81,9 @@ jobs: echo "PRE_BUILT_SETUPTOOLS_SDIST=$(ls dist/*.tar.gz)" >> $GITHUB_ENV echo "PRE_BUILT_SETUPTOOLS_WHEEL=$(ls dist/*.whl)" >> $GITHUB_ENV rm -rf setuptools.egg-info # Avoid interfering with the other tests + - name: Workaround for unreleased PyNaCl (pyca/pynacl#805) + if: contains(matrix.python, 'pypy') + run: echo "SETUPTOOLS_ENFORCE_DEPRECATION=0" >> $GITHUB_ENV - name: Install tox run: | python -m pip install tox diff --git a/newsfragments/4066.removal.1.rst b/newsfragments/4066.removal.1.rst new file mode 100644 index 0000000000..40cfd976ec --- /dev/null +++ b/newsfragments/4066.removal.1.rst @@ -0,0 +1,2 @@ +Configuring project ``version`` and ``egg_info.tag_*`` in such a way that +results in invalid version strings (according to :pep:`440`) is no longer permitted. diff --git a/newsfragments/4066.removal.2.rst b/newsfragments/4066.removal.2.rst new file mode 100644 index 0000000000..ff3c7c2885 --- /dev/null +++ b/newsfragments/4066.removal.2.rst @@ -0,0 +1,4 @@ +Removed deprecated ``egg_base`` option from ``dist_info``. +Note that the ``dist_info`` command is considered internal to the way +``setuptools`` build backend works and not intended for +public usage. diff --git a/newsfragments/4066.removal.3.rst b/newsfragments/4066.removal.3.rst new file mode 100644 index 0000000000..7d4048b785 --- /dev/null +++ b/newsfragments/4066.removal.3.rst @@ -0,0 +1,4 @@ +The parsing of the deprecated ``metadata.license_file`` and +``metadata.requires`` fields in ``setup.cfg`` is no longer supported. +Users are expected to move to ``metadata.license_files`` and +``options.install_requires`` (respectively). diff --git a/newsfragments/4066.removal.4.rst b/newsfragments/4066.removal.4.rst new file mode 100644 index 0000000000..d599450ac2 --- /dev/null +++ b/newsfragments/4066.removal.4.rst @@ -0,0 +1,2 @@ +Passing ``config_settings`` to ``setuptools.build_meta`` with +deprecated values for ``--global-option`` is no longer allowed. diff --git a/newsfragments/4066.removal.5.rst b/newsfragments/4066.removal.5.rst new file mode 100644 index 0000000000..99f77a0965 --- /dev/null +++ b/newsfragments/4066.removal.5.rst @@ -0,0 +1,4 @@ +Removed deprecated ``namespace-packages`` from ``pyproject.toml``. +Users are asked to use +:doc:`implicit namespace packages ` +(as defined in :pep:`420`). diff --git a/newsfragments/4066.removal.6.rst b/newsfragments/4066.removal.6.rst new file mode 100644 index 0000000000..350ea60eb6 --- /dev/null +++ b/newsfragments/4066.removal.6.rst @@ -0,0 +1,4 @@ +Added strict enforcement for ``project.dynamic`` in ``pyproject.toml``. +This removes the transitional ability of users configuring certain parameters +via ``setup.py`` without making the necessary changes to ``pyproject.toml`` +(as mandated by :pep:`612`). diff --git a/setuptools/_normalization.py b/setuptools/_normalization.py index 3e94e662ef..eee4fb7746 100644 --- a/setuptools/_normalization.py +++ b/setuptools/_normalization.py @@ -7,7 +7,6 @@ from typing import Union from .extern import packaging -from .warnings import SetuptoolsDeprecationWarning _Path = Union[str, Path] @@ -15,6 +14,7 @@ _VALID_NAME = re.compile(r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$", re.I) _UNSAFE_NAME_CHARS = re.compile(r"[^A-Z0-9.]+", re.I) _NON_ALPHANUMERIC = re.compile(r"[^A-Z0-9]+", re.I) +_PEP440_FALLBACK = re.compile(r"^v?(?P(?:[0-9]+!)?[0-9]+(?:\.[0-9]+)*)", re.I) def safe_identifier(name: str) -> str: @@ -42,6 +42,8 @@ def safe_name(component: str) -> str: def safe_version(version: str) -> str: """Convert an arbitrary string into a valid version string. + Can still raise an ``InvalidVersion`` exception. + To avoid exceptions use ``best_effort_version``. >>> safe_version("1988 12 25") '1988.12.25' >>> safe_version("v0.2.1") @@ -65,32 +67,35 @@ def safe_version(version: str) -> str: def best_effort_version(version: str) -> str: """Convert an arbitrary string into a version-like string. + Fallback when ``safe_version`` is not safe enough. >>> best_effort_version("v0.2 beta") '0.2b0' - - >>> import warnings - >>> warnings.simplefilter("ignore", category=SetuptoolsDeprecationWarning) >>> best_effort_version("ubuntu lts") - 'ubuntu.lts' + '0.dev0+sanitized.ubuntu.lts' + >>> best_effort_version("0.23ubuntu1") + '0.23.dev0+sanitized.ubuntu1' + >>> best_effort_version("0.23-") + '0.23.dev0+sanitized' + >>> best_effort_version("0.-_") + '0.dev0+sanitized' + >>> best_effort_version("42.+?1") + '42.dev0+sanitized.1' """ - # See pkg_resources.safe_version + # See pkg_resources._forgiving_version try: return safe_version(version) except packaging.version.InvalidVersion: - SetuptoolsDeprecationWarning.emit( - f"Invalid version: {version!r}.", - f""" - Version {version!r} is not valid according to PEP 440. - - Please make sure to specify a valid version for your package. - Also note that future releases of setuptools may halt the build process - if an invalid version is given. - """, - see_url="https://peps.python.org/pep-0440/", - due_date=(2023, 9, 26), # See setuptools/dist _validate_version - ) v = version.replace(' ', '.') - return safe_name(v) + match = _PEP440_FALLBACK.search(v) + if match: + safe = match["safe"] + rest = v[len(safe) :] + else: + safe = "0" + rest = version + safe_rest = _NON_ALPHANUMERIC.sub(".", rest).strip(".") + local = f"sanitized.{safe_rest}".strip(".") + return safe_version(f"{safe}.dev0+{local}") def safe_extra(extra: str) -> str: diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 9267cf312f..ff1d7eaee2 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -185,11 +185,6 @@ def _get_config(self, key: str, config_settings: _ConfigSettings) -> List[str]: opts = cfg.get(key) or [] return shlex.split(opts) if isinstance(opts, str) else opts - def _valid_global_options(self): - """Global options accepted by setuptools (e.g. quiet or verbose).""" - options = (opt[:2] for opt in setuptools.dist.Distribution.global_options) - return {flag for long_and_short in options for flag in long_and_short if flag} - def _global_args(self, config_settings: _ConfigSettings) -> Iterator[str]: """ Let the user specify ``verbose`` or ``quiet`` + escape hatch via @@ -220,9 +215,7 @@ def _global_args(self, config_settings: _ConfigSettings) -> Iterator[str]: level = str(cfg.get("quiet") or cfg.get("--quiet") or "1") yield ("-v" if level.lower() in falsey else "-q") - valid = self._valid_global_options() - args = self._get_config("--global-option", config_settings) - yield from (arg for arg in args if arg.strip("-") in valid) + yield from self._get_config("--global-option", config_settings) def __dist_info_args(self, config_settings: _ConfigSettings) -> Iterator[str]: """ @@ -284,33 +277,11 @@ def _arbitrary_args(self, config_settings: _ConfigSettings) -> Iterator[str]: ['foo'] >>> list(fn({'--build-option': 'foo bar'})) ['foo', 'bar'] - >>> warnings.simplefilter('error', SetuptoolsDeprecationWarning) - >>> list(fn({'--global-option': 'foo'})) # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - SetuptoolsDeprecationWarning: ...arguments given via `--global-option`... + >>> list(fn({'--global-option': 'foo'})) + [] """ - args = self._get_config("--global-option", config_settings) - global_opts = self._valid_global_options() - bad_args = [] - - for arg in args: - if arg.strip("-") not in global_opts: - bad_args.append(arg) - yield arg - yield from self._get_config("--build-option", config_settings) - if bad_args: - SetuptoolsDeprecationWarning.emit( - "Incompatible `config_settings` passed to build backend.", - f""" - The arguments {bad_args!r} were given via `--global-option`. - Please use `--build-option` instead, - `--global-option` is reserved for flags like `--verbose` or `--quiet`. - """, - due_date=(2023, 9, 26), # Warning introduced in v64.0.1, 11/Aug/2022. - ) - class _BuildMetaBackend(_ConfigSettingsTranslator): def _get_build_requires(self, config_settings, requirements): diff --git a/setuptools/command/dist_info.py b/setuptools/command/dist_info.py index 9df625cee7..5ef322168c 100644 --- a/setuptools/command/dist_info.py +++ b/setuptools/command/dist_info.py @@ -12,7 +12,6 @@ from pathlib import Path from .. import _normalization -from ..warnings import SetuptoolsDeprecationWarning class dist_info(Command): @@ -24,13 +23,6 @@ class dist_info(Command): description = "DO NOT CALL DIRECTLY, INTERNAL ONLY: create .dist-info directory" user_options = [ - ( - 'egg-base=', - 'e', - "directory containing .egg-info directories" - " (default: top of the source tree)" - " DEPRECATED: use --output-dir.", - ), ( 'output-dir=', 'o', @@ -47,7 +39,6 @@ class dist_info(Command): negative_opt = {'no-date': 'tag-date'} def initialize_options(self): - self.egg_base = None self.output_dir = None self.name = None self.dist_info_dir = None @@ -56,13 +47,6 @@ def initialize_options(self): self.keep_egg_info = False def finalize_options(self): - if self.egg_base: - msg = "--egg-base is deprecated for dist_info command. Use --output-dir." - SetuptoolsDeprecationWarning.emit(msg, due_date=(2023, 9, 26)) - # This command is internal to setuptools, therefore it should be safe - # to remove the deprecated support soon. - self.output_dir = self.egg_base or self.output_dir - dist = self.distribution project_dir = dist.src_root or os.curdir self.output_dir = Path(self.output_dir or project_dir) diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index a5199deb33..7c7f57aaf8 100644 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -127,7 +127,7 @@ def name(self): def tagged_version(self): tagged = self._maybe_tag(self.distribution.get_version()) - return _normalization.best_effort_version(tagged) + return _normalization.safe_version(tagged) def _maybe_tag(self, version): """ @@ -148,7 +148,10 @@ def _already_tagged(self, version: str) -> bool: def _safe_tags(self) -> str: # To implement this we can rely on `safe_version` pretending to be version 0 # followed by tags. Then we simply discard the starting 0 (fake version number) - return _normalization.best_effort_version(f"0{self.vtags}")[1:] + try: + return _normalization.safe_version(f"0{self.vtags}")[1:] + except packaging.version.InvalidVersion: + return _normalization.safe_name(self.vtags.replace(' ', '.')) def tags(self) -> str: version = '' diff --git a/setuptools/config/_apply_pyprojecttoml.py b/setuptools/config/_apply_pyprojecttoml.py index 4489d22437..80318d5d0b 100644 --- a/setuptools/config/_apply_pyprojecttoml.py +++ b/setuptools/config/_apply_pyprojecttoml.py @@ -12,6 +12,7 @@ from collections.abc import Mapping from email.headerregistry import Address from functools import partial, reduce +from inspect import cleandoc from itertools import chain from types import MappingProxyType from typing import ( @@ -28,7 +29,8 @@ cast, ) -from ..warnings import SetuptoolsWarning, SetuptoolsDeprecationWarning +from ..errors import RemovedConfigError +from ..warnings import SetuptoolsWarning if TYPE_CHECKING: from setuptools._importlib import metadata # noqa @@ -90,12 +92,13 @@ 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, kwargs = TOOL_TABLE_DEPRECATIONS[norm_key] - msg = f"The parameter `{norm_key}` is deprecated, {suggestion}" - SetuptoolsDeprecationWarning.emit( - "Deprecated config", msg, **kwargs # type: ignore - ) + if norm_key in TOOL_TABLE_REMOVALS: + suggestion = cleandoc(TOOL_TABLE_REMOVALS[norm_key]) + msg = f""" + The parameter `tool.setuptools.{field}` was long deprecated + and has been removed from `pyproject.toml`. + """ + raise RemovedConfigError("\n".join([cleandoc(msg), suggestion])) norm_key = TOOL_TABLE_RENAMES.get(norm_key, norm_key) _set_config(dist, norm_key, value) @@ -105,13 +108,13 @@ def _apply_tool_table(dist: "Distribution", config: dict, filename: _Path): def _handle_missing_dynamic(dist: "Distribution", project_table: dict): """Be temporarily forgiving with ``dynamic`` fields not listed in ``dynamic``""" - # TODO: Set fields back to `None` once the feature stabilizes dynamic = set(project_table.get("dynamic", [])) for field, getter in _PREVIOUSLY_DEFINED.items(): if not (field in project_table or field in dynamic): value = getter(dist) if value: - _WouldIgnoreField.emit(field=field, value=value) + _MissingDynamic.emit(field=field, value=value) + project_table[field] = _RESET_PREVIOUSLY_DEFINED.get(field) def json_compatible_key(key: str) -> str: @@ -226,14 +229,18 @@ def _unify_entry_points(project_table: dict): renaming = {"scripts": "console_scripts", "gui_scripts": "gui_scripts"} for key, value in list(project.items()): # eager to allow modifications norm_key = json_compatible_key(key) - if norm_key in renaming and value: + if norm_key in renaming: + # Don't skip even if value is empty (reason: reset missing `dynamic`) entry_points[renaming[norm_key]] = project.pop(key) if entry_points: project["entry-points"] = { name: [f"{k} = {v}" for k, v in group.items()] for name, group in entry_points.items() + if group # now we can skip empty groups } + # Sometimes this will set `project["entry-points"] = {}`, and that is + # intentional (for reseting configurations that are missing `dynamic`). def _copy_command_options(pyproject: dict, dist: "Distribution", filename: _Path): @@ -353,11 +360,11 @@ def _acessor(obj): } TOOL_TABLE_RENAMES = {"script_files": "scripts"} -TOOL_TABLE_DEPRECATIONS = { - "namespace_packages": ( - "consider using implicit namespaces instead (PEP 420).", - {"due_date": (2023, 10, 30)}, # warning introduced in May 2022 - ) +TOOL_TABLE_REMOVALS = { + "namespace_packages": """ + Please migrate to implicit native namespaces instead. + See https://packaging.python.org/en/latest/guides/packaging-namespace-packages/. + """, } SETUPTOOLS_PATCHES = { @@ -388,14 +395,27 @@ def _acessor(obj): } -class _WouldIgnoreField(SetuptoolsDeprecationWarning): - _SUMMARY = "`{field}` defined outside of `pyproject.toml` would be ignored." +_RESET_PREVIOUSLY_DEFINED: dict = { + # Fix improper setting: given in `setup.py`, but not listed in `dynamic` + # dict: pyproject name => value to which reset + "license": {}, + "authors": [], + "maintainers": [], + "keywords": [], + "classifiers": [], + "urls": {}, + "entry-points": {}, + "scripts": {}, + "gui-scripts": {}, + "dependencies": [], + "optional-dependencies": [], +} - _DETAILS = """ - ########################################################################## - # configuration would be ignored/result in error due to `pyproject.toml` # - ########################################################################## +class _MissingDynamic(SetuptoolsWarning): + _SUMMARY = "`{field}` defined outside of `pyproject.toml` is ignored." + + _DETAILS = """ The following seems to be defined outside of `pyproject.toml`: `{field} = {value!r}` @@ -405,12 +425,14 @@ class _WouldIgnoreField(SetuptoolsDeprecationWarning): https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ - For the time being, `setuptools` will still consider the given value (as a - **transitional** measure), but please note that future releases of setuptools will - follow strictly the standard. - - To prevent this warning, you can list `{field}` under `dynamic` or alternatively + To prevent this problem, you can list `{field}` under `dynamic` or alternatively remove the `[project]` table from your file and rely entirely on other means of configuration. """ - _DUE_DATE = (2023, 10, 30) # Initially introduced in 27 May 2022 + # TODO: Consider removing this check in the future? + # There is a trade-off here between improving "debug-ability" and the cost + # of running/testing/maintaining these unnecessary checks... + + @classmethod + def details(cls, field: str, value: Any) -> str: + return cls._DETAILS.format(field=field, value=value) diff --git a/setuptools/config/pyprojecttoml.py b/setuptools/config/pyprojecttoml.py index 93dbd9f559..379ef222f9 100644 --- a/setuptools/config/pyprojecttoml.py +++ b/setuptools/config/pyprojecttoml.py @@ -14,10 +14,10 @@ from functools import partial from typing import TYPE_CHECKING, Callable, Dict, Mapping, Optional, Set, Union -from ..errors import FileError, OptionError +from ..errors import FileError, InvalidConfigError from ..warnings import SetuptoolsWarning from . import expand as _expand -from ._apply_pyprojecttoml import _PREVIOUSLY_DEFINED, _WouldIgnoreField +from ._apply_pyprojecttoml import _PREVIOUSLY_DEFINED, _MissingDynamic from ._apply_pyprojecttoml import apply as _apply if TYPE_CHECKING: @@ -265,7 +265,7 @@ def _ensure_previously_set(self, dist: "Distribution", field: str): "Some dynamic fields need to be specified via `tool.setuptools.dynamic`" "\nothers must be specified via the equivalent attribute in `setup.py`." ) - raise OptionError(msg) + raise InvalidConfigError(msg) def _expand_directive( self, specifier: str, directive, package_dir: Mapping[str, str] @@ -330,9 +330,7 @@ def _set_scripts(field: str, group: str): if group in groups: value = groups.pop(group) if field not in self.dynamic: - _WouldIgnoreField.emit(field=field, value=value) - # TODO: Don't set field when support for pyproject.toml stabilizes - # instead raise an error as specified in PEP 621 + raise InvalidConfigError(_MissingDynamic.details(field, value)) expanded[field] = value _set_scripts("scripts", "console_scripts") diff --git a/setuptools/config/setupcfg.py b/setuptools/config/setupcfg.py index bb35559069..1a0e4154b9 100644 --- a/setuptools/config/setupcfg.py +++ b/setuptools/config/setupcfg.py @@ -556,23 +556,9 @@ def parsers(self): 'platforms': parse_list, 'keywords': parse_list, 'provides': parse_list, - 'requires': self._deprecated_config_handler( - parse_list, - "The requires parameter is deprecated, please use " - "install_requires for runtime dependencies.", - due_date=(2023, 10, 30), - # Warning introduced in 27 Oct 2018 - ), 'obsoletes': parse_list, 'classifiers': self._get_parser_compound(parse_file, parse_list), 'license': exclude_files_parser('license'), - 'license_file': self._deprecated_config_handler( - exclude_files_parser('license_file'), - "The license_file parameter is deprecated, " - "use license_files instead.", - due_date=(2023, 10, 30), - # Warning introduced in 23 May 2021 - ), 'license_files': parse_list, 'description': parse_file, 'long_description': parse_file, diff --git a/setuptools/dist.py b/setuptools/dist.py index 6e31bd7c27..222e8a7623 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -26,7 +26,7 @@ from .extern.ordered_set import OrderedSet from .extern.packaging.markers import InvalidMarker, Marker from .extern.packaging.specifiers import InvalidSpecifier, SpecifierSet -from .extern.packaging.version import InvalidVersion, Version +from .extern.packaging.version import Version from . import _entry_points from . import _normalization @@ -311,9 +311,7 @@ def __init__(self, attrs=None): self._set_metadata_defaults(attrs) - self.metadata.version = self._normalize_version( - self._validate_version(self.metadata.version) - ) + self.metadata.version = self._normalize_version(self.metadata.version) self._finalize_requires() def _validate_metadata(self): @@ -343,7 +341,10 @@ def _set_metadata_defaults(self, attrs): def _normalize_version(version): from . import sic - if isinstance(version, sic) or version is None: + if isinstance(version, numbers.Number): + # Some people apparently take "version number" too literally :) + version = str(version) + elif isinstance(version, sic) or version is None: return version normalized = str(Version(version)) @@ -352,33 +353,6 @@ def _normalize_version(version): return normalized return version - @staticmethod - def _validate_version(version): - if isinstance(version, numbers.Number): - # Some people apparently take "version number" too literally :) - version = str(version) - - if version is not None: - try: - Version(version) - except (InvalidVersion, TypeError): - from . import sic - - SetuptoolsDeprecationWarning.emit( - f"Invalid version: {version!r}.", - """ - The version specified is not a valid version according to PEP 440. - This may not work as expected with newer versions of - setuptools, pip, and PyPI. - """, - see_url="https://peps.python.org/pep-0440/", - due_date=(2023, 9, 26), - # Warning initially introduced in 26 Sept 2014 - # pypa/packaging already removed legacy versions. - ) - return sic(version) - return version - def _finalize_requires(self): """ Set `metadata.python_requires` and fix environment markers @@ -550,7 +524,7 @@ def warn_dash_deprecation(self, opt, section): versions. Please use the underscore name {underscore_opt!r} instead. """, see_docs="userguide/declarative_config.html", - due_date=(2023, 9, 26), + due_date=(2024, 9, 26), # Warning initially introduced in 3 Mar 2021 ) return underscore_opt @@ -574,7 +548,7 @@ def make_option_lowercase(self, opt, section): future versions. Please use lowercase {lowercase_opt!r} instead. """, see_docs="userguide/declarative_config.html", - due_date=(2023, 9, 26), + due_date=(2024, 9, 26), # Warning initially introduced in 6 Mar 2021 ) return lowercase_opt diff --git a/setuptools/errors.py b/setuptools/errors.py index ec7fb3b6c4..67a5a1df10 100644 --- a/setuptools/errors.py +++ b/setuptools/errors.py @@ -29,6 +29,14 @@ BaseError = _distutils_errors.DistutilsError +class InvalidConfigError(OptionError): + """Error used for invalid configurations.""" + + +class RemovedConfigError(OptionError): + """Error used for configurations that were deprecated and removed.""" + + class RemovedCommandError(BaseError, RuntimeError): """Error used for commands that have been removed in setuptools. diff --git a/setuptools/tests/config/test_apply_pyprojecttoml.py b/setuptools/tests/config/test_apply_pyprojecttoml.py index 294947a00a..7905aa9ab6 100644 --- a/setuptools/tests/config/test_apply_pyprojecttoml.py +++ b/setuptools/tests/config/test_apply_pyprojecttoml.py @@ -21,9 +21,9 @@ from setuptools.dist import Distribution from setuptools.config import setupcfg, pyprojecttoml from setuptools.config import expand -from setuptools.config._apply_pyprojecttoml import _WouldIgnoreField, _some_attrgetter +from setuptools.config._apply_pyprojecttoml import _MissingDynamic, _some_attrgetter from setuptools.command.egg_info import write_requirements -from setuptools.warnings import SetuptoolsDeprecationWarning +from setuptools.errors import RemovedConfigError from .downloads import retrieve_file, urls_from_file @@ -316,7 +316,7 @@ def test_namespace_packages(self, tmp_path): namespace-packages = ["myproj.pkg"] """ pyproject.write_text(cleandoc(config), encoding="utf-8") - with pytest.warns(SetuptoolsDeprecationWarning, match="namespace_packages"): + with pytest.raises(RemovedConfigError, match="namespace-packages"): pyprojecttoml.apply_configuration(makedist(tmp_path), pyproject) @@ -339,18 +339,15 @@ def pyproject(self, tmp_path, dynamic, extra_content=""): ], ) def test_not_listed_in_dynamic(self, tmp_path, attr, field, value): - """For the time being we just warn if the user pre-set values (e.g. via - ``setup.py``) but do not include them in ``dynamic``. - """ + """Setuptools cannot set a field if not listed in ``dynamic``""" pyproject = self.pyproject(tmp_path, []) dist = makedist(tmp_path, **{attr: value}) msg = re.compile(f"defined outside of `pyproject.toml`:.*{field}", re.S) - with pytest.warns(_WouldIgnoreField, match=msg): + with pytest.warns(_MissingDynamic, match=msg): dist = pyprojecttoml.apply_configuration(dist, pyproject) - # TODO: Once support for pyproject.toml config stabilizes attr should be None dist_value = _some_attrgetter(f"metadata.{attr}", attr)(dist) - assert dist_value == value + assert not dist_value @pytest.mark.parametrize( "attr, field, value", diff --git a/setuptools/tests/config/test_pyprojecttoml.py b/setuptools/tests/config/test_pyprojecttoml.py index 81ec949a42..318885a6bd 100644 --- a/setuptools/tests/config/test_pyprojecttoml.py +++ b/setuptools/tests/config/test_pyprojecttoml.py @@ -6,7 +6,6 @@ import tomli_w from path import Path as _Path -from setuptools.config._apply_pyprojecttoml import _WouldIgnoreField from setuptools.config.pyprojecttoml import ( read_configuration, expand_configuration, @@ -200,14 +199,8 @@ def test_scripts_not_listed_in_dynamic(self, tmp_path, missing_dynamic): dynamic = {"scripts", "gui-scripts", "entry-points"} - {missing_dynamic} msg = f"defined outside of `pyproject.toml`:.*{missing_dynamic}" - with pytest.warns(_WouldIgnoreField, match=re.compile(msg, re.S)): - expanded = expand_configuration(self.pyproject(dynamic), tmp_path) - - expanded_project = expanded["project"] - assert dynamic < set(expanded_project) - assert len(expanded_project["entry-points"]) == 1 - # TODO: Test the following when pyproject.toml support stabilizes: - # >>> assert missing_dynamic not in expanded_project + with pytest.raises(OptionError, match=re.compile(msg, re.S)): + expand_configuration(self.pyproject(dynamic), tmp_path) class TestClassifiers: diff --git a/setuptools/tests/config/test_setupcfg.py b/setuptools/tests/config/test_setupcfg.py index fa16728ea7..23fc0d0b47 100644 --- a/setuptools/tests/config/test_setupcfg.py +++ b/setuptools/tests/config/test_setupcfg.py @@ -388,23 +388,6 @@ def test_classifiers(self, tmpdir): with get_dist(tmpdir) as dist: assert set(dist.metadata.classifiers) == expected - def test_deprecated_config_handlers(self, tmpdir): - fake_env( - tmpdir, - '[metadata]\n' - 'version = 10.1.1\n' - 'description = Some description\n' - 'requires = some, requirement\n', - ) - - with pytest.warns(SetuptoolsDeprecationWarning, match="requires"): - with get_dist(tmpdir) as dist: - metadata = dist.metadata - - assert metadata.version == '10.1.1' - assert metadata.description == 'Some description' - assert metadata.requires == ['some', 'requirement'] - def test_interpolation(self, tmpdir): fake_env(tmpdir, '[metadata]\n' 'description = %(message)s\n') with pytest.raises(configparser.InterpolationMissingOptionError): diff --git a/setuptools/tests/test_bdist_deprecations.py b/setuptools/tests/test_bdist_deprecations.py index 1b69c41858..61f4e9a4cb 100644 --- a/setuptools/tests/test_bdist_deprecations.py +++ b/setuptools/tests/test_bdist_deprecations.py @@ -10,6 +10,7 @@ @pytest.mark.skipif(sys.platform == 'win32', reason='non-Windows only') +@pytest.mark.xfail(reason="bdist_rpm is long deprecated, should we remove it? #1988") @mock.patch('distutils.command.bdist_rpm.bdist_rpm') def test_bdist_rpm_warning(distutils_cmd, tmpdir_cwd): dist = Distribution( diff --git a/setuptools/tests/test_build_meta.py b/setuptools/tests/test_build_meta.py index f36119eb9c..22e3b4303a 100644 --- a/setuptools/tests/test_build_meta.py +++ b/setuptools/tests/test_build_meta.py @@ -706,25 +706,6 @@ def _assert_link_tree(self, parent_dir): for file in files: assert file.is_symlink() or os.stat(file).st_nlink > 0 - @pytest.mark.filterwarnings("ignore::setuptools.SetuptoolsDeprecationWarning") - # Since the backend is running via a process pool, in some operating systems - # we may have problems to make assertions based on warnings/stdout/stderr... - # So the best is to ignore them for the time being. - def test_editable_with_global_option_still_works(self, tmpdir_cwd): - """The usage of --global-option is now discouraged in favour of --build-option. - This is required to make more sense of the provided scape hatch and align with - previous pip behaviour. See pypa/setuptools#1928. - """ - path.build({**self._simple_pyproject_example, '_meta': {}}) - build_backend = self.get_build_backend() - assert not Path("build").exists() - - cfg = {"--global-option": ["--mode", "strict"]} - build_backend.prepare_metadata_for_build_editable("_meta", cfg) - build_backend.build_editable("temp", cfg, "_meta") - - self._assert_link_tree(next(Path("build").glob("__editable__.*"))) - def test_editable_without_config_settings(self, tmpdir_cwd): """ Sanity check to ensure tests with --mode=strict are different from the ones @@ -920,7 +901,8 @@ def test_build_with_empty_setuppy(self, build_backend, build_hook): files = {'setup.py': ''} path.build(files) - with pytest.raises(ValueError, match=re.escape('No distribution was found.')): + msg = re.escape('No distribution was found.') + with pytest.raises(ValueError, match=msg): getattr(build_backend, build_hook)("temp") diff --git a/tox.ini b/tox.ini index 1ce665bdcd..e352869f39 100644 --- a/tox.ini +++ b/tox.ini @@ -6,8 +6,7 @@ deps = # ^-- use dev version while we wait for the new release setenv = PYTHONWARNDEFAULTENCODING = 1 - SETUPTOOLS_ENFORCE_DEPRECATION = 0 - # ^-- Temporarily disable, until overdue deprecations are handled + SETUPTOOLS_ENFORCE_DEPRECATION = {env:SETUPTOOLS_ENFORCE_DEPRECATION:1} commands = pytest {posargs} usedevelop = True @@ -15,6 +14,7 @@ extras = testing pass_env = SETUPTOOLS_USE_DISTUTILS + SETUPTOOLS_ENFORCE_DEPRECATION PRE_BUILT_SETUPTOOLS_WHEEL PRE_BUILT_SETUPTOOLS_SDIST TIMEOUT_BACKEND_TEST # timeout (in seconds) for test_build_meta