From 14a525047f6b1dcf0dd0687299afe663fa6f0ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Sat, 27 Jan 2024 18:17:02 +0100 Subject: [PATCH] deprecate scripts depending on extras (#690) --- src/poetry/core/factory.py | 13 +++++++++++-- src/poetry/core/masonry/builders/builder.py | 12 +++++++++++- .../fixtures/licenses_and_copying/pyproject.toml | 1 - tests/masonry/builders/test_builder.py | 3 ++- tests/masonry/builders/test_complete.py | 3 ++- tests/masonry/builders/test_sdist.py | 2 ++ tests/masonry/builders/test_wheel.py | 2 ++ tests/masonry/test_api.py | 7 +++++++ tests/masonry/test_builder.py | 2 ++ tests/test_factory.py | 11 +++++++++-- 10 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/poetry/core/factory.py b/src/poetry/core/factory.py index e085b0f01..bcf81e76a 100644 --- a/src/poetry/core/factory.py +++ b/src/poetry/core/factory.py @@ -464,11 +464,20 @@ def validate( continue extras = script.get("extras", []) + if extras: + result["warnings"].append( + f'The script "{name}" depends on an extra. Scripts' + " depending on extras are deprecated and support for them" + " will be removed in a future version of" + " poetry/poetry-core. See" + " https://packaging.python.org/en/latest/specifications/entry-points/#data-model" + " for details." + ) for extra in extras: if extra not in config_extras: result["errors"].append( - f'Script "{name}" requires extra "{extra}" which is not' - " defined." + f'The script "{name}" requires extra "{extra}"' + " which is not defined." ) # Checking types of all readme files (must match) diff --git a/src/poetry/core/masonry/builders/builder.py b/src/poetry/core/masonry/builders/builder.py index a07d06e09..54847309b 100644 --- a/src/poetry/core/masonry/builders/builder.py +++ b/src/poetry/core/masonry/builders/builder.py @@ -311,7 +311,7 @@ def convert_entry_points(self) -> dict[str, list[str]]: f"Use of callable in script specification ({name}) is" " deprecated. Use reference instead.", DeprecationWarning, - stacklevel=2, + stacklevel=1, ) specification = { "reference": specification["callable"], @@ -322,6 +322,16 @@ def convert_entry_points(self) -> dict[str, list[str]]: continue extras = specification.get("extras", []) + if extras: + warnings.warn( + f'The script "{name}" depends on an extra. Scripts depending on' + " extras are deprecated and support for them will be removed in a" + " future version of poetry/poetry-core. See" + " https://packaging.python.org/en/latest/specifications/entry-points/#data-model" + " for details.", + DeprecationWarning, + stacklevel=1, + ) extras = f"[{', '.join(extras)}]" if extras else "" reference = specification.get("reference") diff --git a/tests/masonry/builders/fixtures/licenses_and_copying/pyproject.toml b/tests/masonry/builders/fixtures/licenses_and_copying/pyproject.toml index 70880bcda..bb1e5f528 100644 --- a/tests/masonry/builders/fixtures/licenses_and_copying/pyproject.toml +++ b/tests/masonry/builders/fixtures/licenses_and_copying/pyproject.toml @@ -43,7 +43,6 @@ time = ["pendulum"] [tool.poetry.scripts] my-script = "my_package:main" my-2nd-script = "my_package:main2" -extra-script = {reference = "my_package.extra:main", extras = ["time"], type = "console"} [tool.poetry.urls] "Issue Tracker" = "https://github.com/python-poetry/poetry/issues" diff --git a/tests/masonry/builders/test_builder.py b/tests/masonry/builders/test_builder.py index c9502d2c3..779bfd14b 100644 --- a/tests/masonry/builders/test_builder.py +++ b/tests/masonry/builders/test_builder.py @@ -262,7 +262,8 @@ def test_entrypoint_scripts_legacy_warns(fixture: str) -> None: ), ], ) -@pytest.mark.filterwarnings("ignore::DeprecationWarning") +@pytest.mark.filterwarnings("ignore:.* callable .* deprecated:DeprecationWarning") +@pytest.mark.filterwarnings("ignore:.* script .* extra:DeprecationWarning") def test_builder_convert_entry_points( fixture: str, result: dict[str, list[str]] ) -> None: diff --git a/tests/masonry/builders/test_complete.py b/tests/masonry/builders/test_complete.py index 1b518647e..31a68c460 100644 --- a/tests/masonry/builders/test_complete.py +++ b/tests/masonry/builders/test_complete.py @@ -111,7 +111,8 @@ def test_complete(no_vcs: bool) -> None: module_path = temporary_dir builder = Builder(Factory().create_poetry(module_path)) - builder.build(fmt="all") + with pytest.warns(DeprecationWarning, match=".* script .* extra"): + builder.build(fmt="all") whl = module_path / "dist" / "my_package-1.2.3-py3-none-any.whl" diff --git a/tests/masonry/builders/test_sdist.py b/tests/masonry/builders/test_sdist.py index dc3591541..416f08661 100644 --- a/tests/masonry/builders/test_sdist.py +++ b/tests/masonry/builders/test_sdist.py @@ -116,6 +116,7 @@ def test_convert_dependencies() -> None: assert result == (main, extras) +@pytest.mark.filterwarnings("ignore:.* script .* extra:DeprecationWarning") def test_make_setup() -> None: poetry = Factory().create_poetry(project("complete")) @@ -298,6 +299,7 @@ def test_sdist_reproducibility() -> None: assert len(hashes) == 1 +@pytest.mark.filterwarnings("ignore:.* script .* extra:DeprecationWarning") def test_setup_py_context() -> None: poetry = Factory().create_poetry(project("complete")) diff --git a/tests/masonry/builders/test_wheel.py b/tests/masonry/builders/test_wheel.py index f686747af..32f13fbce 100644 --- a/tests/masonry/builders/test_wheel.py +++ b/tests/masonry/builders/test_wheel.py @@ -70,6 +70,7 @@ def test_wheel_module() -> None: assert "module1.py" in z.namelist() +@pytest.mark.filterwarnings("ignore:.* script .* extra:DeprecationWarning") def test_wheel_package() -> None: module_path = fixtures_dir / "complete" WheelBuilder.make(Factory().create_poetry(module_path)) @@ -208,6 +209,7 @@ def test_wheel_build_script_creates_package() -> None: shutil.rmtree(module_path / "my_package") +@pytest.mark.filterwarnings("ignore:.* script .* extra:DeprecationWarning") def test_dist_info_file_permissions() -> None: module_path = fixtures_dir / "complete" WheelBuilder.make(Factory().create_poetry(module_path)) diff --git a/tests/masonry/test_api.py b/tests/masonry/test_api.py index c0d124df3..04024ba69 100644 --- a/tests/masonry/test_api.py +++ b/tests/masonry/test_api.py @@ -8,6 +8,8 @@ from typing import TYPE_CHECKING from typing import Iterator +import pytest + from poetry.core import __version__ from poetry.core.masonry import api from poetry.core.utils.helpers import temporary_directory @@ -44,6 +46,7 @@ def test_get_requires_for_build_sdist() -> None: assert api.get_requires_for_build_sdist() == expected +@pytest.mark.filterwarnings("ignore:.* script .* extra:DeprecationWarning") def test_build_wheel() -> None: with temporary_directory() as tmp_dir, cwd(os.path.join(fixtures, "complete")): filename = api.build_wheel(tmp_dir) @@ -132,6 +135,7 @@ def test_build_sdist_with_bad_path_dep_succeeds(caplog: LogCaptureFixture) -> No assert "does not exist" in record.message +@pytest.mark.filterwarnings("ignore:.* script .* extra:DeprecationWarning") def test_prepare_metadata_for_build_wheel() -> None: entry_points = """\ [console_scripts] @@ -224,6 +228,7 @@ def test_prepare_metadata_for_build_wheel_with_bad_path_dep_succeeds( assert "does not exist" in record.message +@pytest.mark.filterwarnings("ignore:.* script .* extra:DeprecationWarning") def test_build_editable_wheel() -> None: pkg_dir = Path(fixtures) / "complete" @@ -244,6 +249,7 @@ def test_build_editable_wheel() -> None: assert pkg_dir.as_posix() == z.read("my_package.pth").decode().strip() +@pytest.mark.filterwarnings("ignore:.* script .* extra:DeprecationWarning") def test_build_wheel_with_metadata_directory() -> None: pkg_dir = Path(fixtures) / "complete" @@ -271,6 +277,7 @@ def test_build_wheel_with_metadata_directory() -> None: assert f"{metadata_directory}/CUSTOM" in namelist +@pytest.mark.filterwarnings("ignore:.* script .* extra:DeprecationWarning") def test_build_editable_wheel_with_metadata_directory() -> None: pkg_dir = Path(fixtures) / "complete" diff --git a/tests/masonry/test_builder.py b/tests/masonry/test_builder.py index e6495f9dd..42cd5f495 100644 --- a/tests/masonry/test_builder.py +++ b/tests/masonry/test_builder.py @@ -61,6 +61,7 @@ def test_builder_raises_error_in_non_package_mode(tmp_path: Path, format: str) - assert str(err.value) == "Building a package is not possible in non-package mode." +@pytest.mark.filterwarnings("ignore:.* script .* extra:DeprecationWarning") @pytest.mark.parametrize("format", ["sdist", "wheel", "all"]) def test_builder_creates_places_built_files_in_specified_directory( tmp_path: Path, format: str @@ -72,6 +73,7 @@ def test_builder_creates_places_built_files_in_specified_directory( assert all(archive.exists() for archive in build_artifacts) +@pytest.mark.filterwarnings("ignore:.* script .* extra:DeprecationWarning") @pytest.mark.parametrize("format", ["sdist", "wheel", "all"]) def test_builder_creates_packages_in_dist_directory_if_no_output_is_specified( format: str, diff --git a/tests/test_factory.py b/tests/test_factory.py index 6a93ed61a..193f8a72c 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -308,8 +308,8 @@ def test_validate_strict_fails_strict_and_non_strict() -> None: '"some-extras" in main dependencies.' ), ( - 'Script "a_script_with_unknown_extra" requires extra "foo" which is not' - " defined." + 'The script "a_script_with_unknown_extra" requires extra "foo" which is' + " not defined." ), ( "Declared README files must be of same type: found text/markdown," @@ -325,6 +325,13 @@ def test_validate_strict_fails_strict_and_non_strict() -> None: 'The "pathlib2" dependency specifies the "allows-prereleases" property,' ' which is deprecated. Use "allow-prereleases" instead.' ), + ( + 'The script "a_script_with_unknown_extra" depends on an extra. Scripts' + " depending on extras are deprecated and support for them will be" + " removed in a future version of poetry/poetry-core. See" + " https://packaging.python.org/en/latest/specifications/entry-points/#data-model" + " for details." + ), ], }