Skip to content

PEP 621 + Poetry: pin_pep508_entry silently drops direct git references (@ git+) #14728

@liusally

Description

@liusally

Description

pin_pep508_entry in pyproject_preparer.rb does not handle PEP 508 direct references (@ git+https://...). Prior to #14706, it produced an invalid specifier causing Poetry to crash. After #14706 (merged today), it silently drops the @ git+ URL and replaces the dep with ==version from PyPI — changing the resolved package from a private fork to the public one.

Reproduction

pyproject.toml using PEP 621 format with a Poetry backend:

[project]
dependencies = [
    "pillow>=12.1.1,<13.0.0",
    "ffmpeg-python @ git+https://github.com/example/ffmpeg-python",
]

When dependabot tries to resolve pillow, freeze_pep621_dep_array! iterates all entries and calls pin_pep508_entry on ffmpeg-python. The lock file has version = "0.2.0", so:

Before #14706: output is ffmpeg-python==0.2.0 @ git+https://... — Poetry crashes with The requirement is invalid: Unexpected character at column 22

After #14706: output is ffmpeg-python==0.2.0 — silently replaces the git fork with the PyPI version, which may have different dependencies (in our case, the fork removes an unmaintained transitive dep)

Root cause

The new pin_pep508_entry extracts the name prefix via PEP508_PREFIX, then unconditionally rebuilds the entry as "#{prefix}==#{version}#{marker}", discarding everything between the name and the marker — including @ git+ URLs.

Suggested fix

pin_pep508_entry should detect direct references and return the entry unchanged:

def self.pin_pep508_entry(entry, version)
  prefix_match = entry.match(PEP508_PREFIX)
  return entry unless prefix_match

  prefix = T.must(prefix_match[:prefix])
  rest = T.must(entry[prefix.length..])

  # Skip direct references — already pinned to a URL
  return entry if rest.match?(/\A\s*@\s/)

  marker_match = rest.match(/(\s*;.*)/)
  marker = marker_match ? marker_match[1] : ""
  "#{prefix}==#{version}#{marker}"
end

Environment

  • Package manager: pip (Poetry backend with poetry.lock)
  • pyproject.toml format: PEP 621 [project].dependencies
  • Dependabot Updates workflow (GitHub-hosted, security updates)

Metadata

Metadata

Assignees

Type

No type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions