diff options
| author | Anderson Bravalheri <andersonbravalheri@gmail.com> | 2023-03-06 09:50:30 +0000 |
|---|---|---|
| committer | Anderson Bravalheri <andersonbravalheri@gmail.com> | 2023-03-06 09:50:30 +0000 |
| commit | 1640731114734043b8500d211366fc941b741f67 (patch) | |
| tree | eacc71180c31cdb3f6e8899b412f84e9cc7bcde3 /pkg_resources | |
| parent | 330035d26ab236c8558afcd7961c3475754db8b6 (diff) | |
| parent | 94b583b0807aa0b798e6dd9903019415a6de3e67 (diff) | |
| download | python-setuptools-git-1640731114734043b8500d211366fc941b741f67.tar.gz | |
Make pkg_resources more forgiving of non-compliant versions (#3839)
Diffstat (limited to 'pkg_resources')
| -rw-r--r-- | pkg_resources/__init__.py | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index e08d17f4..a73a1df3 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -121,6 +121,9 @@ _namespace_packages = None warnings.warn("pkg_resources is deprecated as an API", DeprecationWarning) +_PEP440_FALLBACK = re.compile(r"^v?(?P<safe>(?:[0-9]+!)?[0-9]+(?:\.[0-9]+)*)", re.I) + + class PEP440Warning(RuntimeWarning): """ Used when there is an issue with a version or specifier not complying with @@ -1396,6 +1399,38 @@ def safe_version(version): return re.sub('[^A-Za-z0-9.]+', '-', version) +def _forgiving_version(version): + """Fallback when ``safe_version`` is not safe enough + >>> parse_version(_forgiving_version('0.23ubuntu1')) + <Version('0.23.dev0+sanitized.ubuntu1')> + >>> parse_version(_forgiving_version('0.23-')) + <Version('0.23.dev0+sanitized')> + >>> parse_version(_forgiving_version('0.-_')) + <Version('0.dev0+sanitized')> + >>> parse_version(_forgiving_version('42.+?1')) + <Version('42.dev0+sanitized.1')> + >>> parse_version(_forgiving_version('hello world')) + <Version('0.dev0+sanitized.hello.world')> + """ + version = version.replace(' ', '.') + match = _PEP440_FALLBACK.search(version) + if match: + safe = match["safe"] + rest = version[len(safe):] + else: + safe = "0" + rest = version + local = f"sanitized.{_safe_segment(rest)}".strip(".") + return f"{safe}.dev0+{local}" + + +def _safe_segment(segment): + """Convert an arbitrary string into a safe segment""" + segment = re.sub('[^A-Za-z0-9.]+', '-', segment) + segment = re.sub('-[^A-Za-z0-9]+', '-', segment) + return re.sub(r'\.[^A-Za-z0-9]+', '.', segment).strip(".-") + + def safe_extra(extra): """Convert an arbitrary string to a standard 'extra' name @@ -2642,7 +2677,7 @@ class Distribution: @property def hashcmp(self): return ( - self.parsed_version, + self._forgiving_parsed_version, self.precedence, self.key, self.location, @@ -2701,6 +2736,32 @@ class Distribution: return self._parsed_version @property + def _forgiving_parsed_version(self): + try: + return self.parsed_version + except packaging.version.InvalidVersion as ex: + self._parsed_version = parse_version(_forgiving_version(self.version)) + + notes = "\n".join(getattr(ex, "__notes__", [])) # PEP 678 + msg = f"""!!\n\n + ************************************************************************* + {str(ex)}\n{notes} + + This is a long overdue deprecation. + For the time being, `pkg_resources` will use `{self._parsed_version}` + as a replacement to avoid breaking existing environments, + but no future compatibility is guaranteed. + + If you maintain package {self.project_name} you should implement + the relevant changes to adequate the project to PEP 440 immediately. + ************************************************************************* + \n\n!! + """ + warnings.warn(msg, DeprecationWarning) + + return self._parsed_version + + @property def version(self): try: return self._version |
