-
Notifications
You must be signed in to change notification settings - Fork 251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dealing with legacy version parsing functionality being removed #631
Comments
Could you clarify? The warning is emitted when a LegacyVersion is created, so if code checks the return value’s type, a warning would have been emitted when the return value is created in the first place. The reasoning does not make sense to me. |
Maybe a code snippet will help make the issue clearer. To use version = packaging.version.parse(version_string)
# LegacyVersion was removed in packaging 22, but is still returned by
# packing <= 21
LegacyVersion = getattr(packaging.version, "LegacyVersion", type(None))
if isinstance(version, LegacyVersion):
raise ValueError("invalid version: " + version_string) In 22, the first line will raise an error (woot) but in 21 it won't. |
This actually breaks code that seems to make sense:
This doesn't work anymore. It's actually worse than that. I thought this only broke because of the trailing |
parse creates LegacyVersion objects, and thus raises the deprecation warnings. Try running with There was a deprecation period for sure: #321 |
Could we please re-open this? I will try explain the problem in tiny minute detail. Before, in packaging 21, one had to write code like this to parse a version and check that it was a valid version: version = packaging.version.parse(version_string)
if isinstance(version, packaging.version.LegacyVersion):
raise ValueError("invalid version: " + version_string) because The deprecation warning was not triggered, unless the exception case happened, which usually meant that someone had messed up the version number. Whether the deprecation was trigger or not is also somewhat moot since there is no other way to check that the result of parse was a valid non-legacy version. Now in packaging 22, the equivalent code is just: version = packaging.version.parse(version_string) but that will silently accept bad versions in older versions of packaging, so one is left with awful code I resorted to my previous comment. |
Replies like this are super unhelpful. I referenced the PR for #321in my bug report. I explained why the deprecation failed to be run in this sentence:
If this is the reaction of the packaging devs, I won't bother filing bug reports here in the future. |
No, you can do:
|
Sorry, I guess I was a bit too terse there (I was on a train, and I was put off by a statement you made that was untrue; especially after a deprecation period that ran for over an year). Here's a fuller example:
Notice the |
packaging.version.parse
API without deprecation period.LegacyVersion
You could have gotten an error if you had turned on raising an exception for warnings when calling
How so? You specifically said there wasn't a deprecation period and we are simply disagreeing with your sentiment by saying we provided a mechanism that either you didn't happen to know about or chose not to use. Are you specifically upset that Pradyun linked to the issue? You have to understand there are other people reading this issue, so even if you linked to the PR a direct link to the issue is still beneficial to others.
As Pradyun and I are arguing, though, that wasn't required of you to operate that way. Python's deprecation mechanism is the |
I've retitled this to be something that won't annoy me when I revisit this, and reopened it, since that was requested by OP. I sincerely don't think there's anything more we could've done here given that this is a low-level library that can't be spewing out to stdout/stderr and we need to rely on users of this library (which isn't the same as end users) doing their due deligence for dealing with deprecations. If you think there is, please say so without accusing us of not doing anything after we spent a not-insignificant amount of time figuring out how to make this as non-disruptive as possible (go read #321 as well as the PRs it led to, if you wanna see that). |
Perhaps a way to write the code that supports both versions of packaging is something like this: with warnings.catch_warnings():
warnings.filterwarnings("error", "Creating a LegacyVersion", DeprecationWarning)
try:
packaging.version.parse("legacyversion")
except (DeprecationWarning, packaging.version.InvalidVersion):
... |
This could probably be replaced with |
Perhaps what @hodgestar would appreciate is the ability to still run class LegacyVersion(_BaseVersion):
def __init__(self, version):
raise NotImplementedError(...) |
IIUC, You don't need to do all this. Most of this is functionally the same as doing |
Not if your code base needs to support both versions of packaging and raise an exception when a legacy version is provided. |
No, it will raise if given a legacy version, regardless of which version of packaging is being used. Version class has only ever accepted PEP 440 versions. |
Ah, I've missed that. I believe that is the most important bit of information that was perhaps lost in all the other: If you don't want to parse legacy versions, use packaging.version.Version instead of packaging.version.parse. Thanks! |
This is exactly my point -- one can not use |
Aside: Dealing with the pypa projects is super frustrating. This change broke every past release of my package and my I get that people are trying to improve the ecosystem, but breaking packages every few months is painful, and it would be good for the people working in the packaging space to know that pain, even if they decide in the end that it is a pain that has to be born to build a better future. |
Feedback taken. Did you read #631 (comment)? |
Of course. |
@pradyunsg @brettcannon This bug report has done it's job. I've expressed what I wanted to. I don't feel that you understood why the change in behaviour of Thank you for replying and doing your best too. I'll close this issue now and we can all move on with our lives. |
Then you know that I've nearly said this and that I don't know of a better way to handle this. If you think there is, please feel welcome to let us know.
The underlying assumption here is that we're not aware of the pain this can cause to users -- and, honestly, we are. This change has been 8+ years in the making (with ~2 years of that presenting a user-facing warning) where at each step we've been going "ok, what can we do to reduce disruption". We've made changes in the higher-level tools to help flag this to users more explicitly and this low-level library can't do much more than use language features for deprecating things that are due for removal. |
As a concrete suggestion, I think it would have been better to deprecate |
…t it is possible to read property files in a POD - dependency-checker - Fix issue `Bump of packaging-21.3 to packaging-22.0 breaks cyclonedx-python`(CycloneDX/cyclonedx-python#449, pypa/packaging#631) which prevents cyclonedx to generate bom.xml
…t it is possible to read property files in a POD - dependency-checker - Fix issue `Bump of packaging-21.3 to packaging-22.0 breaks cyclonedx-python`(CycloneDX/cyclonedx-python#449, pypa/packaging#631) which prevents cyclonedx to generate bom.xml
…kaging-22.0 breaks cyclonedx-python](CycloneDX/cyclonedx-python#449) on [packaging](pypa/packaging#631) which prevents cyclonedx to generate bom.xml
Oh, I never responded to @ldionne's comment: This broke because "foo-<version>" isn't a valid version -- you should pass in This sort of issues have been a major source of confusion in and around Python packaging, so strings like that are literally why it was important to remove this functionality, and move to a world where such "not a version" strings are not accepted.
vs
|
Summary: As explained in pypa/packaging#631, `packaging v22` completely removes `version.LegacyVersion`. This change breaks `compat.py`. Unfortunately we cannot check for the version of `packaging` inside of `compat.py`, because `version.parse()` used to return a `version.LegacyVersion` in certain instances, but will now throw an error. Until a more robust fix is developed, we will have to lock the version of `packaging<22` to avoid build errors. Reviewed By: peiyizhang Differential Revision: D42275881 fbshipit-source-id: 9eae10b9400efd24b02b2142d219b8a22d16d99e
LegacyVersion
PR #407 dropped
LegacyVersion
, but at the same time it broke the API ofpackaging.version.parse
in a way that makes it very hard to supportparse
from both packaging 21 and 22.In 21 if one called
parse("...")
it would returnLegacyVersion
instead of raising an error. So if code wanted to useparse
but check that the version was correct it has to check whether the returned type wasLegacyVersion
.In 22,
LegacyVersion
is now gone, and an exception is raised instead.The deprecations raised for LegacyVersion were only raised when a LegacyVersion was created, so code that called
parse
and checked the return type didn't raise any warnings.The text was updated successfully, but these errors were encountered: