utils.py 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. # This file is dual licensed under the terms of the Apache License, Version
  2. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
  3. # for complete details.
  4. from __future__ import absolute_import, division, print_function
  5. import re
  6. from ._typing import TYPE_CHECKING, cast
  7. from .version import InvalidVersion, Version
  8. if TYPE_CHECKING: # pragma: no cover
  9. from typing import NewType, Union
  10. NormalizedName = NewType("NormalizedName", str)
  11. _canonicalize_regex = re.compile(r"[-_.]+")
  12. def canonicalize_name(name):
  13. # type: (str) -> NormalizedName
  14. # This is taken from PEP 503.
  15. value = _canonicalize_regex.sub("-", name).lower()
  16. return cast("NormalizedName", value)
  17. def canonicalize_version(_version):
  18. # type: (str) -> Union[Version, str]
  19. """
  20. This is very similar to Version.__str__, but has one subtle difference
  21. with the way it handles the release segment.
  22. """
  23. try:
  24. version = Version(_version)
  25. except InvalidVersion:
  26. # Legacy versions cannot be normalized
  27. return _version
  28. parts = []
  29. # Epoch
  30. if version.epoch != 0:
  31. parts.append("{0}!".format(version.epoch))
  32. # Release segment
  33. # NB: This strips trailing '.0's to normalize
  34. parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in version.release)))
  35. # Pre-release
  36. if version.pre is not None:
  37. parts.append("".join(str(x) for x in version.pre))
  38. # Post-release
  39. if version.post is not None:
  40. parts.append(".post{0}".format(version.post))
  41. # Development release
  42. if version.dev is not None:
  43. parts.append(".dev{0}".format(version.dev))
  44. # Local version segment
  45. if version.local is not None:
  46. parts.append("+{0}".format(version.local))
  47. return "".join(parts)