Skip to content

Require version in [project] table in non-package mode - #11028

Open
vikasvardhanv wants to merge 1 commit into
python-poetry:mainfrom
vikasvardhanv:fix-10032-project-version-required
Open

vikasvardhanv wants to merge 1 commit into
python-poetry:mainfrom
vikasvardhanv:fix-10032-project-version-required

Conversation

@vikasvardhanv

Copy link
Copy Markdown

Closes #10032

Bug

A pyproject.toml using the PEP 621 [project] table with a name but no version, in non-package mode, was silently accepted:

[project]
name = "test"
requires-python = ">=3.10"
dependencies = ["mkdocs"]

[tool.poetry]
package-mode = false

poetry check reported All set! (and poetry lock / sync proceeded) even though PEP 621 requires a version in the [project] table unless it is listed in [project.dynamic].

Root cause

Factory.validate() relies on the core schema validation to enforce the version requirement, but that check only fires in package mode (Either [project.version] or [tool.poetry.version] is required in package mode.). In non-package mode the requirement was never checked, so a [project] table with a name but no version passed validation.

Fix

Add a targeted check in Factory.validate() that, in non-package mode, flags a [project] table which declares a name but has neither a static version nor version listed in dynamic.

The check is gated on non-package mode so that package mode continues to emit only the existing core message (no duplicate error). Valid cases remain valid:

  • version declared statically -> OK
  • version listed in [project.dynamic] -> OK
  • legacy [tool.poetry]-only projects (no [project] table) -> unaffected

Testing

  • Added test_validate_non_package_mode_requires_project_version (parametrized: missing version -> error; static version -> OK; dynamic version -> OK) and test_validate_package_mode_missing_version_not_duplicated (ensures no duplicate error in package mode). The missing-version case fails on main and passes with this change.
  • pytest tests/test_factory.py tests/console/commands/test_check.py tests/json/test_schema.py -> 66 passed.
  • ruff check, ruff format --check, and mypy pass on the changed files.

Per PEP 621, a [project] table that declares a name must also declare a
version, either statically or via [project.dynamic]. In package mode this
is already enforced by the core schema validation, but in non-package mode
the requirement was skipped, so a pyproject.toml such as:

    [project]
    name = "test"
    dependencies = ["mkdocs"]

    [tool.poetry]
    package-mode = false

was silently accepted by `poetry check`, `poetry lock`, etc.

Add a validation check in Factory.validate that flags a [project] table
with a name but no version (and no "version" in dynamic) when running in
non-package mode. The check is gated on non-package mode so that package
mode does not emit a duplicate error alongside the existing core message.

Closes python-poetry#10032

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/poetry/factory.py" line_range="391" />
<code_context>
+            poetry_config.get("package-mode", True) is False
+            and project.get("name") is not None
+            and "version" not in project
+            and "version" not in project.get("dynamic", [])
+        ):
+            results["errors"].append(
</code_context>
<issue_to_address>
**issue (bug_risk):** Factory.validate() raises TypeError when [project].dynamic is set to a non-iterable value such as null or an integer, instead of returning the schema validation errors for the malformed project configuration.

**Triggers:** When package mode is false, the project has a name but no version, and dynamic is present with a non-iterable value.

**Suggested fix:** Check that `project.get("dynamic")` is a list before testing membership, or use a type-safe default such as `dynamic = project.get("dynamic") if isinstance(project.get("dynamic"), list) else []`.

```suggestion
            and "version" not in (project.get("dynamic") if isinstance(project.get("dynamic"), list) else [])
```
</issue_to_address>

Sourcery assessment

Approval pending. 1 finding to address first.

Blocking findings: src/poetry/factory.py:391


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 thread src/poetry/factory.py
poetry_config.get("package-mode", True) is False
and project.get("name") is not None
and "version" not in project
and "version" not in project.get("dynamic", [])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): Factory.validate() raises TypeError when [project].dynamic is set to a non-iterable value such as null or an integer, instead of returning the schema validation errors for the malformed project configuration.

Triggers: When package mode is false, the project has a name but no version, and dynamic is present with a non-iterable value.

Suggested fix: Check that project.get("dynamic") is a list before testing membership, or use a type-safe default such as dynamic = project.get("dynamic") if isinstance(project.get("dynamic"), list) else [].

Suggested change
and "version" not in project.get("dynamic", [])
and "version" not in (project.get("dynamic") if isinstance(project.get("dynamic"), list) else [])

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.

version field not required in [project] table when package-mode = false

1 participant