Skip to content

Conversation

@radoering
Copy link
Member

@radoering radoering commented Dec 14, 2025

Almost one year and three minor versions after Poetry 2.0, I think we should make the warnings for the deprecated tool.poetry fields more prominent. Currently, they are only returned in strict validation mode, i.e. when running poetry check. With this PR, they are always returned, i.e. they are printed when any Poetry command is run.

I think this makes sense if we ever want to remove the deprecated fields - even in a major release.

Summary by Sourcery

Always validate and surface deprecated [tool.poetry] field warnings, not only in strict mode, and adjust validation behavior and tests accordingly.

Bug Fixes:

  • Ensure validation errors and warnings correctly include issues from both [project] and [tool.poetry] sections in non-strict and strict modes.

Enhancements:

  • Run legacy-versus-[project] configuration validation in all validation modes so deprecation warnings for [tool.poetry] fields are always reported.
  • Refine validation failure expectations to distinguish legacy [tool.poetry] errors from new-style [project] errors.

Tests:

  • Update and extend validation tests to cover warnings in both strict and non-strict modes and to assert combined error/warning outputs.
  • Adjust and add TOML fixtures to use [project] metadata where appropriate and to exercise deprecation and error scenarios for both legacy and new-style configuration.

@sourcery-ai
Copy link

sourcery-ai bot commented Dec 14, 2025

Reviewer's Guide

This PR changes validation so that deprecation warnings for legacy [tool.poetry] fields are always emitted (not only in strict mode), updates tests/fixtures to reflect the new behavior and modern [project] usage, and slightly refactors validation ordering in Factory.validate to always run legacy-vs-project checks.

Sequence diagram for validation flow with always-on legacy field warnings

sequenceDiagram
    actor User
    participant CLI as PoetryCLI
    participant Factory as Factory
    participant ValidatorResult as ValidationResult

    User->>CLI: run_command()
    CLI->>Factory: validate(toml_data, strict)
    Factory->>ValidatorResult: create_or_init(result)
    Factory->>Factory: _validate_dependency_groups(toml_data, result)
    Factory->>Factory: _validate_legacy_vs_project(toml_data, result)
    alt strict is True
        Factory->>Factory: _validate_project(project, result)
        Factory->>Factory: _validate_strict(config, result)
    end
    Factory-->>CLI: result (with legacy field warnings if present)
    CLI-->>User: display warnings and errors
Loading

Class diagram for Factory validation and legacy vs project checks

classDiagram
    class Factory {
        +validate(toml_data, strict) ValidationResult
        +_validate_dependency_groups(toml_data, result) None
        +_validate_legacy_vs_project(toml_data, result) None
        +_validate_project(project, result) None
        +_validate_strict(config, result) None
    }

    class ValidationResult {
        +errors list
        +warnings list
        +add_error(message) None
        +add_warning(message) None
    }

    Factory ..> ValidationResult : uses
    Factory ..> ValidationResult : populate_errors_and_warnings
    Factory ..> Factory : calls_validate_dependency_groups
    Factory ..> Factory : calls_validate_legacy_vs_project
    Factory ..> Factory : calls_validate_project_in_strict_mode
    Factory ..> Factory : calls_validate_strict_in_strict_mode
Loading

File-Level Changes

Change Details Files
Always emit legacy [tool.poetry] deprecation warnings regardless of strict mode.
  • Move the _validate_legacy_vs_project call in Factory.validate to run before the strict-mode-only block so its warnings are always collected.
  • Keep strict validation (project schema checks and _validate_strict) behavior unchanged aside from ordering.
src/poetry/core/factory.py
Update validation tests to expect legacy deprecation warnings in non-strict mode and add coverage for both strict/non-strict paths and new-style [project] failures.
  • Parametrize test_validate_strict_legacy_warnings over strict=False/True and assert legacy warnings are returned in both cases.
  • Extend test_validate_fails to also assert presence of complete_legacy_warnings alongside existing error output.
  • Introduce test_validate_new_fails to exercise invalid [project.authors] errors without legacy warnings.
  • Adjust failure expectation tests to include new project name error and non-strict legacy deprecation warnings while keeping strict-mode additional warnings separate.
tests/test_factory.py
Align test fixtures with modern [project] table usage while keeping legacy sections where needed for behavior under test.
  • Convert several fixtures from [tool.poetry] to [project] for name/version/description/authors and move python requirements into project-level requires-python/python-requires and dependencies where appropriate.
  • Remove unused [tool.poetry.dependencies]/[tool.poetry.extras] tables from fixtures that now use project/group deps, to avoid legacy-only setups except where explicitly required for tests.
  • Augment the strict-validation failure fixture with a [project] section declaring dynamic fields so that readme-related strict warnings still make sense under the new validation order.
tests/masonry/builders/fixtures/with_bad_path_dep/pyproject.toml
tests/fixtures/project_with_groups_and_legacy_dev/pyproject.toml
tests/fixtures/project_with_invalid_dev_deps/pyproject.toml
tests/fixtures/project_failing_strict_validation/pyproject.toml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • By moving _validate_legacy_vs_project out of the strict branch you are now always running all legacy/project consistency checks, including any hard errors they may emit; if the goal is to only surface deprecation warnings for tool.poetry fields in non-strict mode, consider either splitting warning-only checks from error checks or scoping what runs outside strict.
  • In tests/masonry/builders/fixtures/with_bad_path_dep/pyproject.toml the new [project] metadata uses python-requires rather than the PEP 621 requires-python key, and you removed the previous [tool.poetry.dependencies].python entry; double-check that this fixture still models the intended Python constraint and doesn’t accidentally change what the test is validating.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- By moving `_validate_legacy_vs_project` out of the strict branch you are now always running all legacy/project consistency checks, including any hard errors they may emit; if the goal is to only surface deprecation warnings for `tool.poetry` fields in non-strict mode, consider either splitting warning-only checks from error checks or scoping what runs outside `strict`.
- In `tests/masonry/builders/fixtures/with_bad_path_dep/pyproject.toml` the new `[project]` metadata uses `python-requires` rather than the PEP 621 `requires-python` key, and you removed the previous `[tool.poetry.dependencies].python` entry; double-check that this fixture still models the intended Python constraint and doesn’t accidentally change what the test is validating.

## Individual Comments

### Comment 1
<location> `tests/test_factory.py:722-731` </location>
<code_context>
-
-
-def test_validate_strict_legacy_warnings(complete_legacy_warnings: list[str]) -> None:
[email protected]("strict", [False, True])
+def test_validate_strict_legacy_warnings(
+    complete_legacy_warnings: list[str], strict: bool
+) -> None:
     complete = fixtures_dir / "complete.toml"
     with complete.open("rb") as f:
         content = tomllib.load(f)

-    assert Factory.validate(content, strict=True) == {
+    assert Factory.validate(content, strict=strict) == {
         "errors": [],
         "warnings": complete_legacy_warnings,
     }
</code_context>

<issue_to_address>
**suggestion (testing):** Consider adding a test case for a config without any legacy fields to ensure no deprecation warnings are emitted in either strict or non-strict mode.

To fully cover the new behavior, please add a complementary test using a config without any legacy `tool.poetry` fields and assert that `Factory.validate(..., strict=False)` and `Factory.validate(..., strict=True)` both return an empty `warnings` list. This helps guard against regressions where `_validate_legacy_vs_project` might start emitting warnings for valid `project`-only configurations.

Suggested implementation:

```python
    assert Factory.validate(content, strict=strict) == {
        "errors": [],
        "warnings": complete_legacy_warnings,
    }
    assert Factory.validate(content) == {"errors": [], "warnings": []}


@pytest.mark.parametrize("strict", [False, True])
def test_validate_project_only_no_legacy_warnings(strict: bool) -> None:
    project_only = fixtures_dir / "project_only.toml"
    with project_only.open("rb") as f:
        content = tomllib.load(f)

    assert Factory.validate(content, strict=strict) == {
        "errors": [],
        "warnings": [],
    }


def test_validate_fails(complete_legacy_warnings: list[str]) -> None:
    complete = fixtures_dir / "complete.toml"
    with complete.open("rb") as f:
        content = tomllib.load(f)

    expected = "tool.poetry.authors must be array"

```

1. Ensure that a fixture file `project_only.toml` exists under `fixtures_dir` and that it represents a valid configuration using only `project`-style metadata, with no legacy `tool.poetry` metadata fields.
2. If `fixtures_dir` uses a different naming convention for such a fixture (e.g. `project_only_pyproject.toml` or similar), update the filename in `project_only = fixtures_dir / "project_only.toml"` accordingly.
3. Optionally, if the default behavior (`Factory.validate(content)`) is meant to be tested for the project-only config as well, you can add an additional assertion mirroring `assert Factory.validate(content) == {"errors": [], "warnings": []}` inside the new test.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +722 to 731
@pytest.mark.parametrize("strict", [False, True])
def test_validate_strict_legacy_warnings(
complete_legacy_warnings: list[str], strict: bool
) -> None:
complete = fixtures_dir / "complete.toml"
with complete.open("rb") as f:
content = tomllib.load(f)

assert Factory.validate(content, strict=True) == {
assert Factory.validate(content, strict=strict) == {
"errors": [],
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Consider adding a test case for a config without any legacy fields to ensure no deprecation warnings are emitted in either strict or non-strict mode.

To fully cover the new behavior, please add a complementary test using a config without any legacy tool.poetry fields and assert that Factory.validate(..., strict=False) and Factory.validate(..., strict=True) both return an empty warnings list. This helps guard against regressions where _validate_legacy_vs_project might start emitting warnings for valid project-only configurations.

Suggested implementation:

    assert Factory.validate(content, strict=strict) == {
        "errors": [],
        "warnings": complete_legacy_warnings,
    }
    assert Factory.validate(content) == {"errors": [], "warnings": []}


@pytest.mark.parametrize("strict", [False, True])
def test_validate_project_only_no_legacy_warnings(strict: bool) -> None:
    project_only = fixtures_dir / "project_only.toml"
    with project_only.open("rb") as f:
        content = tomllib.load(f)

    assert Factory.validate(content, strict=strict) == {
        "errors": [],
        "warnings": [],
    }


def test_validate_fails(complete_legacy_warnings: list[str]) -> None:
    complete = fixtures_dir / "complete.toml"
    with complete.open("rb") as f:
        content = tomllib.load(f)

    expected = "tool.poetry.authors must be array"
  1. Ensure that a fixture file project_only.toml exists under fixtures_dir and that it represents a valid configuration using only project-style metadata, with no legacy tool.poetry metadata fields.
  2. If fixtures_dir uses a different naming convention for such a fixture (e.g. project_only_pyproject.toml or similar), update the filename in project_only = fixtures_dir / "project_only.toml" accordingly.
  3. Optionally, if the default behavior (Factory.validate(content)) is meant to be tested for the project-only config as well, you can add an additional assertion mirroring assert Factory.validate(content) == {"errors": [], "warnings": []} inside the new test.

@Secrus
Copy link
Member

Secrus commented Dec 14, 2025

I wonder if we could add a way for users to disable the warnings (either via config or env var). I know some people just don't want to migrate because of "reasons" and they should be able to set i_am_aware_of_deprecation_remove_warnings=true or something like that.

@radoering
Copy link
Member Author

A config setting had to live in poetry. poetry-core has no config. It is easy to introduce an env var. However, I do not like to thoughlessly introduce env vars without a config setting. (It is easy to lose track of them.)

I know some people just don't want to migrate because of "reasons"

Is this about the project section in general or just about dependencies? tool.poetry.dependencies is not deprecated, you just have to declare dependencies as dynamic in the project section.

Do we want to care about those people? (It may be easier to answer that question if we knew the "reasons".) Then, we may just not make the deprecations more prominent and keep them as is until we think we do not have to care anymore. I am perfectly fine with that.

@Secrus
Copy link
Member

Secrus commented Dec 30, 2025

A config setting had to live in poetry. poetry-core has no config. It is easy to introduce an env var. However, I do not like to thoughlessly introduce env vars without a config setting. (It is easy to lose track of them.)

I agree, however I would still add an opt-out env var (we can mark it with a FIXME or TODO in the code. Just to avoid people complaining in issues/discussions.

Is this about the project section in general or just about dependencies?

The [project] section and any changes to metadata spec at all. Some arguments are like "we have X amount of services and have to fix all" etc.

Do we want to care about those people?

Personally, I am all for breaking fast and often with clear migration paths, so I would say "no".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants