Prefer importlib over pkg_resources
authorJeremy Stanley <fungi@yuggoth.org>
Sat, 23 May 2020 20:11:18 +0000 (20:11 +0000)
committerJeremy Stanley <fungi@yuggoth.org>
Sat, 23 May 2020 20:11:18 +0000 (20:11 +0000)
Since Setuptools pkg_resources library is effectively deprecated in
newer releases, try to use the equivalent importlib.metadata
features and exceptions when they're available.

mudpy/version.py

index 0b4ad79..afe66eb 100644 (file)
@@ -1,20 +1,35 @@
 """Version and diagnostic information for the mudpy engine."""
 
-# Copyright (c) 2018 mudpy authors. Permission to use, copy,
+# Copyright (c) 2018-2020 mudpy authors. Permission to use, copy,
 # modify, and distribute this software is granted under terms
 # provided in the LICENSE file distributed with this software.
 
 import json
-import pkg_resources
 import sys
 
 
+# TODO(fungi) Clean up once Python 3.6 is the oldest interpreter supported
+if not hasattr(__builtins__, 'ModuleNotFoundError'):
+    ModuleNotFoundError = ImportError
+# TODO(fungi) Clean up once Python 3.8 is the oldest interpreter supported
+try:
+    import importlib.metadata
+    use_importlib = True
+except ModuleNotFoundError:
+    import pkg_resources
+    use_importlib = False
+
+
 class VersionDetail:
 
     """Version detail for a Python package."""
 
     def __init__(self, package):
-        self.project_name = _normalize_project(package.project_name)
+        if use_importlib:
+            project_name = package.metadata.get('Name')
+        else:
+            project_name = package.project_name
+        self.project_name = _normalize_project(project_name)
         version = package.version
         self.version_info = tuple(version.split('.'))
 
@@ -22,13 +37,23 @@ class VersionDetail:
         self.text = "%s %s" % (self.project_name, version)
 
         # Obtain Git commit ID from PBR metadata if present
-        dist = pkg_resources.get_distribution(self.project_name)
+        if use_importlib:
+            dist = importlib.metadata.distribution(self.project_name)
+        else:
+            dist = pkg_resources.get_distribution(self.project_name)
         try:
-            self.git_version = json.loads(
-                dist.get_metadata("pbr.json"))["git_version"]
-            self.text = "%s (%s)" % (self.text, self.git_version)
+            if use_importlib:
+                pbr_metadata = dist.read_text("pbr.json")
+            else:
+                pbr_metadata = dist.get_metadata("pbr.json")
         except (IOError, KeyError):
+            pbr_metadata = None
+        if pbr_metadata:
+            self.git_version = json.loads(pbr_metadata)["git_version"]
+        else:
             self.git_version = None
+        if self.git_version:
+            self.text = "%s (%s)" % (self.text, self.git_version)
 
     def __repr__(self):
         return self.text
@@ -48,15 +73,23 @@ class Versions:
 
         # List of package names for this package's declared dependencies
         requirements = []
-        for package in pkg_resources.get_distribution(project_name).requires():
-            requirements.append(_normalize_project(package.project_name))
+        if use_importlib:
+            for req in importlib.metadata.distribution(project_name).requires:
+                requirements.append(_normalize_project(req))
+        else:
+            for req in pkg_resources.get_distribution(project_name).requires():
+                requirements.append(_normalize_project(req.project_name))
 
         # Accumulators for Python package versions
         self.dependencies = {}
         self.environment = {}
 
         # Loop over all installed packages
-        for package in pkg_resources.working_set:
+        if use_importlib:
+            distributions = importlib.metadata.distributions()
+        else:
+            distributions = pkg_resources.working_set
+        for package in distributions:
             version = VersionDetail(package)
             # Sort packages into the corresponding buckets
             if version.project_name in requirements:
@@ -84,4 +117,7 @@ class Versions:
 
 def _normalize_project(project_name):
     """Convenience function to normalize Python project names."""
-    return pkg_resources.safe_name(project_name).lower()
+    if use_importlib:
+        return project_name.lower()
+    else:
+        return pkg_resources.safe_name(project_name).lower()