Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-opentelemetry-instrumentation for openSUSE:Factory checked in at 2025-06-03 17:51:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-opentelemetry-instrumentation (Old) and /work/SRC/openSUSE:Factory/.python-opentelemetry-instrumentation.new.16005 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-opentelemetry-instrumentation" Tue Jun 3 17:51:28 2025 rev:4 rq:1281748 version:0.54b1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-opentelemetry-instrumentation/python-opentelemetry-instrumentation.changes 2025-02-26 17:19:30.557689055 +0100 +++ /work/SRC/openSUSE:Factory/.python-opentelemetry-instrumentation.new.16005/python-opentelemetry-instrumentation.changes 2025-06-03 17:51:52.025443943 +0200 @@ -1,0 +2,10 @@ +Mon Jun 2 06:13:57 UTC 2025 - Steve Kowalik <steven.kowa...@suse.com> + +- Update to 0.54b1: + * Make auto instrumentation use the same dependency resolver as manual + instrumentation does + * make it simpler to initialize auto-instrumentation programmatically +- Update URL. +- Run the testsuite again. + +------------------------------------------------------------------- Old: ---- opentelemetry_instrumentation-0.51b0.tar.gz New: ---- opentelemetry_instrumentation-0.54b1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-opentelemetry-instrumentation.spec ++++++ --- /var/tmp/diff_new_pack.Onl3Mw/_old 2025-06-03 17:51:52.573466671 +0200 +++ /var/tmp/diff_new_pack.Onl3Mw/_new 2025-06-03 17:51:52.573466671 +0200 @@ -18,19 +18,20 @@ %{?sle15_python_module_pythons} Name: python-opentelemetry-instrumentation -Version: 0.51b0 +Version: 0.54b1 Release: 0 Summary: Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python License: Apache-2.0 -URL: https://github.com/open-telemetry/opentelemetry-python/tree/main/opentelemetry-instrumentation +URL: https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/opentelemetry-instrumentation Source: https://files.pythonhosted.org/packages/source/o/opentelemetry-instrumentation/opentelemetry_instrumentation-%{version}.tar.gz -BuildRequires: %{python_module packaging >= 18.0} +BuildRequires: %{python_module hatchling} BuildRequires: %{python_module pip} -BuildRequires: %{python_module wheel} BuildRequires: python-rpm-macros # SECTION test requirements BuildRequires: %{python_module opentelemetry-api >= 1.4} -BuildRequires: %{python_module hatchling} +BuildRequires: %{python_module opentelemetry-semantic-conventions = %{version}} +BuildRequires: %{python_module opentelemetry-test-utils = %{version}} +BuildRequires: %{python_module packaging >= 18.0} BuildRequires: %{python_module pytest} BuildRequires: %{python_module wrapt >= 1.0.0} # /SECTION @@ -38,6 +39,8 @@ Requires(post): update-alternatives Requires(postun): update-alternatives Requires: python-opentelemetry-api >= 1.4 +Requires: python-opentelemetry-semantic-conventions = %{version} +Requires: python-packaging >= 18.0 Requires: python-wrapt >= 1.0.0 BuildArch: noarch %python_subpackages @@ -57,9 +60,8 @@ %python_clone -a %{buildroot}%{_bindir}/opentelemetry-bootstrap %python_expand %fdupes %{buildroot}%{$python_sitelib} -# Tests disabled because they're not shipped with the sources -#%%check -#%%pytest +%check +%pytest %post %python_install_alternative opentelemetry-instrument opentelemetry-bootstrap ++++++ opentelemetry_instrumentation-0.51b0.tar.gz -> opentelemetry_instrumentation-0.54b1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/PKG-INFO new/opentelemetry_instrumentation-0.54b1/PKG-INFO --- old/opentelemetry_instrumentation-0.51b0/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: opentelemetry-instrumentation -Version: 0.51b0 +Version: 0.54b1 Summary: Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python Project-URL: Homepage, https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/opentelemetry-instrumentation Project-URL: Repository, https://github.com/open-telemetry/opentelemetry-python-contrib @@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.13 Requires-Python: >=3.8 Requires-Dist: opentelemetry-api~=1.4 -Requires-Dist: opentelemetry-semantic-conventions==0.51b0 +Requires-Dist: opentelemetry-semantic-conventions==0.54b1 Requires-Dist: packaging>=18.0 Requires-Dist: wrapt<2.0.0,>=1.0.0 Description-Content-Type: text/x-rst @@ -157,6 +157,19 @@ The above command will configure the global trace provider to use the Random IDs Generator, and then pass ``--port=3000`` to ``flask run``. +Programmatic Auto-instrumentation +--------------------------------- + +:: + + from opentelemetry.instrumentation import auto_instrumentation + auto_instrumentation.initialize() + + +If you are in an environment where you cannot use opentelemetry-instrument to inject auto-instrumentation you can do so programmatically with +the code above. Please note that some instrumentations may require the ``initialize()`` method to be called before the library they +instrument is imported. + References ---------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/README.rst new/opentelemetry_instrumentation-0.54b1/README.rst --- old/opentelemetry_instrumentation-0.51b0/README.rst 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/README.rst 2020-02-02 01:00:00.000000000 +0100 @@ -130,6 +130,19 @@ The above command will configure the global trace provider to use the Random IDs Generator, and then pass ``--port=3000`` to ``flask run``. +Programmatic Auto-instrumentation +--------------------------------- + +:: + + from opentelemetry.instrumentation import auto_instrumentation + auto_instrumentation.initialize() + + +If you are in an environment where you cannot use opentelemetry-instrument to inject auto-instrumentation you can do so programmatically with +the code above. Please note that some instrumentations may require the ``initialize()`` method to be called before the library they +instrument is imported. + References ---------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/pyproject.toml new/opentelemetry_instrumentation-0.54b1/pyproject.toml --- old/opentelemetry_instrumentation-0.51b0/pyproject.toml 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/pyproject.toml 2020-02-02 01:00:00.000000000 +0100 @@ -27,7 +27,7 @@ ] dependencies = [ "opentelemetry-api ~= 1.4", - "opentelemetry-semantic-conventions == 0.51b0", + "opentelemetry-semantic-conventions == 0.54b1", "wrapt >= 1.0.0, < 2.0.0", "packaging >= 18.0", ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/_semconv.py new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/_semconv.py --- old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/_semconv.py 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/_semconv.py 2020-02-02 01:00:00.000000000 +0100 @@ -47,6 +47,43 @@ from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.trace.status import Status, StatusCode +# Values defined in milliseconds +HTTP_DURATION_HISTOGRAM_BUCKETS_OLD = ( + 0.0, + 5.0, + 10.0, + 25.0, + 50.0, + 75.0, + 100.0, + 250.0, + 500.0, + 750.0, + 1000.0, + 2500.0, + 5000.0, + 7500.0, + 10000.0, +) + +# Values defined in seconds +HTTP_DURATION_HISTOGRAM_BUCKETS_NEW = ( + 0.005, + 0.01, + 0.025, + 0.05, + 0.075, + 0.1, + 0.25, + 0.5, + 0.75, + 1, + 2.5, + 5, + 7.5, + 10, +) + # These lists represent attributes for metrics that are currently supported _client_duration_attrs_old = [ @@ -354,7 +391,8 @@ if _report_old(sem_conv_opt_in_mode): set_string_attribute(result, SpanAttributes.HTTP_HOST, host) if _report_new(sem_conv_opt_in_mode): - set_string_attribute(result, CLIENT_ADDRESS, host) + if not result.get(SERVER_ADDRESS): + set_string_attribute(result, SERVER_ADDRESS, host) # net.peer.ip -> net.sock.peer.addr diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py --- old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py 2020-02-02 01:00:00.000000000 +0100 @@ -19,6 +19,12 @@ from re import sub from shutil import which +from opentelemetry.instrumentation.auto_instrumentation._load import ( + _load_configurators, + _load_distro, + _load_instrumentors, +) +from opentelemetry.instrumentation.utils import _python_path_without_directory from opentelemetry.instrumentation.version import __version__ from opentelemetry.util._importlib_metadata import entry_points @@ -110,3 +116,20 @@ executable = which(args.command) execl(executable, executable, *args.command_args) + + +def initialize(): + """Setup auto-instrumentation, called by the sitecustomize module""" + # prevents auto-instrumentation of subprocesses if code execs another python process + if "PYTHONPATH" in environ: + environ["PYTHONPATH"] = _python_path_without_directory( + environ["PYTHONPATH"], dirname(abspath(__file__)), pathsep + ) + + try: + distro = _load_distro() + distro.configure() + _load_configurators() + _load_instrumentors(distro) + except Exception: # pylint: disable=broad-except + _logger.exception("Failed to auto initialize OpenTelemetry") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/auto_instrumentation/_load.py new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/auto_instrumentation/_load.py --- old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/auto_instrumentation/_load.py 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/auto_instrumentation/_load.py 2020-02-02 01:00:00.000000000 +0100 @@ -12,13 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from functools import cached_property from logging import getLogger from os import environ -from opentelemetry.instrumentation.dependencies import ( - get_dist_dependency_conflicts, -) +from opentelemetry.instrumentation.dependencies import DependencyConflictError from opentelemetry.instrumentation.distro import BaseDistro, DefaultDistro from opentelemetry.instrumentation.environment_variables import ( OTEL_PYTHON_CONFIGURATOR, @@ -26,36 +23,11 @@ OTEL_PYTHON_DISTRO, ) from opentelemetry.instrumentation.version import __version__ -from opentelemetry.util._importlib_metadata import ( - EntryPoint, - distributions, - entry_points, -) +from opentelemetry.util._importlib_metadata import entry_points _logger = getLogger(__name__) -class _EntryPointDistFinder: - @cached_property - def _mapping(self): - return { - self._key_for(ep): dist - for dist in distributions() - for ep in dist.entry_points - } - - def dist_for(self, entry_point: EntryPoint): - dist = getattr(entry_point, "dist", None) - if dist: - return dist - - return self._mapping.get(self._key_for(entry_point)) - - @staticmethod - def _key_for(entry_point: EntryPoint): - return f"{entry_point.group}:{entry_point.name}:{entry_point.value}" - - def _load_distro() -> BaseDistro: distro_name = environ.get(OTEL_PYTHON_DISTRO, None) for entry_point in entry_points(group="opentelemetry_distro"): @@ -83,7 +55,6 @@ def _load_instrumentors(distro): package_to_exclude = environ.get(OTEL_PYTHON_DISABLED_INSTRUMENTATIONS, []) - entry_point_finder = _EntryPointDistFinder() if isinstance(package_to_exclude, str): package_to_exclude = package_to_exclude.split(",") # to handle users entering "requests , flask" or "requests, flask" with spaces @@ -100,19 +71,25 @@ continue try: - entry_point_dist = entry_point_finder.dist_for(entry_point) - conflict = get_dist_dependency_conflicts(entry_point_dist) - if conflict: - _logger.debug( - "Skipping instrumentation %s: %s", - entry_point.name, - conflict, - ) - continue - - # tell instrumentation to not run dep checks again as we already did it above - distro.load_instrumentor(entry_point, skip_dep_check=True) + distro.load_instrumentor( + entry_point, raise_exception_on_conflict=True + ) _logger.debug("Instrumented %s", entry_point.name) + except DependencyConflictError as exc: + _logger.debug( + "Skipping instrumentation %s: %s", + entry_point.name, + exc.conflict, + ) + continue + except ModuleNotFoundError as exc: + # ModuleNotFoundError is raised when the library is not installed + # and the instrumentation is not required to be loaded. + # See https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3421 + _logger.debug( + "Skipping instrumentation %s: %s", entry_point.name, exc.msg + ) + continue except ImportError: # in scenarios using the kubernetes operator to do autoinstrumentation some # instrumentors (usually requiring binary extensions) may fail to load diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py --- old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py 2020-02-02 01:00:00.000000000 +0100 @@ -12,33 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from logging import getLogger -from os import environ -from os.path import abspath, dirname, pathsep - -from opentelemetry.instrumentation.auto_instrumentation._load import ( - _load_configurators, - _load_distro, - _load_instrumentors, -) -from opentelemetry.instrumentation.utils import _python_path_without_directory - -logger = getLogger(__name__) - - -def initialize(): - # prevents auto-instrumentation of subprocesses if code execs another python process - environ["PYTHONPATH"] = _python_path_without_directory( - environ["PYTHONPATH"], dirname(abspath(__file__)), pathsep - ) - - try: - distro = _load_distro() - distro.configure() - _load_configurators() - _load_instrumentors(distro) - except Exception: # pylint: disable=broad-except - logger.exception("Failed to auto initialize opentelemetry") - +from opentelemetry.instrumentation.auto_instrumentation import initialize initialize() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/bootstrap_gen.py new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/bootstrap_gen.py --- old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/bootstrap_gen.py 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/bootstrap_gen.py 2020-02-02 01:00:00.000000000 +0100 @@ -18,203 +18,207 @@ libraries = [ { "library": "openai >= 1.26.0", - "instrumentation": "opentelemetry-instrumentation-openai-v2==2.2b0.dev", + "instrumentation": "opentelemetry-instrumentation-openai-v2", }, { "library": "google-cloud-aiplatform >= 1.64", - "instrumentation": "opentelemetry-instrumentation-vertexai==2.1b0.dev", + "instrumentation": "opentelemetry-instrumentation-vertexai>=2.0b0", }, { "library": "aio_pika >= 7.2.0, < 10.0.0", - "instrumentation": "opentelemetry-instrumentation-aio-pika==0.51b0", + "instrumentation": "opentelemetry-instrumentation-aio-pika==0.54b1", }, { "library": "aiohttp ~= 3.0", - "instrumentation": "opentelemetry-instrumentation-aiohttp-client==0.51b0", + "instrumentation": "opentelemetry-instrumentation-aiohttp-client==0.54b1", }, { "library": "aiohttp ~= 3.0", - "instrumentation": "opentelemetry-instrumentation-aiohttp-server==0.51b0", + "instrumentation": "opentelemetry-instrumentation-aiohttp-server==0.54b1", }, { "library": "aiokafka >= 0.8, < 1.0", - "instrumentation": "opentelemetry-instrumentation-aiokafka==0.51b0", + "instrumentation": "opentelemetry-instrumentation-aiokafka==0.54b1", }, { "library": "aiopg >= 0.13.0, < 2.0.0", - "instrumentation": "opentelemetry-instrumentation-aiopg==0.51b0", + "instrumentation": "opentelemetry-instrumentation-aiopg==0.54b1", }, { "library": "asgiref ~= 3.0", - "instrumentation": "opentelemetry-instrumentation-asgi==0.51b0", + "instrumentation": "opentelemetry-instrumentation-asgi==0.54b1", + }, + { + "library": "asyncclick ~= 8.0", + "instrumentation": "opentelemetry-instrumentation-asyncclick==0.54b1", }, { "library": "asyncpg >= 0.12.0", - "instrumentation": "opentelemetry-instrumentation-asyncpg==0.51b0", + "instrumentation": "opentelemetry-instrumentation-asyncpg==0.54b1", }, { "library": "boto~=2.0", - "instrumentation": "opentelemetry-instrumentation-boto==0.51b0", + "instrumentation": "opentelemetry-instrumentation-boto==0.54b1", }, { "library": "boto3 ~= 1.0", - "instrumentation": "opentelemetry-instrumentation-boto3sqs==0.51b0", + "instrumentation": "opentelemetry-instrumentation-boto3sqs==0.54b1", }, { "library": "botocore ~= 1.0", - "instrumentation": "opentelemetry-instrumentation-botocore==0.51b0", + "instrumentation": "opentelemetry-instrumentation-botocore==0.54b1", }, { "library": "cassandra-driver ~= 3.25", - "instrumentation": "opentelemetry-instrumentation-cassandra==0.51b0", + "instrumentation": "opentelemetry-instrumentation-cassandra==0.54b1", }, { "library": "scylla-driver ~= 3.25", - "instrumentation": "opentelemetry-instrumentation-cassandra==0.51b0", + "instrumentation": "opentelemetry-instrumentation-cassandra==0.54b1", }, { "library": "celery >= 4.0, < 6.0", - "instrumentation": "opentelemetry-instrumentation-celery==0.51b0", + "instrumentation": "opentelemetry-instrumentation-celery==0.54b1", }, { "library": "click >= 8.1.3, < 9.0.0", - "instrumentation": "opentelemetry-instrumentation-click==0.51b0", + "instrumentation": "opentelemetry-instrumentation-click==0.54b1", }, { "library": "confluent-kafka >= 1.8.2, <= 2.7.0", - "instrumentation": "opentelemetry-instrumentation-confluent-kafka==0.51b0", + "instrumentation": "opentelemetry-instrumentation-confluent-kafka==0.54b1", }, { "library": "django >= 1.10", - "instrumentation": "opentelemetry-instrumentation-django==0.51b0", + "instrumentation": "opentelemetry-instrumentation-django==0.54b1", }, { "library": "elasticsearch >= 6.0", - "instrumentation": "opentelemetry-instrumentation-elasticsearch==0.51b0", + "instrumentation": "opentelemetry-instrumentation-elasticsearch==0.54b1", }, { "library": "falcon >= 1.4.1, < 5.0.0", - "instrumentation": "opentelemetry-instrumentation-falcon==0.51b0", + "instrumentation": "opentelemetry-instrumentation-falcon==0.54b1", }, { "library": "fastapi ~= 0.58", - "instrumentation": "opentelemetry-instrumentation-fastapi==0.51b0", + "instrumentation": "opentelemetry-instrumentation-fastapi==0.54b1", }, { "library": "flask >= 1.0", - "instrumentation": "opentelemetry-instrumentation-flask==0.51b0", + "instrumentation": "opentelemetry-instrumentation-flask==0.54b1", }, { "library": "grpcio >= 1.42.0", - "instrumentation": "opentelemetry-instrumentation-grpc==0.51b0", + "instrumentation": "opentelemetry-instrumentation-grpc==0.54b1", }, { "library": "httpx >= 0.18.0", - "instrumentation": "opentelemetry-instrumentation-httpx==0.51b0", + "instrumentation": "opentelemetry-instrumentation-httpx==0.54b1", }, { "library": "jinja2 >= 2.7, < 4.0", - "instrumentation": "opentelemetry-instrumentation-jinja2==0.51b0", + "instrumentation": "opentelemetry-instrumentation-jinja2==0.54b1", }, { "library": "kafka-python >= 2.0, < 3.0", - "instrumentation": "opentelemetry-instrumentation-kafka-python==0.51b0", + "instrumentation": "opentelemetry-instrumentation-kafka-python==0.54b1", }, { "library": "kafka-python-ng >= 2.0, < 3.0", - "instrumentation": "opentelemetry-instrumentation-kafka-python==0.51b0", + "instrumentation": "opentelemetry-instrumentation-kafka-python==0.54b1", }, { "library": "mysql-connector-python >= 8.0, < 10.0", - "instrumentation": "opentelemetry-instrumentation-mysql==0.51b0", + "instrumentation": "opentelemetry-instrumentation-mysql==0.54b1", }, { "library": "mysqlclient < 3", - "instrumentation": "opentelemetry-instrumentation-mysqlclient==0.51b0", + "instrumentation": "opentelemetry-instrumentation-mysqlclient==0.54b1", }, { "library": "pika >= 0.12.0", - "instrumentation": "opentelemetry-instrumentation-pika==0.51b0", + "instrumentation": "opentelemetry-instrumentation-pika==0.54b1", }, { "library": "psycopg >= 3.1.0", - "instrumentation": "opentelemetry-instrumentation-psycopg==0.51b0", + "instrumentation": "opentelemetry-instrumentation-psycopg==0.54b1", }, { "library": "psycopg2 >= 2.7.3.1", - "instrumentation": "opentelemetry-instrumentation-psycopg2==0.51b0", + "instrumentation": "opentelemetry-instrumentation-psycopg2==0.54b1", }, { "library": "psycopg2-binary >= 2.7.3.1", - "instrumentation": "opentelemetry-instrumentation-psycopg2==0.51b0", + "instrumentation": "opentelemetry-instrumentation-psycopg2==0.54b1", }, { "library": "pymemcache >= 1.3.5, < 5", - "instrumentation": "opentelemetry-instrumentation-pymemcache==0.51b0", + "instrumentation": "opentelemetry-instrumentation-pymemcache==0.54b1", }, { "library": "pymongo >= 3.1, < 5.0", - "instrumentation": "opentelemetry-instrumentation-pymongo==0.51b0", + "instrumentation": "opentelemetry-instrumentation-pymongo==0.54b1", }, { "library": "pymssql >= 2.1.5, < 3", - "instrumentation": "opentelemetry-instrumentation-pymssql==0.51b0", + "instrumentation": "opentelemetry-instrumentation-pymssql==0.54b1", }, { "library": "PyMySQL < 2", - "instrumentation": "opentelemetry-instrumentation-pymysql==0.51b0", + "instrumentation": "opentelemetry-instrumentation-pymysql==0.54b1", }, { "library": "pyramid >= 1.7", - "instrumentation": "opentelemetry-instrumentation-pyramid==0.51b0", + "instrumentation": "opentelemetry-instrumentation-pyramid==0.54b1", }, { "library": "redis >= 2.6", - "instrumentation": "opentelemetry-instrumentation-redis==0.51b0", + "instrumentation": "opentelemetry-instrumentation-redis==0.54b1", }, { "library": "remoulade >= 0.50", - "instrumentation": "opentelemetry-instrumentation-remoulade==0.51b0", + "instrumentation": "opentelemetry-instrumentation-remoulade==0.54b1", }, { "library": "requests ~= 2.0", - "instrumentation": "opentelemetry-instrumentation-requests==0.51b0", + "instrumentation": "opentelemetry-instrumentation-requests==0.54b1", }, { "library": "sqlalchemy >= 1.0.0, < 2.1.0", - "instrumentation": "opentelemetry-instrumentation-sqlalchemy==0.51b0", + "instrumentation": "opentelemetry-instrumentation-sqlalchemy==0.54b1", }, { - "library": "starlette ~= 0.13.0", - "instrumentation": "opentelemetry-instrumentation-starlette==0.51b0", + "library": "starlette >= 0.13, <0.15", + "instrumentation": "opentelemetry-instrumentation-starlette==0.54b1", }, { "library": "psutil >= 5", - "instrumentation": "opentelemetry-instrumentation-system-metrics==0.51b0", + "instrumentation": "opentelemetry-instrumentation-system-metrics==0.54b1", }, { "library": "tornado >= 5.1.1", - "instrumentation": "opentelemetry-instrumentation-tornado==0.51b0", + "instrumentation": "opentelemetry-instrumentation-tornado==0.54b1", }, { "library": "tortoise-orm >= 0.17.0", - "instrumentation": "opentelemetry-instrumentation-tortoiseorm==0.51b0", + "instrumentation": "opentelemetry-instrumentation-tortoiseorm==0.54b1", }, { "library": "pydantic >= 1.10.2", - "instrumentation": "opentelemetry-instrumentation-tortoiseorm==0.51b0", + "instrumentation": "opentelemetry-instrumentation-tortoiseorm==0.54b1", }, { "library": "urllib3 >= 1.0.0, < 3.0.0", - "instrumentation": "opentelemetry-instrumentation-urllib3==0.51b0", + "instrumentation": "opentelemetry-instrumentation-urllib3==0.54b1", }, ] default_instrumentations = [ - "opentelemetry-instrumentation-asyncio==0.51b0", - "opentelemetry-instrumentation-dbapi==0.51b0", - "opentelemetry-instrumentation-logging==0.51b0", - "opentelemetry-instrumentation-sqlite3==0.51b0", - "opentelemetry-instrumentation-threading==0.51b0", - "opentelemetry-instrumentation-urllib==0.51b0", - "opentelemetry-instrumentation-wsgi==0.51b0", + "opentelemetry-instrumentation-asyncio==0.54b1", + "opentelemetry-instrumentation-dbapi==0.54b1", + "opentelemetry-instrumentation-logging==0.54b1", + "opentelemetry-instrumentation-sqlite3==0.54b1", + "opentelemetry-instrumentation-threading==0.54b1", + "opentelemetry-instrumentation-urllib==0.54b1", + "opentelemetry-instrumentation-wsgi==0.54b1", ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/dependencies.py new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/dependencies.py --- old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/dependencies.py 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/dependencies.py 2020-02-02 01:00:00.000000000 +0100 @@ -20,7 +20,6 @@ from packaging.requirements import InvalidRequirement, Requirement from opentelemetry.util._importlib_metadata import ( - Distribution, PackageNotFoundError, version, ) @@ -40,23 +39,14 @@ return f'DependencyConflict: requested: "{self.required}" but found: "{self.found}"' -def get_dist_dependency_conflicts( - dist: Distribution, -) -> DependencyConflict | None: - instrumentation_deps = [] - extra = "extra" - instruments = "instruments" - instruments_marker = {extra: instruments} - if dist.requires: - for dep in dist.requires: - if extra not in dep or instruments not in dep: - continue - - req = Requirement(dep) - if req.marker.evaluate(instruments_marker): - instrumentation_deps.append(req) +class DependencyConflictError(Exception): + conflict: DependencyConflict - return get_dependency_conflicts(instrumentation_deps) + def __init__(self, conflict: DependencyConflict): + self.conflict = conflict + + def __str__(self): + return str(self.conflict) def get_dependency_conflicts( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/instrumentor.py new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/instrumentor.py --- old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/instrumentor.py 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/instrumentor.py 2020-02-02 01:00:00.000000000 +0100 @@ -28,6 +28,7 @@ ) from opentelemetry.instrumentation.dependencies import ( DependencyConflict, + DependencyConflictError, get_dependency_conflicts, ) @@ -104,9 +105,17 @@ # check if instrumentor has any missing or conflicting dependencies skip_dep_check = kwargs.pop("skip_dep_check", False) + raise_exception_on_conflict = kwargs.pop( + "raise_exception_on_conflict", False + ) if not skip_dep_check: conflict = self._check_dependency_conflicts() if conflict: + # auto-instrumentation path: don't log conflict as error, instead + # let _load_instrumentors handle the exception + if raise_exception_on_conflict: + raise DependencyConflictError(conflict) + # manual instrumentation path: log the conflict as error _LOG.error(conflict) return None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/sqlcommenter_utils.py new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/sqlcommenter_utils.py --- old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/sqlcommenter_utils.py 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/sqlcommenter_utils.py 2020-02-02 01:00:00.000000000 +0100 @@ -23,7 +23,7 @@ meta.update(**_add_framework_tags()) comment = _generate_sql_comment(**meta) sql = sql.rstrip() - if sql[-1] == ";": + if sql.endswith(";"): sql = sql[:-1] + comment + ";" else: sql = sql + comment diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/version.py new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/version.py --- old/opentelemetry_instrumentation-0.51b0/src/opentelemetry/instrumentation/version.py 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/src/opentelemetry/instrumentation/version.py 2020-02-02 01:00:00.000000000 +0100 @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.51b0" +__version__ = "0.54b1" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/tests/auto_instrumentation/test_initialize.py new/opentelemetry_instrumentation-0.54b1/tests/auto_instrumentation/test_initialize.py --- old/opentelemetry_instrumentation-0.51b0/tests/auto_instrumentation/test_initialize.py 1970-01-01 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/tests/auto_instrumentation/test_initialize.py 2020-02-02 01:00:00.000000000 +0100 @@ -0,0 +1,61 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# type: ignore + +from os import environ +from os.path import abspath, dirname, pathsep +from unittest import TestCase +from unittest.mock import patch + +from opentelemetry.instrumentation import auto_instrumentation + +# TODO: convert to assertNoLogs instead of mocking logger when 3.10 is baseline + + +class TestInitialize(TestCase): + auto_instrumentation_path = dirname(abspath(auto_instrumentation.__file__)) + + @patch.dict("os.environ", {}, clear=True) + @patch("opentelemetry.instrumentation.auto_instrumentation._logger") + def test_handles_pythonpath_not_set(self, logger_mock): + auto_instrumentation.initialize() + self.assertNotIn("PYTHONPATH", environ) + logger_mock.exception.assert_not_called() + + @patch.dict("os.environ", {"PYTHONPATH": "."}) + @patch("opentelemetry.instrumentation.auto_instrumentation._logger") + def test_handles_pythonpath_set(self, logger_mock): + auto_instrumentation.initialize() + self.assertEqual(environ["PYTHONPATH"], ".") + logger_mock.exception.assert_not_called() + + @patch.dict( + "os.environ", + {"PYTHONPATH": auto_instrumentation_path + pathsep + "foo"}, + ) + @patch("opentelemetry.instrumentation.auto_instrumentation._logger") + def test_clears_auto_instrumentation_path(self, logger_mock): + auto_instrumentation.initialize() + self.assertEqual(environ["PYTHONPATH"], "foo") + logger_mock.exception.assert_not_called() + + @patch("opentelemetry.instrumentation.auto_instrumentation._logger") + @patch("opentelemetry.instrumentation.auto_instrumentation._load_distro") + def test_handles_exceptions(self, load_distro_mock, logger_mock): + # pylint:disable=no-self-use + load_distro_mock.side_effect = ValueError + auto_instrumentation.initialize() + logger_mock.exception.assert_called_once_with( + "Failed to auto initialize OpenTelemetry" + ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/tests/auto_instrumentation/test_load.py new/opentelemetry_instrumentation-0.54b1/tests/auto_instrumentation/test_load.py --- old/opentelemetry_instrumentation-0.51b0/tests/auto_instrumentation/test_load.py 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/tests/auto_instrumentation/test_load.py 2020-02-02 01:00:00.000000000 +0100 @@ -17,13 +17,16 @@ from unittest.mock import Mock, call, patch from opentelemetry.instrumentation.auto_instrumentation import _load +from opentelemetry.instrumentation.dependencies import ( + DependencyConflict, + DependencyConflictError, +) from opentelemetry.instrumentation.environment_variables import ( OTEL_PYTHON_CONFIGURATOR, OTEL_PYTHON_DISABLED_INSTRUMENTATIONS, OTEL_PYTHON_DISTRO, ) from opentelemetry.instrumentation.version import __version__ -from opentelemetry.util._importlib_metadata import EntryPoint, entry_points class TestLoad(TestCase): @@ -200,17 +203,20 @@ # Confirm method raises exception if it fails to load a distro. self.assertRaises(Exception, _load._load_distro) + @staticmethod + def _instrumentation_failed_to_load_call(entry_point, dependency_conflict): + return call( + "Skipping instrumentation %s: %s", entry_point, dependency_conflict + ) + @patch.dict( "os.environ", {OTEL_PYTHON_DISABLED_INSTRUMENTATIONS: " instr1 , instr3 "}, ) @patch( - "opentelemetry.instrumentation.auto_instrumentation._load.get_dist_dependency_conflicts" - ) - @patch( "opentelemetry.instrumentation.auto_instrumentation._load.entry_points" ) - def test_load_instrumentors(self, iter_mock, dep_mock): + def test_load_instrumentors(self, iter_mock): # Mock opentelemetry_pre_instrument entry points # pylint: disable=too-many-locals pre_ep_mock1 = Mock() @@ -255,8 +261,6 @@ (ep_mock1, ep_mock2, ep_mock3, ep_mock4), (post_ep_mock1, post_ep_mock2), ] - # No dependency conflict - dep_mock.return_value = None _load._load_instrumentors(distro_mock) # All opentelemetry_pre_instrument entry points should be loaded pre_mock1.assert_called_once() @@ -265,8 +269,8 @@ # Only non-disabled instrumentations should be loaded distro_mock.load_instrumentor.assert_has_calls( [ - call(ep_mock2, skip_dep_check=True), - call(ep_mock4, skip_dep_check=True), + call(ep_mock2, raise_exception_on_conflict=True), + call(ep_mock4, raise_exception_on_conflict=True), ] ) self.assertEqual(distro_mock.load_instrumentor.call_count, 2) @@ -278,13 +282,11 @@ "os.environ", {OTEL_PYTHON_DISABLED_INSTRUMENTATIONS: " instr1 , instr3 "}, ) - @patch( - "opentelemetry.instrumentation.auto_instrumentation._load.get_dist_dependency_conflicts" - ) + @patch("opentelemetry.instrumentation.auto_instrumentation._load._logger") @patch( "opentelemetry.instrumentation.auto_instrumentation._load.entry_points" ) - def test_load_instrumentors_dep_conflict(self, iter_mock, dep_mock): # pylint: disable=no-self-use + def test_load_instrumentors_dep_conflict(self, iter_mock, mock_logger): # pylint: disable=no-self-use ep_mock1 = Mock() ep_mock1.name = "instr1" @@ -297,27 +299,39 @@ ep_mock4 = Mock() ep_mock4.name = "instr4" + dependency_conflict = DependencyConflict("1.2.3", None) + distro_mock = Mock() + distro_mock.load_instrumentor.side_effect = [ + None, + DependencyConflictError(dependency_conflict), + ] - iter_mock.return_value = (ep_mock1, ep_mock2, ep_mock3, ep_mock4) # If a dependency conflict is raised, that instrumentation should not be loaded, but others still should. - dep_mock.side_effect = [None, "DependencyConflict"] + # In this case, ep_mock4 will fail to load and ep_mock2 will succeed. (ep_mock1 and ep_mock3 are disabled) + iter_mock.return_value = (ep_mock1, ep_mock2, ep_mock3, ep_mock4) _load._load_instrumentors(distro_mock) distro_mock.load_instrumentor.assert_has_calls( [ - call(ep_mock2, skip_dep_check=True), + call(ep_mock2, raise_exception_on_conflict=True), + call(ep_mock4, raise_exception_on_conflict=True), + ] + ) + assert distro_mock.load_instrumentor.call_count == 2 + mock_logger.debug.assert_has_calls( + [ + self._instrumentation_failed_to_load_call( + ep_mock4.name, dependency_conflict + ) ] ) - distro_mock.load_instrumentor.assert_called_once() - @patch( - "opentelemetry.instrumentation.auto_instrumentation._load.get_dist_dependency_conflicts" - ) + @patch("opentelemetry.instrumentation.auto_instrumentation._load._logger") @patch( "opentelemetry.instrumentation.auto_instrumentation._load.entry_points" ) def test_load_instrumentors_import_error_does_not_stop_everything( - self, iter_mock, dep_mock + self, iter_mock, mock_logger ): ep_mock1 = Mock(name="instr1") ep_mock2 = Mock(name="instr2") @@ -331,25 +345,27 @@ (ep_mock1, ep_mock2), (), ] - dep_mock.return_value = None _load._load_instrumentors(distro_mock) distro_mock.load_instrumentor.assert_has_calls( [ - call(ep_mock1, skip_dep_check=True), - call(ep_mock2, skip_dep_check=True), + call(ep_mock1, raise_exception_on_conflict=True), + call(ep_mock2, raise_exception_on_conflict=True), ] ) self.assertEqual(distro_mock.load_instrumentor.call_count, 2) + mock_logger.exception.assert_any_call( + "Importing of %s failed, skipping it", + ep_mock1.name, + ) + + mock_logger.debug.assert_any_call("Instrumented %s", ep_mock2.name) - @patch( - "opentelemetry.instrumentation.auto_instrumentation._load.get_dist_dependency_conflicts" - ) @patch( "opentelemetry.instrumentation.auto_instrumentation._load.entry_points" ) - def test_load_instrumentors_raises_exception(self, iter_mock, dep_mock): + def test_load_instrumentors_raises_exception(self, iter_mock): ep_mock1 = Mock(name="instr1") ep_mock2 = Mock(name="instr2") @@ -362,48 +378,59 @@ (ep_mock1, ep_mock2), (), ] - dep_mock.return_value = None with self.assertRaises(ValueError): _load._load_instrumentors(distro_mock) distro_mock.load_instrumentor.assert_has_calls( [ - call(ep_mock1, skip_dep_check=True), + call(ep_mock1, raise_exception_on_conflict=True), ] ) self.assertEqual(distro_mock.load_instrumentor.call_count, 1) + @patch("opentelemetry.instrumentation.auto_instrumentation._load._logger") + @patch( + "opentelemetry.instrumentation.auto_instrumentation._load.entry_points" + ) + def test_load_instrumentors_module_not_found_error( + self, iter_mock, mock_logger + ): + ep_mock1 = Mock() + ep_mock1.name = "instr1" + + ep_mock2 = Mock() + ep_mock2.name = "instr2" + + distro_mock = Mock() + + distro_mock.load_instrumentor.side_effect = [ + ModuleNotFoundError("No module named 'fake_module'"), + None, + ] + + iter_mock.side_effect = [(), (ep_mock1, ep_mock2), ()] + + _load._load_instrumentors(distro_mock) + + distro_mock.load_instrumentor.assert_has_calls( + [ + call(ep_mock1, raise_exception_on_conflict=True), + call(ep_mock2, raise_exception_on_conflict=True), + ] + ) + self.assertEqual(distro_mock.load_instrumentor.call_count, 2) + + mock_logger.debug.assert_any_call( + "Skipping instrumentation %s: %s", + "instr1", + "No module named 'fake_module'", + ) + + mock_logger.debug.assert_any_call("Instrumented %s", ep_mock2.name) + def test_load_instrumentors_no_entry_point_mocks(self): distro_mock = Mock() _load._load_instrumentors(distro_mock) # this has no specific assert because it is run for every instrumentation self.assertTrue(distro_mock) - - def test_entry_point_dist_finder(self): - entry_point_finder = _load._EntryPointDistFinder() - self.assertTrue(entry_point_finder._mapping) - entry_point = list( - entry_points(group="opentelemetry_environment_variables") - )[0] - self.assertTrue(entry_point) - self.assertTrue(entry_point.dist) - - # this will not hit cache - entry_point_dist = entry_point_finder.dist_for(entry_point) - self.assertTrue(entry_point_dist) - # dist are not comparable so we are sure we are not hitting the cache - self.assertEqual(entry_point.dist, entry_point_dist) - - # this will hit cache - entry_point_without_dist = EntryPoint( - name=entry_point.name, - group=entry_point.group, - value=entry_point.value, - ) - self.assertIsNone(entry_point_without_dist.dist) - new_entry_point_dist = entry_point_finder.dist_for( - entry_point_without_dist - ) - # dist are not comparable, being truthy is enough - self.assertTrue(new_entry_point_dist) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/tests/auto_instrumentation/test_sitecustomize.py new/opentelemetry_instrumentation-0.54b1/tests/auto_instrumentation/test_sitecustomize.py --- old/opentelemetry_instrumentation-0.51b0/tests/auto_instrumentation/test_sitecustomize.py 1970-01-01 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/tests/auto_instrumentation/test_sitecustomize.py 2020-02-02 01:00:00.000000000 +0100 @@ -0,0 +1,28 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# type: ignore + +from unittest import TestCase +from unittest.mock import patch + + +class TestSiteCustomize(TestCase): + # pylint:disable=import-outside-toplevel,unused-import,no-self-use + @patch("opentelemetry.instrumentation.auto_instrumentation.initialize") + def test_sitecustomize_side_effects(self, initialize_mock): + initialize_mock.assert_not_called() + + import opentelemetry.instrumentation.auto_instrumentation.sitecustomize # NOQA + + initialize_mock.assert_called_once() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/tests/test_dependencies.py new/opentelemetry_instrumentation-0.54b1/tests/test_dependencies.py --- old/opentelemetry_instrumentation-0.51b0/tests/test_dependencies.py 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/tests/test_dependencies.py 2020-02-02 01:00:00.000000000 +0100 @@ -20,10 +20,8 @@ from opentelemetry.instrumentation.dependencies import ( DependencyConflict, get_dependency_conflicts, - get_dist_dependency_conflicts, ) from opentelemetry.test.test_base import TestBase -from opentelemetry.util._importlib_metadata import Distribution class TestDependencyConflicts(TestBase): @@ -64,41 +62,3 @@ str(conflict), f'DependencyConflict: requested: "pytest == 5000" but found: "pytest {pytest.__version__}"', ) - - def test_get_dist_dependency_conflicts(self): - class MockDistribution(Distribution): - def locate_file(self, path): - pass - - def read_text(self, filename): - pass - - @property - def requires(self): - return ['test-pkg ~= 1.0; extra == "instruments"'] - - dist = MockDistribution() - - conflict = get_dist_dependency_conflicts(dist) - self.assertTrue(conflict is not None) - self.assertTrue(isinstance(conflict, DependencyConflict)) - self.assertEqual( - str(conflict), - 'DependencyConflict: requested: "test-pkg~=1.0; extra == "instruments"" but found: "None"', - ) - - def test_get_dist_dependency_conflicts_requires_none(self): - class MockDistribution(Distribution): - def locate_file(self, path): - pass - - def read_text(self, filename): - pass - - @property - def requires(self): - return None - - dist = MockDistribution() - conflict = get_dist_dependency_conflicts(dist) - self.assertTrue(conflict is None) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentelemetry_instrumentation-0.51b0/tests/test_instrumentor.py new/opentelemetry_instrumentation-0.54b1/tests/test_instrumentor.py --- old/opentelemetry_instrumentation-0.51b0/tests/test_instrumentor.py 2020-02-02 01:00:00.000000000 +0100 +++ new/opentelemetry_instrumentation-0.54b1/tests/test_instrumentor.py 2020-02-02 01:00:00.000000000 +0100 @@ -15,7 +15,12 @@ from logging import WARNING from unittest import TestCase +from unittest.mock import patch +from opentelemetry.instrumentation.dependencies import ( + DependencyConflict, + DependencyConflictError, +) from opentelemetry.instrumentation.instrumentor import BaseInstrumentor @@ -48,3 +53,38 @@ def test_singleton(self): self.assertIs(self.Instrumentor(), self.Instrumentor()) + + @patch("opentelemetry.instrumentation.instrumentor._LOG") + @patch( + "opentelemetry.instrumentation.instrumentor.BaseInstrumentor._check_dependency_conflicts" + ) + def test_instrument_missing_dependency_raise( + self, mock__check_dependency_conflicts, mock_logger + ): + instrumentor = self.Instrumentor() + + mock__check_dependency_conflicts.return_value = DependencyConflict( + "missing", "missing" + ) + + self.assertRaises( + DependencyConflictError, + instrumentor.instrument, + raise_exception_on_conflict=True, + ) + mock_logger.error.assert_not_called() + + @patch("opentelemetry.instrumentation.instrumentor._LOG") + @patch( + "opentelemetry.instrumentation.instrumentor.BaseInstrumentor._check_dependency_conflicts" + ) + def test_instrument_missing_dependency_log_error( + self, mock__check_dependency_conflicts, mock_logger + ): + instrumentor = self.Instrumentor() + conflict = DependencyConflict("missing", "missing") + mock__check_dependency_conflicts.return_value = conflict + self.assertIsNone( + instrumentor.instrument(raise_exception_on_conflict=False) + ) + mock_logger.error.assert_any_call(conflict)