can poetry be used by library developers / maintainers, e.g. to declare abstract dependencies? #3757
Replies: 12 comments 24 replies
-
Using For library requirements, it's a little better, because pip can install older versions. But since Pip 20.3's new solver, it now matters if you over constrain - so it's time for Poetry's default to become Let's use an upcoming example. Many libraries depend on click. Usually not even for the functionality they provide as a library. Let's say a few of them (at least two) follow Poetry's recommendation and use If, however, Click 8 does happen to break something unforeseen (as minor / patch versions can break things to; it's just about as common to break something on accident as to break it on purpose in an established library), and no libraries put Looking at well designed poetry libraries, like @willmcgugan's rich, I see the |
Beta Was this translation helpful? Give feedback.
-
Thank you, Henry. I agree that one mistake I made, which is something I should have known as a library developer, was to pin my dependencies to the major version. Although in my defense I did it unthinkingly by following the defaults suggested by But even if that were not the case, another issue here is the solver being strict and refusing to let me install anything that specifies Python ">=3.x, <4.0" because I myself have only specified Python ">=3.x" (without the "<4.0"). for an example of someone else facing the same issue, see: |
Beta Was this translation helpful? Give feedback.
-
I'm curious about this:
Why do you think this? I think Python versions close to semver. 3.0 introduced breaking changes from 2.x. I think Python would only go to 4.0 if it introduced breaking changes. |
Beta Was this translation helpful? Give feedback.
-
A) The Python devs clearly state that 4.0 (if ever introduced) will not contain breaking changes like 3.0 did, that will not ever happen again. I think the line above is pretty much from the devs. Personally, I think it's likely to happen if the Limited API needs changes; that's tied to "all subsequent 3.x" versions (and might be the one case where "<4" is valid - but as I've mentioned, Requires-Python doesn't handle this correctly - you can't install Python based on your requirements! Also, Limited API can't be used by poetry users (or pretty much anyone, I've only seen one package successfully use it). B) Every release contains breaking changes. 3.10 has a bunch, like changing the default for annotations to strings, and removing a bunch if Python 2 compatibility stuff. 3.12 will remove distutils. Etc. If you can run Python 3.X without warnings with the -Xd flag, you probably can upgrade a single point version safely. These breaking changes are not usually out-of-the-blue if you follow Python, you might be able to keep updating for years. C) Even with perfect SerVer, a breaking change may not break your code. For a stable library or Python, the "breakage" likely does not affect light to medium weight users of the code. |
Beta Was this translation helpful? Give feedback.
-
Thank you @nedbat -- I'm for sure not a core Python dev but what @henryiii matches similar remarks I saw on Twitter You are totally right that of course there were breaking changes going from 2.0 to 3.0. |
Beta Was this translation helpful? Give feedback.
-
One thing the core devs haven't said: what would cause them to change the version number to 4.0? My guess is that the public perception of 4.0 would be an assumption of "3.0-like" changes, and the resulting negative PR impact would mean that we aren't going to have a 4.0. But that's just my guess. |
Beta Was this translation helpful? Give feedback.
-
They basically have said - nothing that they know of. I think the Limited API might one thing. That's besides the point, though - this is the wrong way to use the Requires-Python metadata. If you suddenly realize you don't support 3.10, you should not set <3.10 here. This will not solve by installing an older Python version, it will not produce a pretty error message like "the current version of Python is not supported", instead, it will look for an older release of your software that doesn't list <3.10, then install that, because this feature was designed around dropping Python versions, not eventually supporting them. For libraries, it's better, since that is part of the standard solver; but still should not be over constrained. If you know Click 8.0 breaks your code, if it's your fault, you can write |
Beta Was this translation helpful? Give feedback.
-
PS: Originally, they said things like the string annotations would do it. But that didn't fly, and it was happened in 3.10 instead. Honestly, this is more consistent with historical changes too. New features in the 2.x series like NumPy also follows this method. Changes have 3 versions of warnings (IIRC) before being made breaking. |
Beta Was this translation helpful? Give feedback.
-
Hello everyone, there are different aspects discussed here, that are (more or less) unrelated to each other. The first one is, that The other aspect discussed in this issue, is about the default python version constraint poetry generates. As other stated out, python itself doesn't follow SemVer. But IMO this is not an argument for not defining an upper boundary for the supported python versions. Breaking changes can already occur between minor versions in python. So if a package author haven't test against all available minor versions and don't like to bet, that its package will work in other or future python release, it might be a good idea to restrict the python version constraint to the version they tested. On the other hand, defining the python version constraint in a to small area, makes it hard to resolve dependency if it's a library used in other project. Saying this I believe, the default behavior by poetry, to use the caret operator for python version constraint, is a good compromise. No one knows yet if there ever will be a python version 4 and how it differs from python3. But if there ever will be one, there's a good chance that it will break many things. However my opinion about poetry's default here is not set in stone, but I believe it is a good choice. Furthermore the default is not hide anywhere and it is the responsibility of the package maintainer to review its fin swimmer PS: I will move this issue to the discussion board. |
Beta Was this translation helpful? Give feedback.
-
Another aspect discussed here, I missed in my first reply is, using the caret requirement for dependencies by default. IMO this is a very good choice and should not be changed. SemVer is widely used, even if it has its problems in the real world. It's the best predictor we have, whether a version bump may change our library or not. |
Beta Was this translation helpful? Give feedback.
-
Hi @finswimmer thank you for taking the time to respond. You are right there are different aspects to the issue I raised. Now that you've moved this to Discussions (thank you), let me try to state everything more clearly. Many of the points you make about dependency resolution and SemVer are very valid for app developers, who primarily want their app to be stable in production. Although reasonable people can disagree about the benefits of SemVer, as outlined in those posts from Hynek Schlawak and Brett Cannon. But the same points do not make sense for library developers. As a library developer, I want to define my "abstract dependencies" in the I thought that Just to be extra clear, my current understanding is that a library developer should not pin their dependencies, including Python, for several reasons. For example, here on this Python Packaging Authority page it states:
https://packaging.python.org/discussions/install-requires-vs-requirements/#install-requires I see that It's also the case that a library developer never wants to upper-bound the required version of Python, I think, as @henryiii described above.
I don't understand all the nuances of that, but for any library developer reading this: please do be aware of issues you might run into if you switch to So: That's also exactly what @bryevdv wants to do here: It seems like this is still not a possibility, and the current standard, which is not explicitly written down anywhere, is:
I think one reason why this gets confusing is that @taion says something similar here where he says
To be clear, I'm not sure what that section would be or how it should be named, and I think the proposal described in that issue for As a final point related to this, it is possible to declare Hope that summary helps anyone else considering similar questions, and happy to edit + hear feedback |
Beta Was this translation helpful? Give feedback.
-
https://iscinumpy.dev/post/bound-version-constraints/ and https://iscinumpy.dev/post/poetry-versions/ are followups to this discussion, FYI. |
Beta Was this translation helpful? Give feedback.
-
Feature Request
Hi, I do not find any issues discussing this, so sorry in advance if it's been hashed out before.
My experience with Poetry has been that it's a great tool for development--much cleaner than using a
setup.py
file, that's for sure. But I don't understand some of the defaults for dependencies.In particular, I'm confused about why the default is to pin to major versions, for both Python itself and for a project's dependencies.
Especially in the case of Python itself, this can cause problems for new users that switch to Poetry for development.
The default now is to set the Python requirement to
>=3.y.z, <4.0
, where the important part is the<4.0
.New users will be frustrated when they find that, by using this default, they will suddenly be forcing people to install older versions of things, because the previous
setup.py
file they used for development probably did not specify "<4.0" for PYTHON_REQUIRES.This is the situation I am in now.
Unlike you devs, I am not smart enough to understand how the
pip
or poetry solvers work.But I am smart enough to know that I can longer install one of my own libraries, according to your solver, because:
Pretty sure what's happening to me is what's described here:
https://mobile.twitter.com/HenrySchreiner3/status/1362183452343296004
So
poetry
is now demanding that I obey semver for Python itself, basically.i.e, I can "fix" this if I go back to including
<4.0
for the package I'm developing now.But I don't want to, because I don't want anyone depending on my library to be "trapped" the same way I am now.
I'm fine with "opinionated" libraries, but in this case, I'm not aware of any good reason to hold the opinion that my required Python should take semver into consideration. In particular, for Python, there's no reason to assume that 4.0 will be drastically different from 3.x.
Similarly, the default for libraries is to use "^" to pin to a major version, presumably under the assumption that it's somehow safer.
But this can have unintended consequences, as discussed here:
https://hynek.me/articles/semver-will-not-save-you/
Especially for a lot of data science libraries that stay in "Perpetual ZeroVer" for extended periods of development, this is not a great assumption anyway.
See also this blog post about why semver often doesn't work in practice for Python: https://snarky.ca/why-i-dont-like-semver/
If you really want people to switch to your very helpful tool, please consider some defaults that will not come back to bite people without them knowing it, and are more in keeping with expectations in the community.
In short, why not just always use ">=" by default, for Python and for dependencies?
If the answer is "because semver", I hope you will consider what's in the posts I linked above.
Beta Was this translation helpful? Give feedback.
All reactions