Switch from pkg_resources to importlib

setuptools seems to be in the process of deprecating pkg_resources.

Change-Id: I64f1434a5acab99057beb4f397adca85bdcc4ab6
This commit is contained in:
Tim Burke
2023-01-31 12:45:36 -08:00
parent 90f9a479b6
commit bac5d8ff7f
4 changed files with 116 additions and 12 deletions

View File

@@ -18,16 +18,30 @@ import sys
import gettext import gettext
import warnings import warnings
import pkg_resources __version__ = None
# First, try to get our version out of PKG-INFO. If we're installed,
# this'll let us find our version without pulling in pbr. After all, if
# we're installed on a system, we're not in a Git-managed source tree, so
# pbr doesn't really buy us anything.
try: try:
# First, try to get our version out of PKG-INFO. If we're installed, import importlib.metadata
# this'll let us find our version without pulling in pbr. After all, if except ImportError:
# we're installed on a system, we're not in a Git-managed source tree, so # python < 3.8
# pbr doesn't really buy us anything. import pkg_resources
try:
__version__ = __canonical_version__ = pkg_resources.get_provider( __version__ = __canonical_version__ = pkg_resources.get_provider(
pkg_resources.Requirement.parse('swift')).version pkg_resources.Requirement.parse('swift')).version
except pkg_resources.DistributionNotFound: except pkg_resources.DistributionNotFound:
pass
else:
try:
__version__ = __canonical_version__ = importlib.metadata.distribution(
'swift').version
except importlib.metadata.PackageNotFoundError:
pass
if __version__ is None:
# No PKG-INFO? We're probably running from a checkout, then. Let pbr do # No PKG-INFO? We're probably running from a checkout, then. Let pbr do
# its thing to figure out a version number. # its thing to figure out a version number.
import pbr.version import pbr.version
@@ -35,6 +49,7 @@ except pkg_resources.DistributionNotFound:
__version__ = _version_info.release_string() __version__ = _version_info.release_string()
__canonical_version__ = _version_info.version_string() __canonical_version__ = _version_info.version_string()
_localedir = os.environ.get('SWIFT_LOCALEDIR') _localedir = os.environ.get('SWIFT_LOCALEDIR')
_t = gettext.translation('swift', localedir=_localedir, fallback=True) _t = gettext.translation('swift', localedir=_localedir, fallback=True)

View File

@@ -15,7 +15,17 @@
import lxml.etree import lxml.etree
from copy import deepcopy from copy import deepcopy
from pkg_resources import resource_stream # pylint: disable-msg=E0611 try:
# importlib.resources was introduced in py37, but couldn't handle
# resources in subdirectories (which we use); files() added support
from importlib.resources import files
del files
except ImportError:
# python < 3.9
from pkg_resources import resource_stream # pylint: disable-msg=E0611
else:
import importlib.resources
resource_stream = None
import six import six
from swift.common.utils import get_logger from swift.common.utils import get_logger
@@ -70,7 +80,13 @@ def fromstring(text, root_tag=None, logger=None):
# validate XML # validate XML
try: try:
path = 'schema/%s.rng' % camel_to_snake(root_tag) path = 'schema/%s.rng' % camel_to_snake(root_tag)
with resource_stream(__name__, path) as rng: if resource_stream:
# python < 3.9
stream = resource_stream(__name__, path)
else:
stream = importlib.resources.files(
__name__.rsplit('.', 1)[0]).joinpath(path).open('rb')
with stream as rng:
lxml.etree.RelaxNG(file=rng).assertValid(elem) lxml.etree.RelaxNG(file=rng).assertValid(elem)
except IOError as e: except IOError as e:
# Probably, the schema file doesn't exist. # Probably, the schema file doesn't exist.

View File

@@ -58,7 +58,12 @@ import eventlet.debug
import eventlet.greenthread import eventlet.greenthread
import eventlet.patcher import eventlet.patcher
import eventlet.semaphore import eventlet.semaphore
import pkg_resources try:
import importlib.metadata
pkg_resources = None
except ImportError:
# python < 3.8
import pkg_resources
from eventlet import GreenPool, sleep, Timeout from eventlet import GreenPool, sleep, Timeout
from eventlet.event import Event from eventlet.event import Event
from eventlet.green import socket, threading from eventlet.green import socket, threading
@@ -6415,8 +6420,20 @@ def load_pkg_resource(group, uri):
if scheme != 'egg': if scheme != 'egg':
raise TypeError('Unhandled URI scheme: %r' % scheme) raise TypeError('Unhandled URI scheme: %r' % scheme)
if pkg_resources:
# python < 3.8
return pkg_resources.load_entry_point(dist, group, name) return pkg_resources.load_entry_point(dist, group, name)
# May raise importlib.metadata.PackageNotFoundError
meta = importlib.metadata.distribution(dist)
entry_points = [ep for ep in meta.entry_points
if ep.group == group and ep.name == name]
if not entry_points:
raise ImportError("Entry point %r not found" % ((group, name),))
return entry_points[0].load()
class PipeMutex(object): class PipeMutex(object):
""" """

View File

@@ -4801,6 +4801,9 @@ cluster_dfw1 = http://dfw1.host/v1/
'X-Backend-Redirect-Timestamp': '-1'}) 'X-Backend-Redirect-Timestamp': '-1'})
self.assertIn('Invalid timestamp', str(exc)) self.assertIn('Invalid timestamp', str(exc))
@unittest.skipIf(sys.version_info >= (3, 8),
'pkg_resources loading is only available on python 3.7 '
'and earlier')
@mock.patch('pkg_resources.load_entry_point') @mock.patch('pkg_resources.load_entry_point')
def test_load_pkg_resource(self, mock_driver): def test_load_pkg_resource(self, mock_driver):
tests = { tests = {
@@ -4824,6 +4827,59 @@ cluster_dfw1 = http://dfw1.host/v1/
utils.load_pkg_resource(*args) utils.load_pkg_resource(*args)
self.assertEqual("Unhandled URI scheme: 'nog'", str(cm.exception)) self.assertEqual("Unhandled URI scheme: 'nog'", str(cm.exception))
@unittest.skipIf(sys.version_info < (3, 8),
'importlib loading is only available on python 3.8 '
'and later')
@mock.patch('importlib.metadata.distribution')
def test_load_pkg_resource_importlib(self, mock_driver):
import importlib.metadata
repl_obj = object()
ec_obj = object()
other_obj = object()
mock_driver.return_value.entry_points = [
importlib.metadata.EntryPoint(group='swift.diskfile',
name='replication.fs',
value=repl_obj),
importlib.metadata.EntryPoint(group='swift.diskfile',
name='erasure_coding.fs',
value=ec_obj),
importlib.metadata.EntryPoint(group='swift.section',
name='thing.other',
value=other_obj),
]
for ep in mock_driver.return_value.entry_points:
ep.load = lambda ep=ep: ep.value
tests = {
('swift.diskfile', 'egg:swift#replication.fs'): repl_obj,
('swift.diskfile', 'egg:swift#erasure_coding.fs'): ec_obj,
('swift.section', 'egg:swift#thing.other'): other_obj,
('swift.section', 'swift#thing.other'): other_obj,
('swift.section', 'thing.other'): other_obj,
}
for args, expected in tests.items():
self.assertIs(expected, utils.load_pkg_resource(*args))
self.assertEqual(mock_driver.mock_calls, [mock.call('swift')])
mock_driver.reset_mock()
with self.assertRaises(TypeError) as cm:
args = ('swift.diskfile', 'nog:swift#replication.fs')
utils.load_pkg_resource(*args)
self.assertEqual("Unhandled URI scheme: 'nog'", str(cm.exception))
with self.assertRaises(ImportError) as cm:
args = ('swift.diskfile', 'other.fs')
utils.load_pkg_resource(*args)
self.assertEqual(
"Entry point ('swift.diskfile', 'other.fs') not found",
str(cm.exception))
with self.assertRaises(ImportError) as cm:
args = ('swift.missing', 'thing.other')
utils.load_pkg_resource(*args)
self.assertEqual(
"Entry point ('swift.missing', 'thing.other') not found",
str(cm.exception))
@with_tempdir @with_tempdir
def test_systemd_notify(self, tempdir): def test_systemd_notify(self, tempdir):
m_sock = mock.Mock(connect=mock.Mock(), sendall=mock.Mock()) m_sock = mock.Mock(connect=mock.Mock(), sendall=mock.Mock())