Skip to content

Comments

consider dependency-groups in lockfile hash#10621

Merged
radoering merged 2 commits intopython-poetry:mainfrom
radoering:hash-dependency-groups
Nov 21, 2025
Merged

consider dependency-groups in lockfile hash#10621
radoering merged 2 commits intopython-poetry:mainfrom
radoering:hash-dependency-groups

Conversation

@radoering
Copy link
Member

@radoering radoering commented Nov 17, 2025

Pull Request Check List

Resolves: #10598

  • Added tests for changed code.
  • Updated documentation for changed code.

Unfortunately, just considering dependency-groups has the following effects:

  1. The new Poetry version will consider a lock file generated with an old version outdated if dependency-groups are defined in the pyproject.toml file.
  2. An old Poetry version will consider a lock file generated with the new Poetry version outdated if dependency-groups are defined in the pyproject.toml file.

I handled the first issue in the second commit. I assume it is controversial if this should be addressed at all. I decided to do it to make the update process smoother and avoid failing pipelines.

I think we have to accept the second issue. (I think we just should not include this fix in a micro release but in a minor release.)

By the way, I extended the tests for changes to the hash function significantly because it is critical for backwards compatibility that the hash does not change if a new field is not used.

Summary by Sourcery

Include dependency-groups in the lockfile content hash while preserving backward compatibility with pre-2.3.0 Poetry by allowing recomputation of the hash without dependency-groups and updating tests accordingly

New Features:

  • Update lockfile hash computation to include dependency-groups by default
  • Detect and accept lockfiles generated by Poetry <2.3.0 by recomputing hash without dependency-groups

Enhancements:

  • Add with_dependency_groups flag to Locker._get_content_hash and adjust relevant content selection to incorporate dependency-groups
  • Update is_fresh to conditionally fallback to legacy hash for older lockfile versions

Tests:

  • Extend tests for lockfile freshness and content hash generation to cover dependency-groups and legacy compatibility
  • Adjust installer stub in tests to support with_dependency_groups parameter

@sourcery-ai
Copy link

sourcery-ai bot commented Nov 17, 2025

Reviewer's Guide

This PR updates the lockfile hash and freshness logic to incorporate the new dependency-groups section while preserving backward compatibility with older Poetry versions, and extends the test suite to validate hashing and freshness behavior across both legacy and new configurations.

Sequence diagram for lockfile freshness check with dependency-groups and version fallback

sequenceDiagram
    participant Locker
    participant Lockfile
    participant "Poetry Version Parser"
    Locker->>Lockfile: open lockfile and read first line
    Locker->>"Poetry Version Parser": extract Poetry version from comment
    alt Poetry version < 2.3.0
        Locker->>Locker: _get_content_hash(with_dependency_groups=False)
        Locker->>Lockfile: compare old_content_hash to lockfile hash
    else Poetry version >= 2.3.0
        Locker->>Locker: _get_content_hash(with_dependency_groups=True)
        Locker->>Lockfile: compare content_hash to lockfile hash
    end
Loading

File-Level Changes

Change Details Files
Enhance lockfile hash and freshness logic to handle dependency-groups with backward compatibility
  • Added a with_dependency_groups parameter to _get_content_hash
  • Modified _get_content_hash to include dependency-groups when present
  • Updated is_fresh to detect pre-2.3.0 lockfiles and rehash without dependency-groups for comparison
src/poetry/packages/locker.py
Extend tests to cover dependency-groups inclusion and legacy compatibility
  • Added test_is_fresh_dependency_groups for freshness checks under various version and hash conditions
  • Refactored test_content_hash_with_legacy_is_compatible parameter and assertion logic
  • Introduced tests for content hash behavior in project and dependency-groups sections
  • Updated test_installer stub to match new _get_content_hash signature
tests/packages/test_locker.py
tests/installation/test_installer.py

Assessment against linked issues

Issue Objective Addressed Explanation
#10598 Ensure that dependencies listed in a PEP735 dependency group in pyproject.toml contribute to the lock file hash.
#10598 Update the lock file hash calculation to handle dependency-groups as a top-level key, not as a project key.

Possibly linked issues


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 and they look great!

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

## Individual Comments

### Comment 1
<location> `src/poetry/packages/locker.py:291-301` </location>
<code_context>
         self._lock_data = None

-    def _get_content_hash(self) -> str:
+    def _get_content_hash(self, *, with_dependency_groups: bool = True) -> str:
         """
         Returns the sha256 hash of the sorted content of the pyproject file.
</code_context>

<issue_to_address>
**suggestion:** Consider documenting the new 'with_dependency_groups' parameter for clarity.

Documenting how this parameter affects hash calculation will help maintainers understand its role and ensure backward compatibility.

```suggestion
    def _get_content_hash(self, *, with_dependency_groups: bool = True) -> str:
        """
        Returns the sha256 hash of the sorted content of the pyproject file.

        Args:
            with_dependency_groups (bool, optional): If True (default), includes the
                'dependency-groups' section from the pyproject file in the hash calculation.
                If False, excludes 'dependency-groups' from the hash. This can be used to
                control whether changes to dependency groups affect the content hash.

        Returns:
            str: The sha256 hash of the relevant pyproject content.
        """
        project_content = self._pyproject_data.get("project", {})
        group_content = (
            self._pyproject_data.get("dependency-groups", {})
            if with_dependency_groups
            else {}
        )
        tool_poetry_content = self._pyproject_data.get("tool", {}).get("poetry", {})
```
</issue_to_address>

### Comment 2
<location> `src/poetry/packages/locker.py:109` </location>
<code_context>
    def is_fresh(self) -> bool:
        """
        Checks whether the lock file is still up to date with the current hash.
        """
        with self.lock.open("rb") as f:
            lock = tomllib.load(f)
        metadata = lock.get("metadata", {})

        if "content-hash" in metadata:
            fresh: bool = self._content_hash == metadata["content-hash"]
            if not fresh:
                with self.lock.open("r", encoding="utf-8") as f:
                    generated_comment = f.readline()
                if m := re.search("Poetry ([^ ]+)", generated_comment):
                    try:
                        version = Version.parse(m.group(1))
                    except InvalidVersionError:
                        pass
                    else:
                        if version < Version.parse("2.3.0"):
                            # Before Poetry 2.3.0, the content hash did not include
                            # dependency groups, so we need to recompute it without
                            # them for comparison.
                            old_content_hash = self._get_content_hash(
                                with_dependency_groups=False
                            )
                            fresh = old_content_hash == metadata["content-hash"]
            return fresh

        return False

</code_context>

<issue_to_address>
**suggestion (code-quality):** Replace m.group(x) with m[x] for re.Match objects ([`use-getitem-for-re-match-groups`](https://docs.sourcery.ai/Reference/Default-Rules/suggestions/use-getitem-for-re-match-groups/))

```suggestion
                        version = Version.parse(m[1])
```
</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.

@radoering radoering force-pushed the hash-dependency-groups branch from a475bd1 to 2e8ab24 Compare November 21, 2025 15:45
@radoering radoering enabled auto-merge (rebase) November 21, 2025 15:49
@radoering radoering merged commit 8ccc6b1 into python-poetry:main Nov 21, 2025
63 checks passed
@radoering radoering mentioned this pull request Dec 7, 2025
@github-actions
Copy link

This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 22, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dependencies listed in a PEP735 dependency group do not contribute to lock file hash

2 participants