@@ -217,18 +217,52 @@ def build_value(cls, string):
217217 """
218218 Return a packaging.version.LegacyVersion or packaging.version.Version
219219 """
220- return packaging_version . Version (string )
220+ return cls . _coerce_pep440 (string )
221221
222222 @classmethod
223223 def is_valid (cls , string ):
224224 try :
225225 # Note: we consider only modern pep440 versions as valid. legacy
226226 # will fail validation for now.
227- cls .build_value (string )
227+ cls ._coerce_pep440 (string )
228228 return True
229229 except packaging_version .InvalidVersion :
230230 return False
231231
232+ @classmethod
233+ def _coerce_pep440 (cls , string ):
234+ """
235+ Return a packaging.version.Version, coercing a limited set of
236+ legacy PyPI version forms that use '-' for a local version segment.
237+ """
238+ try :
239+ return packaging_version .Version (string )
240+ except packaging_version .InvalidVersion :
241+ normalized = cls ._normalize_legacy_local (string )
242+ if normalized :
243+ return packaging_version .Version (normalized )
244+ raise
245+
246+ @classmethod
247+ def _normalize_legacy_local (cls , string ):
248+ """
249+ Normalize legacy local versions like "2.0.1rc2-git" to
250+ PEP 440-compatible "2.0.1rc2+git" when safe.
251+ """
252+ if not string or "+" in string or "-" not in string :
253+ return None
254+
255+ base , local = string .rsplit ("-" , 1 )
256+ if not local or not local [0 ].isalpha ():
257+ return None
258+
259+ candidate = f"{ base } +{ local } "
260+ try :
261+ packaging_version .Version (candidate )
262+ except packaging_version .InvalidVersion :
263+ return None
264+ return candidate
265+
232266
233267class EnhancedSemanticVersion (semantic_version .Version ):
234268 @property
0 commit comments