Skip to content

Clarify recommended use of requires-python #520

Closed

Description

@ucodery

I realize this PR was opened just to add new guidance, but we should really update this paragraph to specify that, even with lower bounds, requires-python is not necessary for every package and is only something to be used when the author has confidence there are versions of Python the package versions Must Not be installed for.

Originally posted by @ucodery in #501 (comment)

Activity

  1. ucodery commented on Jun 10, 2025

    @ucodery
    CollaboratorAuthor

    @lwasser to address your reply made in the originating PR, I am personally against adding requires-python until the author has some confirmed knowledge that some version of Python is incompatible with the code they are writing. And I would like the upper bound option to either not be mentioned, or explicitly advocated against.
    With almost 14 releases of Python3, there is often some lower bound for which some freshly written Python code is incompatible, but figuring out exactly what that version is is not always easy, and possibly unfindable for a more novice Pythonista. I am saying if it is known, go ahead and write it down. But not knowing and guessing, or putting the current development version down as the limit, because it is there, is actively harmful to the packaging ecosystem.

    Even when working with highly experienced package authors, I wouldn't expect a >=3, nor would I even expect that every known lower limit be written out. I think I have a personal rule of thumb that if the lower bound is an EOL version of Python, and the package is a new release not expected to serve legacy code, I don't need to see that bound. Even with EOL support libraries, which I have done many, more than 2 versions behind EOL and I don't really need to see it. For example, async code should all have a >=3.5 limit, even if all other syntax is compatible back to 3.0, but I don't think anyone does this.

    There is a very good post/discussion by Henry about this problem https://discuss.python.org/t/requires-python-upper-limits

  2. sneakers-the-rat commented on Jun 10, 2025

    @sneakers-the-rat
    Contributor

    I totally agree on not adding upper bounds, and also agree on the point made in that thread that "guaranteed to be compatible with" is bad wording in the spec since you can't guarantee anything about future compatibility without knowing what it is.

    I do think that adding a lower bound is good though, even for newbies, for a few reasons. First is sort of a practical/tooling consideration: ruff and other linting tools use the requires-python field to determine which linting rules should apply, which can cause code to accidentally break older versions that are not yet EOL. For example, if you don't have a lower bound below 3.10 and have the UP rules enabled, it will convert all your Union[int, str] to int | str, and then you will break 3.9 by accident. That can be set in the ruff config separately from the package config, but i think it's generally good to set these things in one place rather than making carveouts (because if you have a ruff target of >=3.10 and it breaks running on 3.9, then you should have requires-python >=3.10 because that's a correct lower bound!). That can become an actual problem e.g. if someone is developing with an older version of python like the one that is distributed by their OS - then their linter will be fighting their dev environment, where each time you lint you put the package in a state where you can't run it. the other end of that if you have nothing specified, then ruff will not apply any of those rules, etc.

    Second is that I think that it's much easier to loosen the limits in a later version than it is to tighten them and that is sort of important for newbies. Say you have some package released at version 1.0 that is not compatible e.g. with 3.8 but you don't have requires-python>=3.9. Then say someone raises an issue saying "this isn't compatible with 3.8!" but you don't have the time to fix it, you might then say "sorry we don't support EoL python versions" and release 1.1 that has requires-python>=3.9. Then everyone going to install the package on 3.8 will resolve against the known-broken 1.0 version. If on the other hand you had set a too-tight requires-python>=3.13 in 1.0 and someone raised an issue saying "can u plz lower the bound," then you just release 1.1 that lowers it, then there is no problem.

    I also agree that we shouldn't ask every newbie to go and learn all the lore of version compatibility to set a correct lower bound, but maybe a reasonable recommendation is

    • total newbie: "set the lower bound at the lowest active python version"
    • level above that: "have your CI tests run on all the active python versions. If the lowest bound tests fail, raise the lower bound to the one that passes" (or fix the bugs, but for newbies probably just raise the bound).

    but also no strong feelings. definite no on upper bounds, mild yes on lower bounds.

  3. ucodery commented on Jun 12, 2025

    @ucodery
    CollaboratorAuthor

    Your point on easier to remove a restriction than to add it later is well taken. With PyPI's write-only scheme it is actually impossible to address in some cases, as you mentioned.

    I will still push back a little and say that correcting an overly restrictive version requires that someone notice the failure to install (or maybe just a backtrack!) is a false negative, report that bug, and the author is willing to make the change- for that version which might not be current. This is certainly a plausible scenario and has probably actually happened, but requires a somewhat advanced Python user and author.
    By contrast, never setting the lower version will never give false negatives, that version will alway work with every compatible Python version. Of course, there will be versions it crashes with, but as the package consumer you can adjust you version range to exclude that combination. Importantly, he user has the power to fix their environment immediately and without involving the package maintainers; overly restrictive ranges are very difficult to impossible to fix on your own as a user.

    Also, just my impression here, but I'm not sure asking a total newbie to figure out what is the lowest active python version (on every release because it is a moving target) is that much easier than teaching them the lore of version compatibility. And a CI version matrix is great, but still advanced mojo; still a moving target on every release.

  4. lwasser commented on May 18, 2026

    @lwasser
    Member

    Hi friends. I'm going through and triaging issues now for our sprint and this one - I can't remember the context, but I trust what you two think about requires-python.

    because this content has been updated over time -

    https://www.pyopensci.org/python-package-guide/tutorials/pyproject-toml.html#step-3-specify-python-version-with-requires-python

    What is the call to action here to fix if either of you remembers? i won't add this to the project board until that is clear! My apologies, I can't believe how behind I am on GitHub things.

  5. ucodery commented on May 18, 2026

    @ucodery
    CollaboratorAuthor

    My call to action from this was:

    • remove requires-python as a step in the guide. This makes it seem mandatory, it is not mandatory even for polished projects
    • keep requires-python as a call-out that notes it should be used for known breaking lower-versions
    • don't even mention that it can be used as as range, or as upper-only

    This very much follows the guide on packageing.python.org which buries the upper-version possibility under a strongly-worded footnote.

    For anyone landing here that wants the deep "why", this discuss thread started by Henry covers most everything. IIRC it was the reason for updated wording in the guide too.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions