Class PyProjectHelper

java.lang.Object
org.openrewrite.python.internal.PyProjectHelper

public class PyProjectHelper extends Object
Shared utilities for Python dependency recipes operating on pyproject.toml files.
  • Constructor Details

    • PyProjectHelper

      public PyProjectHelper()
  • Method Details

    • normalizeVersionConstraint

      public static String normalizeVersionConstraint(String version)
      Normalize a version constraint so it is valid PEP 508. When the value does not start with a comparison operator (>=, <=, etc.) we default to >=.
    • extractKeyName

      public static @Nullable String extractKeyName(org.openrewrite.toml.tree.Toml.KeyValue kv)
      Read the unquoted key name from a TOML key-value, or null if the key isn't a plain Toml.Identifier. Quote stripping is handled by the TOML parser itself ("urllib3" and urllib3 both expose "urllib3" via getName()).
    • extractPackageName

      public static @Nullable String extractPackageName(String pep508Spec)
      Extract the package name from a PEP 508 dependency spec string. The name is the first token before any version specifier, extras, or marker.
    • correspondingPyprojectPath

      public static Path correspondingPyprojectPath(Path uvLockPath)
      Derive the pyproject.toml path that corresponds to a uv.lock path.
    • correspondingPipfilePath

      public static Path correspondingPipfilePath(Path pipfileLockPath)
      Derive the Pipfile path that corresponds to a Pipfile.lock path.
    • reparseJson

      public static org.openrewrite.json.tree.Json.Document reparseJson(org.openrewrite.json.tree.Json.Document original, String newContent)
      Reparse a JSON document from new content while preserving the original document's identity (id) and markers.
    • reparseToml

      public static org.openrewrite.toml.tree.Toml.Document reparseToml(org.openrewrite.toml.tree.Toml.Document original, String newContent)
      Reparse a TOML document from new content while preserving the original document's identity (id) and markers.
    • refreshMarker

      public static org.openrewrite.SourceFile refreshMarker(org.openrewrite.SourceFile depsFile)
      Re-derive the PythonResolutionResult marker on a modified dependency source file by re-parsing its current document content. This is needed after structural edits (adding/removing/changing dependencies) so that the marker's declared-dependency list reflects the new content; otherwise idempotency checks in subsequent recipe cycles see stale data and re-apply the edit. Returns the source file unchanged if no marker is present or the file shape is not recognised.
    • applyResolvedDependencies

      public static org.openrewrite.SourceFile applyResolvedDependencies(org.openrewrite.SourceFile depsFile, String regeneratedLockContent)
      Overlay resolved-dependency information from regenerated lock content onto the source file's existing PythonResolutionResult marker. Dispatches on the marker's package manager (uv → UvLockParser; pipenv → PipfileLockParser). Returns the source file unchanged if there is no marker, no recognised package manager, or the lock content has no resolved dependencies.
    • getLiveDepsTree

      public static @Nullable org.openrewrite.SourceFile getLiveDepsTree(org.openrewrite.ExecutionContext ctx, Path depsPath)
      Read the latest known chain-modified deps tree for a given path from the shared ExecutionContext side channel, or null if no recipe has written one yet.
    • putLiveDepsTree

      public static void putLiveDepsTree(org.openrewrite.ExecutionContext ctx, Path depsPath, org.openrewrite.SourceFile depsTree)
      Publish the current chain-modified deps tree for a given path to the shared ExecutionContext side channel. Subsequent recipes — and lock-file visits within the same recipe pass that arrive after this one — read this to apply their edit on top of prior recipes' modifications.
    • editAndRegenerate

      public static PyProjectHelper.EditAndRegenerateResult editAndRegenerate(PythonDependencyFile trait, Function<PythonDependencyFile,PythonDependencyFile> editFn, @Nullable String capturedLockContent)
      Apply a recipe-specific trait edit to a deps tree, refresh its marker, and regenerate the lock file. Used both by deps-file visits (which obtain the trait from the framework's live cursor) and by lock-file lazy-compute visits (which obtain the trait via a synthetic cursor over a tree pulled from the accumulator or the ctx side channel).
      Parameters:
      trait - the trait wrapping the deps tree to edit
      editFn - applies the recipe-specific edit (e.g. t -> t.withAddedDependencies(...))
      capturedLockContent - the lock content captured during scanning, or null when no lock file was seen
      Returns:
      a result describing what changed
    • regenerateLockContent

      public static @Nullable LockFileRegeneration.Result regenerateLockContent(org.openrewrite.SourceFile depsFile, @Nullable String capturedLockContent)
      Regenerate the lock file for a dependencies-file source by dispatching to the package manager indicated by its PythonResolutionResult marker. Returns null when the source has no marker, no package manager, or no regeneration adapter for that package manager.
    • isInsideProjectDependencies

      public static boolean isInsideProjectDependencies(org.openrewrite.Cursor cursor)
      Check whether a cursor path represents a position inside the [project].dependencies array in a pyproject.toml.
    • isInsideDependencyArray

      public static boolean isInsideDependencyArray(org.openrewrite.Cursor cursor, @Nullable String scope, @Nullable String groupName)
      Check whether a cursor path represents a position inside a dependency array for the given scope and optional group name.

      Scope values use TOML dotted-key path syntax:

      • null or "project.dependencies"[project].dependencies
      • "build-system.requires"[build-system].requires
      • "project.optional-dependencies"[project.optional-dependencies].<groupName>
      • "dependency-groups"[dependency-groups].<groupName>
      • "tool.uv.constraint-dependencies"[tool.uv].constraint-dependencies
      • "tool.uv.override-dependencies"[tool.uv].override-dependencies
    • findDependencyInScope

      public static @Nullable PythonResolutionResult.Dependency findDependencyInScope(PythonResolutionResult marker, String packageName, @Nullable String scope, @Nullable String groupName)
      Find a dependency in the specified scope of the marker.
      Parameters:
      marker - the resolution result marker
      packageName - the package name to find
      scope - the scope to search (null means project.dependencies)
      groupName - the group name (required for optional-dependencies and dependency-groups)
      Returns:
      the dependency, or null if not found
    • isInsidePdmOverridesTable

      public static boolean isInsidePdmOverridesTable(org.openrewrite.Cursor cursor)
      Check whether a cursor path represents a position inside the [tool.pdm.overrides] table in a pyproject.toml.