Skip to content

cli: add --min-release-age for relative update delay#13837

Open
nmanthey wants to merge 2 commits intopypa:mainfrom
nmanthey:min_release_age
Open

cli: add --min-release-age for relative update delay#13837
nmanthey wants to merge 2 commits intopypa:mainfrom
nmanthey:min_release_age

Conversation

@nmanthey
Copy link

@nmanthey nmanthey commented Mar 4, 2026

As a user, I want to be able to set a relative time to specify the package versions to update. This feature is present in package managers of other repositories, e.g. in npm, as --min-release-age.

This commit introduces a new --min-release-age option to accept relative time spans (e.g., '7d', '168h', '10080m') as an alternative to --uploaded-prior-to.

The callback parses the given time stamp into an absolute time and next uses the logic already present via the uploaded_prior_to. Parsing supports d/days, h/hours, m/minutes, w/weeks as units. Unit tests are added accordingly, following the test pattern of --uploaded-prior-to.

Related issue #13674

Testing Done

Unit tests check the data parsing code similar to testing for the existing "--uploaded-prior-to" flag.

In addition, I tested the implementation in a local venv:

Command Installed Version Result
pip install certifi 2026.2.25 Latest (no filter)
pip install --min-release-age=10 certifi 2026.1.4 10+ days old
pip install --min-release-age=365 certifi 2025.1.31 365+ days old

Testing Executed

Setup and install current pip

python3 -m venv demo-env 
source demo-env/bin/activate

(demo-env) pip: pip install -e .
Obtaining file:///home/ANT.AMAZON.COM/nmanthey/projects/npm-pipy-update-delay/pip-repo
  Installing build dependencies ... done
  Checking if build backend supports build_editable ... done
  Getting requirements to build editable ... done
  Preparing editable metadata (pyproject.toml) ... done
Building wheels for collected packages: pip
  Building editable for pip (pyproject.toml) ... done
  Created wheel for pip: filename=pip-26.1.dev0-py3-none-any.whl size=40741 sha256=ad7788ea88fdd7d993e30c242a50e8c630553f78233d04a1ed1a44c1bb3dcdb5
  Stored in directory: /tmp/pip-ephem-wheel-cache-nb45iy88/wheels/38/60/5f/06b1d14e4f4b87f2b38289c3b11c4928acff547c425b135bba
Successfully built pip
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 22.0.2
    Uninstalling pip-22.0.2:
      Successfully uninstalled pip-22.0.2
Successfully installed pip-26.1.dev0

Check versions of certifi package

(demo-env) pip: echo "Current date: $(date -u +%Y-%m-%d)"
Current date: 2026-03-04
(demo-env) pip: pip index versions certifi 2>/dev/null | head -6
certifi (2026.2.25)
Available versions: 2026.2.25, 2026.1.4, 2025.11.12, 2025.10.5, 2025.8.3, 2025.7.14, 2025.7.9, 2025.6.15, 2025.4.26, 2025.1.31, 2024.12.14, 2024.8.30, 2024.7.4, 2024.6.2, 2024.2.2, 2023.11.17, 2023.7.22, 2023.5.7, 2022.12.7, 2022.9.24, 2022.9.14, 2022.6.15.2, 2022.6.15.1, 2022.6.15, 2022.5.18.1, 2021.10.8, 2021.5.30, 2020.12.5, 2020.11.8, 2020.6.20, 2020.4.5.2, 2020.4.5.1, 2020.4.5, 2019.11.28, 2019.9.11, 2019.6.16, 2019.3.9, 2018.11.29, 2018.10.15, 2018.8.24, 2018.8.13, 2018.4.16, 2018.1.18, 2017.11.5, 2017.7.27.1, 2017.7.27, 2017.4.17, 2017.1.23, 2016.9.26, 2016.8.31, 2016.8.8, 2016.8.2, 2016.2.28, 2015.11.20.1, 2015.11.20, 2015.9.6.2, 2015.9.6.1, 2015.9.6, 2015.4.28, 14.5.14, 1.0.1, 1.0.0, 0.0.8, 0.0.7, 0.0.6, 0.0.5, 0.0.4, 0.0.3, 0.0.2, 0.0.1

Install version from a year ago

(demo-env) pip: pip install --min-release-age=365 certifi
Collecting certifi
  Using cached certifi-2025.1.31-py3-none-any.whl.metadata (2.5 kB)
Using cached certifi-2025.1.31-py3-none-any.whl (166 kB)
Installing collected packages: certifi
Successfully installed certifi-2025.1.31
(demo-env) pip: pip show certifi | grep "Version:"
Version: 2025.1.31

Uninstall and install version from 10 days ago

(demo-env) pip: pip uninstall -y certifi
Found existing installation: certifi 2025.1.31
Uninstalling certifi-2025.1.31:
  Successfully uninstalled certifi-2025.1.31
(demo-env) pip: pip install --min-release-age=10 certifi
Collecting certifi
  Using cached certifi-2026.1.4-py3-none-any.whl.metadata (2.5 kB)
Using cached certifi-2026.1.4-py3-none-any.whl (152 kB)
Installing collected packages: certifi
Successfully installed certifi-2026.1.4

Uninstall and install latest version

(demo-env) pip: pip uninstall -y certifi
Found existing installation: certifi 2026.1.4
Uninstalling certifi-2026.1.4:
  Successfully uninstalled certifi-2026.1.4
(demo-env) pip: pip install certifi
Collecting certifi
  Using cached certifi-2026.2.25-py3-none-any.whl.metadata (2.5 kB)
Using cached certifi-2026.2.25-py3-none-any.whl (153 kB)
Installing collected packages: certifi
Successfully installed certifi-2026.2.25

@notatallshaw
Copy link
Member

Before I review the code can you expand on the design choices you made here given the discussion in #13674, let us know if you purposely made a choice and why, or if it was arbitrary:

  • Why did you create a new option rather than using the existing --uploaded-prior-to option?
  • Why did you create new units rather than using ISO 8601 duration and/or uv's friendly units? Do the units you use have prior art?

@nmanthey
Copy link
Author

nmanthey commented Mar 5, 2026

Thanks. I answered the questions below. I can see how this could be simplified, and look forward to feedback.

Why did you create a new option rather than using the existing --uploaded-prior-to option?

The parameter name was chosen from the (p)npm tool for JS: --min-release-age 2, where plain integer translates to days. I would like to have it consistent across tools, to make it simple for users. --uploaded-prior-to maps more to the --before, and I related both to an absolute time stamp.

Why did you create new units

The units are inspired by the "friendly" duration from "uv". The pnpm tool also has a minimumReleaseAge. While npm uses days as unit, pnpm uses to minutes.

To make the input more human readable, and to support different time precision, I started with the user friendly units. I am not sure whether many users would like the ISO duration that is discussed in #13674. npm has several pull requests that have a simple unit.

@sethmlarson
Copy link
Contributor

sethmlarson commented Mar 5, 2026

I recommend reading to the end of #13674, there is a lot of design discussion there and seems like we were heading towards consensus about what to support. I don't think we should consider JS or other ecosystems above the Python ecosystem, so going forward with the option pip has selected and a subset of the format(s) that uv has chosen seems like it'd be the most consistent experience for Python users.

@nmanthey
Copy link
Author

nmanthey commented Mar 9, 2026

In the issue, to me there is no consensus on the details yet. I asked in that issue as well.

The parameter supports plain integers as days, or units similar to uv's "friendly" format. I decided not to overload "--uploaded-prior-to", as that parameter implies an absolute time stamp and I find "--uploaded-prior-to=3days" misleading.

It is not clear to me whether you already agreed on overloading "--uploaded-prior-to" or agree to have a separate parameter. I can change the parameter name to "exclude-newer", if consistency to "uv" is more important than to npm.

For the implementation, could we go with an incremental approach and add the parameter with an integer unit for e.g. days first, and later add support for strings with further units based on user feedback?

@nmanthey
Copy link
Author

I changed the logic to extend the existing parameter --uploaded-prior-to to support relative time as well.

Testing Done

Using pip with the --uploaded-prior-to and the value given in the test case, to then show the installed version of the certifi package.

=== Test 1: P7D (7 days) ===
Successfully installed certifi-2026.2.25
Version: 2026.2.25

=== Test 2: P365D (365 days) ===
Successfully installed certifi-2025.1.31
Version: 2025.1.31

=== Test 3: PT720H (30 days in hours) ===
Successfully installed certifi-2026.1.4
Version: 2026.1.4

=== Test 4: Absolute date (existing behavior) ===
Successfully installed certifi-2025.4.26
Version: 2025.4.26

=== Test 5: No filter (latest) ===
Successfully installed certifi-2026.2.25
Version: 2026.2.25

Copy link
Member

@notatallshaw notatallshaw left a comment

Choose a reason for hiding this comment

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

This needs a section in the user guide to carefully reflect how to communicate this following the discussion: #13674

It would come in the "Filtering By Upload Time" section https://pip.pypa.io/en/stable/user_guide/#filtering-by-upload-time

# to disambiguate from absolute datetimes. Only whole days are supported;
# the format may be extended to more of the ISO 8601 duration syntax in
# the future if a real need is presented.
match = re.match(r"^P(\d+)D$", value, re.IGNORECASE)
Copy link
Member

Choose a reason for hiding this comment

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

I believe ISO-8601 duration designators are uppercase only, please don't make this case-insensitive.

As a user, I want to be able to set a relative time to specify the
package versions to update.

This commit extends the --uploaded-prior-to option to accept relative
time spans in ISO format for duration in days (e.g., 'P3D').

The callback parses the given string into a time duration, and next
computes and absolute timestamp. Then, we use the logic already present
in uploaded_prior_to to process the absolute time. Unit tests are
extended accordingly.

Signed-off-by: Norbert Manthey <nmanthey@amazon.de>
Add towncrier news fragment for issue pypa#13674.
@nmanthey
Copy link
Author

I dropped the support for lower case letters, and adapted the unit tests accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants