Skip to content

[regression] pip/pyproject: grouped updates collapse multiple requirements for the same package when they differ only by extras #14573

Closed

Description

@llucax

Is there an existing issue for this?

  • I have searched the existing issues

Package ecosystem

pip

Package manager version

pip 24.2

Language version

Python 3.11

Manifest location and content before the Dependabot update

/pyproject.toml (relevant excerpt, full flle):

requires-python = ">= 3.11, < 4"
dependencies = ["typing-extensions >= 4.13.0, < 5"]
dynamic = ["version"]

[project.optional-dependencies]
dev-flake8 = [
  "flake8 == 7.3.0",
  "flake8-docstrings == 1.7.0",
  "flake8-pyproject == 1.2.4", # For reading the flake8 config from pyproject.toml
  "pydoclint == 0.8.3",
  "pydocstyle == 6.3.0",
]
dev-formatting = ["black == 25.9.0", "isort == 8.0.1"]
dev-mkdocs = [
  "Markdown == 3.10.2",
  "black == 25.9.0",
  "mike == 2.1.4",
  "mkdocs-gen-files == 0.6.1",
  "mkdocs-literate-nav == 0.6.3",
  "mkdocs-macros-plugin == 1.5.0",
  "mkdocs-material == 9.7.6",
  "mkdocstrings[python] == 1.0.3",
  "mkdocstrings-python == 2.0.3",
  "frequenz-repo-config[lib] == 0.14.0",
]
dev-mypy = [
  "mypy == 1.19.1",
  "types-Markdown == 3.10.2.20260211",
  # For checking the noxfile, docs/ script, and tests
  "frequenz-core[dev-mkdocs,dev-noxfile,dev-pytest]",
]
dev-noxfile = ["nox == 2026.2.9", "frequenz-repo-config[lib] == 0.14.0"]
dev-pylint = [
  # dev-pytest already defines a dependency to pylint because of the examples
  # For checking the noxfile, docs/ script, and tests
  "frequenz-core[dev-mkdocs,dev-noxfile,dev-pytest]",
]
dev-pytest = [
  "pytest == 9.0.2",
  "pylint == 4.0.5", # We need this to check for the examples
  "frequenz-repo-config[extra-lint-examples] == 0.14.0",
  "pytest-mock == 3.15.1",
  "pytest-asyncio == 1.3.0",
  "async-solipsism == 0.9",
  "hypothesis == 6.151.10",
]
dev = [
  "frequenz-core[dev-mkdocs,dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]",
]

dependabot.yml content

Relevant content (full file):

version: 2
updates:
  - package-ecosystem: "pip"
    directory: "/"
    schedule:
      interval: "monthly"
      day: "monday"
    labels:
      - "part:tooling"
      - "type:tech-debt"
    # Default versioning-strategy. For other versioning-strategy see:
    # https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#versioning-strategy
    versioning-strategy: auto
    # Allow up to 10 open pull requests for updates to dependency versions
    open-pull-requests-limit: 10
    # We group patch updates as they should always work.
    # We also group minor updates, as it works too for most libraries,
    # typically except libraries that don't have a stable release yet (v0.x.x
    # branch), so we make some exceptions for them.
    # Major updates and dependencies excluded by the above groups are still
    # managed, but they'll create one PR per dependency, as breakage is
    # expected, so it might need manual intervention.
    # Finally, we group some dependencies that are related to each other, and
    # usually need to be updated together.
    groups:
      patch:
        update-types:
          - "patch"
        exclude-patterns:
          # pydoclint has shipped breaking changes in patch updates often
          - "pydoclint"
      minor:
        update-types:
          - "minor"
        exclude-patterns:
          - "async-solipsism"
          - "frequenz-repo-config"
          - "frequenz-repo-config[lib]"
          - "frequenz-repo-config[extra-lint-examples]"
          - "markdown-callouts"
          - "mkdocs-gen-files"
          - "mkdocs-literate-nav"
          - "mkdocstrings*"
          - "mkdocstrings[python]"
          - "pydoclint"
          - "pytest-asyncio"
      # We group repo-config updates as it uses optional dependencies that are
      # considered different dependencies otherwise, and will create one PR for
      # each if we don't group them.
      repo-config:
        patterns:
          - "frequenz-repo-config"
          - "frequenz-repo-config[lib]"
          - "frequenz-repo-config[extra-lint-examples]"
      mkdocstrings:
        patterns:
          - "mkdocstrings*"
          - "mkdocstrings[python]"

Updated dependency

frequenz-repo-config

What you expected to see, versus what you actually saw

This worked previously.

Before the recent Python extras handling change, Dependabot treated:

  • frequenz-repo-config[api]
  • frequenz-repo-config[extra-lint-examples]

as distinct direct requirements. A grouped PR was created successfully and updated both requirements together.

After the recent change that moved extras out of the Python dependency name and into metadata, Dependabot appears to collapse both requirements into the same base package identity. As a result, group matching / update selection no longer behaves correctly for requirements that differ only by extras.

Expected:
Dependabot should continue to treat multiple direct requirements for the same base package but with different extras as separately matchable requirements for grouping and updating, and should update both entries.

Actual:
Dependabot no longer updates/matches both extra-qualified requirements correctly. The behavior regressed compared to earlier runs on the same configuration.

Native package manager behavior

This does not appear to be a resolver limitation in the native tooling.

If both requirement strings are kept explicitly in pyproject.toml and updated manually, the project can still express both direct requirements separately. The regression appears to be in Dependabot's dependency identification / grouping logic after extras were moved out of the dependency name and into metadata.

Images of the diff or a link to the PR, issue, or logs

This appears to be a regression introduced after dependabot-core PR #14476 (“fix(python): Dependency name correct when extras are present”), which moved Python extras out of the dependency name and into metadata.

Before that change, Dependabot treated frequenz-repo-config[api] and frequenz-repo-config[extra-lint-examples] as distinct direct requirements and grouped/updated them correctly. After that change, Dependabot appears to collapse both entries to the same base dependency identity, which breaks grouped updates and matching for direct requirements that differ only by extras.

Related, but not identical, issue:

Working dependabot run (2 weeks ago, March 18):

Not working dependabot run:

Smallest manifest that reproduces the issue

Guess, not checked:

pyproject.toml

[project]
name = "dependabot-extras-repro"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
  "frequenz-repo-config[api]==0.13.6",
  "frequenz-repo-config[extra-lint-examples]==0.13.6",
]

[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"

dependabot.yaml

version: 2
updates:
  - package-ecosystem: "pip"
    directory: "/"
    schedule:
      interval: "weekly"
    groups:
      repo-config:
        patterns:
          - "frequenz-repo-config"
          - "frequenz-repo-config[api]"
          - "frequenz-repo-config[extra-lint-examples]"

Activity

  1. self-assigned this
    on Mar 30, 2026
  2. added a commit that references this issue on Mar 30, 2026
    bdd37fb
  3. jakecoffman commented on Mar 31, 2026

    @jakecoffman
    Member

    Thanks for the detailed and timely report!

  4. llucax commented on Mar 31, 2026

    @llucax
    Author

    Thanks for the quick fix. How does this normally work with GitHub deployment, when can I expect this to be rolled out in GitHub.com (if this is when the right place to ask)? Any recommendation on how to fix the existing broken PRs? Would a @dependabot recreate command fix them?

  5. jakecoffman commented on Mar 31, 2026

    @jakecoffman
    Member

    We deploy from branches, so once a PR is merged it is rolled out. Yes @dependabot recreate should fix the issue for open PRs.

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

Metadata

Metadata

Assignees

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions