From 26214d5945218f91aff3f8d3cc39dc9ffff3eae1 Mon Sep 17 00:00:00 2001 From: Tim Pansino Date: Thu, 9 Nov 2023 15:05:35 -0800 Subject: [PATCH 1/5] Fix package version performance regression --- newrelic/common/package_version_utils.py | 32 +++++++++-------- .../test_package_version_utils.py | 36 +++++++++++++------ 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/newrelic/common/package_version_utils.py b/newrelic/common/package_version_utils.py index 68320b897..aa736a94e 100644 --- a/newrelic/common/package_version_utils.py +++ b/newrelic/common/package_version_utils.py @@ -13,6 +13,7 @@ # limitations under the License. import sys +import warnings try: from functools import cache as _cache_package_versions @@ -110,6 +111,23 @@ def _get_package_version(name): module = sys.modules.get(name, None) version = None + with warnings.catch_warnings(record=True): + for attr in VERSION_ATTRS: + try: + version = getattr(module, attr, None) + + # In certain cases like importlib_metadata.version, version is a callable + # function. + if callable(version): + continue + + # Cast any version specified as a list into a tuple. + version = tuple(version) if isinstance(version, list) else version + if version not in NULL_VERSIONS: + return version + 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: @@ -126,20 +144,6 @@ def _get_package_version(name): except Exception: pass - for attr in VERSION_ATTRS: - try: - version = getattr(module, attr, None) - # In certain cases like importlib_metadata.version, version is a callable - # function. - if callable(version): - continue - # Cast any version specified as a list into a tuple. - version = tuple(version) if isinstance(version, list) else version - 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 diff --git a/tests/agent_unittests/test_package_version_utils.py b/tests/agent_unittests/test_package_version_utils.py index 5ed689ea2..9c5033127 100644 --- a/tests/agent_unittests/test_package_version_utils.py +++ b/tests/agent_unittests/test_package_version_utils.py @@ -13,6 +13,7 @@ # limitations under the License. import sys +import warnings import pytest from testing_support.validators.validate_function_called import validate_function_called @@ -66,10 +67,10 @@ def cleared_package_version_cache(): ("version_tuple", [3, 1, "0b2"], "3.1.0b2"), ), ) -def test_get_package_version(attr, value, expected_value): +def test_get_package_version(monkeypatch, attr, value, expected_value): # There is no file/module here, so we monkeypatch # pytest instead for our purposes - setattr(pytest, attr, value) + monkeypatch.setattr(pytest, attr, value, raising=False) version = get_package_version("pytest") assert version == expected_value delattr(pytest, attr) @@ -77,19 +78,16 @@ def test_get_package_version(attr, value, expected_value): # This test only works on Python 3.7 @SKIP_IF_IMPORTLIB_METADATA -def test_skips_version_callables(): +def test_skips_version_callables(monkeypatch): # There is no file/module here, so we monkeypatch # pytest instead for our purposes - setattr(pytest, "version", lambda x: "1.2.3.4") - setattr(pytest, "version_tuple", [3, 1, "0b2"]) + monkeypatch.setattr(pytest, "version", lambda x: "1.2.3.4", raising=False) + monkeypatch.setattr(pytest, "version_tuple", [3, 1, "0b2"], raising=False) version = get_package_version("pytest") assert version == "3.1.0b2" - delattr(pytest, "version") - delattr(pytest, "version_tuple") - # This test only works on Python 3.7 @SKIP_IF_IMPORTLIB_METADATA @@ -102,10 +100,10 @@ def test_skips_version_callables(): ("version_tuple", [3, 1, "0b2"], (3, 1, "0b2")), ), ) -def test_get_package_version_tuple(attr, value, expected_value): +def test_get_package_version_tuple(monkeypatch, attr, value, expected_value): # There is no file/module here, so we monkeypatch # pytest instead for our purposes - setattr(pytest, attr, value) + monkeypatch.setattr(pytest, attr, value, raising=False) version = get_package_version_tuple("pytest") assert version == expected_value delattr(pytest, attr) @@ -132,10 +130,26 @@ def test_pkg_resources_metadata(): assert version not in NULL_VERSIONS, version +def _getattr_deprecation_warning(attr): + if attr == "__version__": + warnings.warn("Testing deprecation warnings.", DeprecationWarning) + return "3.2.1" + else: + raise NotImplementedError() + + +def test_deprecation_warning_suppression(monkeypatch, recwarn): + # Add fake module to be deleted later + monkeypatch.setattr(pytest, "__getattr__", _getattr_deprecation_warning, raising=False) + + assert get_package_version("pytest") == "3.2.1" + assert not recwarn.list, "Warnings not suppressed." + + def test_version_caching(monkeypatch): # Add fake module to be deleted later sys.modules["mymodule"] = sys.modules["pytest"] - setattr(pytest, "__version__", "1.0.0") + monkeypatch.setattr(pytest, "__version__", "1.0.0", raising=False) version = get_package_version("mymodule") assert version not in NULL_VERSIONS, version From f42bf64532bc5376f6f3594478ec38fcc29dc9a6 Mon Sep 17 00:00:00 2001 From: Hannah Stepanek Date: Fri, 10 Nov 2023 16:47:48 -0800 Subject: [PATCH 2/5] Update tests/agent_unittests/test_package_version_utils.py --- tests/agent_unittests/test_package_version_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/agent_unittests/test_package_version_utils.py b/tests/agent_unittests/test_package_version_utils.py index 9c5033127..92bec3d7b 100644 --- a/tests/agent_unittests/test_package_version_utils.py +++ b/tests/agent_unittests/test_package_version_utils.py @@ -73,7 +73,6 @@ def test_get_package_version(monkeypatch, attr, value, expected_value): monkeypatch.setattr(pytest, attr, value, raising=False) version = get_package_version("pytest") assert version == expected_value - delattr(pytest, attr) # This test only works on Python 3.7 From 05743ba7f80f4ee9fdbf69ef5ef7c4f2b2b1e831 Mon Sep 17 00:00:00 2001 From: Hannah Stepanek Date: Fri, 10 Nov 2023 16:47:53 -0800 Subject: [PATCH 3/5] Update tests/agent_unittests/test_package_version_utils.py --- tests/agent_unittests/test_package_version_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/agent_unittests/test_package_version_utils.py b/tests/agent_unittests/test_package_version_utils.py index 92bec3d7b..43234d689 100644 --- a/tests/agent_unittests/test_package_version_utils.py +++ b/tests/agent_unittests/test_package_version_utils.py @@ -105,7 +105,6 @@ def test_get_package_version_tuple(monkeypatch, attr, value, expected_value): monkeypatch.setattr(pytest, attr, value, raising=False) version = get_package_version_tuple("pytest") assert version == expected_value - delattr(pytest, attr) @SKIP_IF_NOT_IMPORTLIB_METADATA From 8ab1cedcc9b2ad896b4e1f6c942059d77c940ca4 Mon Sep 17 00:00:00 2001 From: Hannah Stepanek Date: Fri, 10 Nov 2023 16:47:59 -0800 Subject: [PATCH 4/5] Update tests/agent_unittests/test_package_version_utils.py --- tests/agent_unittests/test_package_version_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/agent_unittests/test_package_version_utils.py b/tests/agent_unittests/test_package_version_utils.py index 43234d689..ac5838a85 100644 --- a/tests/agent_unittests/test_package_version_utils.py +++ b/tests/agent_unittests/test_package_version_utils.py @@ -141,6 +141,7 @@ def test_deprecation_warning_suppression(monkeypatch, recwarn): monkeypatch.setattr(pytest, "__getattr__", _getattr_deprecation_warning, raising=False) assert get_package_version("pytest") == "3.2.1" + assert not recwarn.list, "Warnings not suppressed." From 6fef4b49f707100fb943bb6a1e6574a2495f9f43 Mon Sep 17 00:00:00 2001 From: Hannah Stepanek Date: Mon, 13 Nov 2023 11:45:31 -0800 Subject: [PATCH 5/5] Skip test in python 2 --- tests/agent_unittests/test_package_version_utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/agent_unittests/test_package_version_utils.py b/tests/agent_unittests/test_package_version_utils.py index ac5838a85..376c8c7e0 100644 --- a/tests/agent_unittests/test_package_version_utils.py +++ b/tests/agent_unittests/test_package_version_utils.py @@ -16,6 +16,7 @@ import warnings import pytest +import six from testing_support.validators.validate_function_called import validate_function_called from newrelic.common.package_version_utils import ( @@ -136,6 +137,7 @@ def _getattr_deprecation_warning(attr): raise NotImplementedError() +@pytest.mark.skipif(six.PY2, reason="Can't add Deprecation in __version__ in Python 2.") def test_deprecation_warning_suppression(monkeypatch, recwarn): # Add fake module to be deleted later monkeypatch.setattr(pytest, "__getattr__", _getattr_deprecation_warning, raising=False)