Skip to content

enhancement(python-setup/pip): align cache input shape and defaults with uv/pixi #18

Description

@MAfarrag

Summary

The three python-setup actions expose caching through inconsistent inputs — different value shapes,
different defaults, and different behavior when no lock/dependency file exists. A caller who learns the cache
input on one action cannot reuse that knowledge on another, and copying a cache: 'true' call from uv/pixi to pip
fails outright. This issue tracks aligning pip's caching UX with uv/pixi while respecting pip's real constraint:
unlike uv/pixi, it can run with no lock/dependency file to hash.

Current state

Action cache value shape Default Cache key source Behavior with no lock/dep file
pip setup-python cache type string: pip / pipenv / poetry / '' '' (off) setup-python hashes pyproject.toml / requirements.txt Hard error (action guard + setup-python both fail)
uv boolean-string: true / false true (on) uv.lock N/A — uv.lock always present
pixi boolean-string: true / false false (off); writes only on main pushes pixi.lock hash N/A — pixi.lock required

Relevant code: actions/python-setup/pip/action.yml:12-20 (input), :44-55 (validate-cache guard),
:57-62 (pass-through to actions/setup-python); actions/python-setup/uv/action.yml:12-19;
actions/python-setup/pixi/action.yml:21-29.

Problems

  • [H1] Inconsistent input shape. cache: 'true' is valid for uv/pixi but invalid for pip — pip forwards
    the value to actions/setup-python's cache: input, which only accepts pip / pipenv / poetry / empty and
    rejects true (Caching for 'true' is not supported). A user copying a uv/pixi invocation to pip gets a hard
    failure with a confusing message.
  • [H2] Divergent defaults. pip is off (''), uv is on ('true'), pixi is off ('false'). There is no
    coherent repo-wide policy, so callers cannot assume what "no cache: given" does.
  • [M1] pip's on-path requires a dependency file. With caching enabled but no pyproject.toml /
    requirements.txt, both the action's own guard (pip/action.yml:49-52) and actions/setup-python error out.
    uv/pixi have no equivalent failure mode because a lockfile is always present. This is exactly why pip cannot
    simply default caching on.
  • [M2] Contract conflict blocks a naive default flip. test-pip-cache-validation-error deliberately asserts
    a failure when cache is set but no dependency file exists. A composite action cannot distinguish an
    explicit value from a defaulted one, so "on by default" and "explicit-cache-without-a-file errors" cannot both
    hold as-is.

Proposed alignment

Recommended design — uniform UX, keeps pip's power, backward compatible where possible:

  • [T1] Accept a boolean-string on pip's cache input like uv/pixi: 'true' → use 'pip' internally,
    'false' / '' → off. Keep accepting the literal setup-python values ('pip', 'pipenv', 'poetry') as a
    pass-through for power users and backward compatibility. Update the input description/examples accordingly.
  • [T2] Apply a consistent default. The requested direction is on-by-default (cache: 'true') to match uv
    — but note pixi is currently 'false'; a repo-wide on-vs-off decision is needed (see Q1).
  • [T3] Make on-by-default safe: when caching is requested but no pyproject.toml / requirements.txt is
    present, auto-disable caching with a ::warning:: and pass an empty cache to setup-python (so setup-python
    does not error either), instead of failing. Required because pip — unlike uv/pixi — can legitimately run with no
    dependency file.
  • [T4] Reconcile the negative test: update test-pip-cache-validation-error to the new auto-skip behavior
    (assert the run succeeds and emits the warning), since a hard error is incompatible with a safe
    on-by-default.
  • [T5] Confirm test-pip-basic and test-pip-no-dependency-file still pass with cache on-by-default (they
    should, via the T3 auto-skip); add assertions for the auto-skip path.
  • [T6] Update docs (docs/python-setup/pip.md, the caching rows in docs/python-setup/index.md, and any
    README / getting-started references) for the new input shape, default, and auto-skip behavior, and note the
    uv/pixi parity.

Backward compatibility & versioning

Changing the cache input's accepted values and default is a behavior change. Per the repo's Breaking Changes
policy, changing input defaults/semantics warrants a major version bump for the pip action (pip/v2). Keeping
the 'pip' / 'pipenv' / 'poetry' pass-through preserves existing callers; the default flip is the breaking
part
(a consumer relying on "no cache unless I ask" would start caching). Call this out in the release notes and
move the pip/vN major tag accordingly.

Open questions (need a decision)

  • [Q1] Repo-wide default policy: default all three cache on (flip pixi to 'true' as well), or align
    pip to pixi's off? The requested direction is pip on-by-default like uv, but pixi is currently off — pick one
    policy for the repo.
  • [Q2] On a missing dependency file with cache on: auto-skip with warning (recommended, required for a safe
    on-by-default) vs keep a hard error?
  • [Q3] Keep the advanced pip cache types (pipenv, poetry) overloaded on the same cache input, or split
    them into a separate cache-dependency / cache-type input to keep cache a clean boolean?

Out of scope

  • Changing uv/pixi cache internals — they already share the boolean-string shape. This issue aligns pip to that
    shape and settles the repo-wide default policy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions