Skip to content

Commit

Permalink
Use importlib.metadata first to avoid deprecation warnings (#878)
Browse files Browse the repository at this point in the history
* Use importlib.metadata first to avoid deprecation warnings

* Use get distribution name of module before fetching its version

* Add support for Python versions < 3.9

* Fix conditional for packages_distributions

* Linter fixes

* Remove fixture in favor of test skips

---------

Co-authored-by: Lalleh Rafeei <84813886+lrafeei@users.noreply.github.com>
  • Loading branch information
renanivo and lrafeei committed Aug 16, 2023
1 parent dc87bd3 commit 7d76243
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 10 deletions.
26 changes: 17 additions & 9 deletions newrelic/common/package_version_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,23 @@ def int_or_str(value):
def _get_package_version(name):
module = sys.modules.get(name, None)
version = None

# importlib was introduced into the standard library starting in Python3.8.
if "importlib" in sys.modules and hasattr(sys.modules["importlib"], "metadata"):
try:
# In Python3.10+ packages_distribution can be checked for as well
if hasattr(sys.modules["importlib"].metadata, "packages_distributions"): # pylint: disable=E1101
distributions = sys.modules["importlib"].metadata.packages_distributions() # pylint: disable=E1101
distribution_name = distributions.get(name, name)
else:
distribution_name = name

version = sys.modules["importlib"].metadata.version(distribution_name) # pylint: disable=E1101
if version not in NULL_VERSIONS:
return version
except Exception:
pass

for attr in VERSION_ATTRS:
try:
version = getattr(module, attr, None)
Expand All @@ -84,15 +101,6 @@ def _get_package_version(name):
except Exception:
pass

# importlib was introduced into the standard library starting in Python3.8.
if "importlib" in sys.modules and hasattr(sys.modules["importlib"], "metadata"):
try:
version = sys.modules["importlib"].metadata.version(name) # pylint: disable=E1101
if version not in NULL_VERSIONS:
return version
except Exception:
pass

if "pkg_resources" in sys.modules:
try:
version = sys.modules["pkg_resources"].get_distribution(name).version
Expand Down
23 changes: 22 additions & 1 deletion tests/agent_unittests/test_package_version_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,19 @@
get_package_version_tuple,
)

# Notes:
# importlib.metadata was a provisional addition to the std library in PY38 and PY39
# while pkg_resources was deprecated.
# importlib.metadata is no longer provisional in PY310+. It added some attributes
# such as distribution_packages and removed pkg_resources.

IS_PY38_PLUS = sys.version_info[:2] >= (3, 8)
IS_PY310_PLUS = sys.version_info[:2] >= (3,10)
SKIP_IF_NOT_IMPORTLIB_METADATA = pytest.mark.skipif(not IS_PY38_PLUS, reason="importlib.metadata is not supported.")
SKIP_IF_IMPORTLIB_METADATA = pytest.mark.skipif(
IS_PY38_PLUS, reason="importlib.metadata is preferred over pkg_resources."
)
SKIP_IF_NOT_PY310_PLUS = pytest.mark.skipif(not IS_PY310_PLUS, reason="These features were added in 3.10+")


@pytest.fixture(scope="function", autouse=True)
Expand All @@ -38,8 +46,10 @@ def patched_pytest_module(monkeypatch):
monkeypatch.delattr(pytest, attr)

yield pytest



# This test only works on Python 3.7
@SKIP_IF_IMPORTLIB_METADATA
@pytest.mark.parametrize(
"attr,value,expected_value",
(
Expand All @@ -58,6 +68,8 @@ def test_get_package_version(attr, value, expected_value):
delattr(pytest, attr)


# This test only works on Python 3.7
@SKIP_IF_IMPORTLIB_METADATA
def test_skips_version_callables():
# There is no file/module here, so we monkeypatch
# pytest instead for our purposes
Expand All @@ -72,6 +84,8 @@ def test_skips_version_callables():
delattr(pytest, "version_tuple")


# This test only works on Python 3.7
@SKIP_IF_IMPORTLIB_METADATA
@pytest.mark.parametrize(
"attr,value,expected_value",
(
Expand All @@ -97,6 +111,13 @@ def test_importlib_metadata():
assert version not in NULL_VERSIONS, version


@SKIP_IF_NOT_PY310_PLUS
@validate_function_called("importlib.metadata", "packages_distributions")
def test_mapping_import_to_distribution_packages():
version = get_package_version("pytest")
assert version not in NULL_VERSIONS, version


@SKIP_IF_IMPORTLIB_METADATA
@validate_function_called("pkg_resources", "get_distribution")
def test_pkg_resources_metadata():
Expand Down

0 comments on commit 7d76243

Please sign in to comment.