Skip to content

Add PythonDependencyFile trait for polymorphic dependency management#7274

Merged
Jenson3210 merged 26 commits intomainfrom
python-dependencies-trait
Apr 8, 2026
Merged

Add PythonDependencyFile trait for polymorphic dependency management#7274
Jenson3210 merged 26 commits intomainfrom
python-dependencies-trait

Conversation

@Jenson3210
Copy link
Copy Markdown
Contributor

@Jenson3210 Jenson3210 commented Apr 3, 2026

Summary

  • Introduces the PythonDependencyFile trait with implementations for PyProjectFile (pyproject.toml), RequirementsFile (requirements.txt), and PipfileFile (Pipfile), providing a polymorphic API for dependency operations: add, upgrade, remove, change, pin transitives, and search markers
  • Refactors AddDependency, UpgradeDependencyVersion, RemoveDependency, ChangeDependency, and UpgradeTransitiveDependencyVersion to use the trait instead of duplicating TOML manipulation logic — removing ~800 lines of duplicated code
  • All recipes now work on pyproject.toml, requirements.txt, and Pipfile files
  • RequirementsFile supports scope-based filename filtering: scope=null matches all files, scope="" matches requirements.txt, scope="dev" matches requirements-dev.txt
  • PipfileFile supports [packages] and [dev-packages] sections via scope parameter, including inline table dependencies (django = {version = ">=3.2", extras = ["postgres"]})
  • Adds PipfileParser for parsing Pipfile and attaching PythonResolutionResult markers with PackageManager.Pipenv
  • Package name normalization (PEP 503) is handled internally by the trait — callers don't need to pre-normalize

Test plan

  • 41 trait unit tests (PythonDependencyFileTest) covering all trait methods, matcher, scope filtering, and static utilities
  • 15 Pipfile trait unit tests (PipfileFileTest) covering matcher, upgrade, add, remove, change, and search markers
  • All existing recipe tests pass (AddDependency, UpgradeDependencyVersion, UpgradeTransitiveDependencyVersion, RemoveDependency, ChangeDependency)
  • New requirements.txt recipe integration tests for all 4 direct-dependency recipes
  • New Pipfile recipe integration tests for all 5 recipes
  • 126 total tests passing

@timtebeek
Copy link
Copy Markdown
Member

In terms of scope I'd say it's unrelated, but flagging it here in case we want to consider a Python variant

Comment thread rewrite-python/src/main/java/org/openrewrite/python/trait/PipfileFile.java Outdated
timtebeek and others added 5 commits April 7, 2026 23:29
Lombok @with always creates new instances even when values are identical,
so reference equality checks fail without explicit value comparison.
This caused recipes to take an extra cycle, breaking 5 CI tests.
- null scope now means "all scopes" for all filtering methods
  (withUpgradedVersions, withRemovedDependencies, withChangedDependency,
  withDependencySearchMarkers, withPinnedTransitiveDependencies)
- withAddedDependencies keeps null = default scope (project.dependencies)
  since additions need a target location
- Add scope/groupName params to withChangedDependency and
  withPinnedTransitiveDependencies for consistent filtering
- Remove restrictive valid scope lists from recipe @option annotations
  since scope values are now polymorphic across file types
  (pyproject.toml, requirements.txt, Pipfile)
- Add scope-filtering tests for search markers across all implementations
Avoids unnecessary trait matching and lock file print-compare
cost when no dependency files need updating.
…e maps

Replace manual string slicing with Path.resolveSibling in
correspondingPyprojectPath and change ExecutionContext lock file maps
from Map<String, String> to Map<Path, String>, eliminating toString()
conversions at all call sites.
Use diamond operator, static imports, toList(), and getFirst() in tests.
Minor line wrapping cleanup in production code.
Copy link
Copy Markdown
Member

@timtebeek timtebeek left a comment

Choose a reason for hiding this comment

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

Nice work! I like how this simplifies all the recipe implementations, and unlocks usage downstream to make the correct change each and every time we handle dependencies, no matter how they're defined.

@github-project-automation github-project-automation Bot moved this from In Progress to Ready to Review in OpenRewrite Apr 8, 2026
@Jenson3210 Jenson3210 merged commit 7767c5f into main Apr 8, 2026
1 check passed
@Jenson3210 Jenson3210 deleted the python-dependencies-trait branch April 8, 2026 10:52
@github-project-automation github-project-automation Bot moved this from Ready to Review to Done in OpenRewrite Apr 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

2 participants