Skip to content

Feature: cool down period#6659

Open
oz123 wants to merge 4 commits intomainfrom
feat-cool-down-period
Open

Feature: cool down period#6659
oz123 wants to merge 4 commits intomainfrom
feat-cool-down-period

Conversation

@oz123
Copy link
Copy Markdown
Contributor

@oz123 oz123 commented Apr 29, 2026

Add "cool-down-period" pipenv

See this feature added to pip:

pypa/pip#13674

The fix

Bumped plette which added a syntax support for this in Pipfile.
Added mathing parsing in pipenv, tests and documentation.
News file added.

@oz123 oz123 requested a review from matteius April 29, 2026 09:37
oz123 added 3 commits April 29, 2026 11:44
Updates vendored plette from 2.1.0 to 2.2.1, which adds the
`cool-down-period` field to the `[pipenv]` section model with
validation and a `cool_down_period_timedelta` helper property.

Signed-off-by: Oz Tiram <oz.tiram@gmail.com>
Reads the new `cool-down-period = "<n>d"` Pipfile setting introduced in
plette 2.2.1 and forwards it to pip's `--uploaded-prior-to P<n>D` flag
during dependency resolution, restricting the resolver to package versions
uploaded at least N days ago.

Includes unit tests for the arg-conversion helper and the injection into
`extra_pip_args`, an integration test verifying the lock succeeds with the
setting present, and documentation in docs/pipfile.md.

Signed-off-by: Oz Tiram <oz.tiram@gmail.com>
Replace nested and sequential if-blocks with short-circuit or-expressions,
reducing branch count without any behavioural change.

Signed-off-by: Oz Tiram <oz.tiram@gmail.com>
@oz123 oz123 force-pushed the feat-cool-down-period branch from b046314 to 2ccdaef Compare April 29, 2026 09:45
@oz123 oz123 changed the title Feat cool down period Feature: cool down period Apr 29, 2026
…f injecting into pip args

Passing --uploaded-prior-to via PIPENV_EXTRA_PIP_ARGS caused the subprocess
resolver to reject it as an unknown option. Instead, set pip_options.uploaded_prior_to
directly in Resolver.pip_options as a datetime object — the same pattern used for
other pip options like pre and cache_dir.

Rename _get_uploaded_prior_to_arg → _get_cool_down_timedelta to reflect that it now
returns a timedelta (or None) rather than a pip arg list. Update unit tests accordingly.

Switch the integration test from the private pypi fixture to pipenv_instance_pypi (real
PyPI), since pypiserver does not expose upload-time metadata and pip errors out rather
than silently ignoring the filter when --uploaded-prior-to is supplied.

Signed-off-by: Oz Tiram <oz.tiram@gmail.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for a Pipfile [pipenv] setting cool-down-period to restrict resolution to package versions uploaded at least N days ago (via pip’s --uploaded-prior-to behavior), along with a vendored plette bump, docs, news, and tests.

Changes:

  • Set pip’s uploaded_prior_to option in Resolver.pip_options based on [pipenv] cool-down-period.
  • Bump vendored plette to 2.2.1 and add corresponding vendored model changes.
  • Add documentation, news entries, and unit/integration tests for the new setting.

Reviewed changes

Copilot reviewed 6 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pipenv/utils/resolver.py Implements cool-down-period parsing and wires it into pip options as uploaded_prior_to.
tests/unit/test_resolver_regressions.py Adds unit tests for parsing and intended pip_options behavior.
tests/integration/test_lock.py Adds integration coverage to ensure cool-down-period affects locking.
docs/pipfile.md Documents the new Pipfile setting and its behavior/limitations.
pipenv/vendor/vendor.txt Bumps vendored plette version pin.
pipenv/vendor/plette/__init__.py Updates vendored plette version constant.
pipenv/vendor/plette/models/sections.py Adds cool-down-period validation/helpers to vendored plette models.
pipenv/vendor/plette/lockfiles.py Updates vendored lockfile encoding implementation.
pipenv/vendor/plette/__main__.py Adds a vendored CLI entry point for validating Pipfiles/Lockfiles.
news/+cool-down-period.feature.rst Announces the new feature.
news/+bump-plette.vendor.rst Notes the vendored dependency bump.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +748 to +775
@pytest.mark.lock
@pytest.mark.requirements
def test_lock_respects_cool_down_period(pipenv_instance_pypi):
"""cool-down-period in [pipenv] passes --uploaded-prior-to to the resolver.
Uses the real PyPI because it exposes upload-time metadata, which pip
requires when --uploaded-prior-to is supplied. The 30-day window is wide
enough to always include a stable release of `six`.
"""
with pipenv_instance_pypi() as p:
with open(p.pipfile_path, "w") as f:
f.write(
f"""
[[source]]
url = "{p.index_url}"
verify_ssl = true
name = "pypi"
[packages]
six = "*"
[pipenv]
cool-down-period = "30d"
"""
)
c = p.pipenv("lock")
assert c.returncode == 0, c.stderr
assert "six" in p.lockfile["default"]
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

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

This integration test uses the real PyPI (network dependency) but isn’t marked with @pytest.mark.needs_internet like other tests in this file (e.g. test_private_index_skip_lock). Without the marker, the test is likely to fail in offline/isolated CI runs. Add the appropriate internet/network marker(s) consistent with the rest of the integration suite.

Copilot uses AI. Check for mistakes.
Comment thread docs/pipfile.md
Comment on lines +225 to +227
The value must be a string in `<int>d` format (e.g. `"30d"` for 30 days). Internally
pipenv translates this to pip's `--uploaded-prior-to P30D` flag, which is only
effective against indexes that expose upload-time metadata as described in the
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

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

The docs say pipenv translates cool-down-period to pip’s --uploaded-prior-to P30D flag, but the implementation sets pip_options.uploaded_prior_to directly to a cutoff datetime (now(UTC) - timedelta). Update the wording to reflect the actual behavior (cutoff datetime) and/or note that pip supports both ISO datetimes and P<n>D durations.

Suggested change
The value must be a string in `<int>d` format (e.g. `"30d"` for 30 days). Internally
pipenv translates this to pip's `--uploaded-prior-to P30D` flag, which is only
effective against indexes that expose upload-time metadata as described in the
The value must be a string in `<int>d` format (e.g. `"30d"` for 30 days). Internally,
pipenv computes a cutoff datetime in UTC (`now - N days`) and passes that cutoff to
pip's uploaded-prior-to filtering. Pip also supports duration-style values such as
`P30D`, but pipenv's behavior here is based on a concrete cutoff timestamp. This is
only effective against indexes that expose upload-time metadata as described in the

Copilot uses AI. Check for mistakes.
Comment on lines +412 to +433
@pytest.mark.utils
def test_pip_options_sets_uploaded_prior_to_from_cool_down_period():
"""Resolver.pip_options sets uploaded_prior_to when cool-down-period is configured."""
import datetime
from types import SimpleNamespace

project = _make_project("30d")
project.s.PIPENV_CACHE_DIR = "/tmp/cache"
project.packages = {}

resolver = Resolver.__new__(Resolver)
resolver.project = project
resolver.sources = []

before = datetime.datetime.now(datetime.timezone.utc)
cool_down = _get_cool_down_timedelta(project)
assert cool_down is not None
cutoff = datetime.datetime.now(datetime.timezone.utc) - cool_down
after = datetime.datetime.now(datetime.timezone.utc) - cool_down

# cutoff should be approximately 30 days ago
assert before - datetime.timedelta(days=30, seconds=1) < cutoff < after + datetime.timedelta(seconds=1)
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

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

This test doesn’t exercise Resolver.pip_options at all: it computes cutoff = now - cool_down locally and asserts on that, so it will pass even if pip_options.uploaded_prior_to is never set. Update the test to call resolver.pip_options (mocking resolver.pip_command.parser.parse_args as needed) and assert that pip_options.uploaded_prior_to is set to approximately now - timedelta(days=30) when cool-down-period is configured. Also SimpleNamespace is imported but unused.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants