summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClark Boylan <clark.boylan@gmail.com>2019-05-29 09:39:59 -0700
committerDaniel Bengtsson <dbengt@redhat.com>2022-03-01 11:02:30 +0100
commit5c8461013f8b65f88d047ec71c92ca11594fe6cf (patch)
tree9ca1b4a0c9cb01eb53dbedf36c33c2ede3c9f48d
parent97e7a60f426e5701e175b1eca8327ea08bf8d7ff (diff)
downloadpbr-5c8461013f8b65f88d047ec71c92ca11594fe6cf.tar.gz
Use importlib-metadata for runtime package version lookups
We were using pkg_resources for runtime package version lookups but pkg_resources incurs a pretty significant cost to use it in thise way (because it scans all installed packages on disk and sorts them). importlib-metadata is the way of the future (part of stdlib in python3.8) and is supposed to be significantly more performant. Replace our use of pkg_resources for runtime version lookups with importlib-metadata so that we are both quicker and future proof. Note that this doesn't handle the problem of no pbr deps yet. We will probably end up needing to vendor importlib-metadata in pbr or something similar. Change-Id: Ife68089d997b266adb37f18e226f49bdd67766fc
-rw-r--r--pbr/version.py41
1 files changed, 37 insertions, 4 deletions
diff --git a/pbr/version.py b/pbr/version.py
index 46c6020..658928e 100644
--- a/pbr/version.py
+++ b/pbr/version.py
@@ -15,13 +15,19 @@
# under the License.
"""
-Utilities for consuming the version from pkg_resources.
+Utilities for consuming the version from importlib-metadata.
"""
import itertools
import operator
import sys
+try:
+ import importlib_metadata
+ use_importlib = True
+except ImportError:
+ use_importlib = False
+
def _is_int(string):
try:
@@ -431,12 +437,15 @@ class VersionInfo(object):
"""Obtain a version from pkg_resources or setup-time logic if missing.
This will try to get the version of the package from the pkg_resources
+ This will try to get the version of the package from the
record associated with the package, and if there is no such record
+ importlib_metadata record associated with the package, and if there
falls back to the logic sdist would use.
+
+ is no such record falls back to the logic sdist would use.
"""
- # Lazy import because pkg_resources is costly to import so defer until
- # we absolutely need it.
import pkg_resources
+
try:
requirement = pkg_resources.Requirement.parse(self.package)
provider = pkg_resources.get_provider(requirement)
@@ -447,6 +456,25 @@ class VersionInfo(object):
# installed into anything. Revert to setup-time logic.
from pbr import packaging
result_string = packaging.get_version(self.package)
+
+ return SemanticVersion.from_pip_string(result_string)
+
+ def _get_version_from_importlib_metadata(self):
+ """Obtain a version from importlib or setup-time logic if missing.
+
+ This will try to get the version of the package from the
+ importlib_metadata record associated with the package, and if there
+ is no such record falls back to the logic sdist would use.
+ """
+ try:
+ distribution = importlib_metadata.distribution(self.package)
+ result_string = distribution.version
+ except importlib_metadata.PackageNotFoundError:
+ # The most likely cause for this is running tests in a tree
+ # produced from a tarball where the package itself has not been
+ # installed into anything. Revert to setup-time logic.
+ from pbr import packaging
+ result_string = packaging.get_version(self.package)
return SemanticVersion.from_pip_string(result_string)
def release_string(self):
@@ -459,7 +487,12 @@ class VersionInfo(object):
def semantic_version(self):
"""Return the SemanticVersion object for this version."""
if self._semantic is None:
- self._semantic = self._get_version_from_pkg_resources()
+ # TODO(damami): simplify this once Python 3.8 is the oldest
+ # we support
+ if use_importlib:
+ self._semantic = self._get_version_from_importlib_metadata()
+ else:
+ self._semantic = self._get_version_from_pkg_resources()
return self._semantic
def version_string(self):