Skip to content

Commit

Permalink
Make entry_points behave the same across Python versions
Browse files Browse the repository at this point in the history
  • Loading branch information
ocelotl committed Feb 8, 2023
1 parent 209093b commit df15cfb
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 14 deletions.
39 changes: 34 additions & 5 deletions opentelemetry-api/src/opentelemetry/util/_importlib_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,51 @@
# FIXME remove this when support for 3.7 is dropped.
if version_info.minor == 7:
# pylint: disable=import-error
from importlib_metadata import entry_points, version # type: ignore
from importlib_metadata import ( # type: ignore
EntryPoint,
entry_points,
version,
)

# FIXME remove this file when support for 3.9 is dropped.
elif version_info.minor in (8, 9):
# pylint: disable=import-error
from importlib.metadata import EntryPoint
from importlib.metadata import (
entry_points as importlib_metadata_entry_points,
)
from importlib.metadata import version

def entry_points(group: str, name: str): # type: ignore
def entry_points(group: str = None, name: str = None): # type: ignore

if group is None:
return importlib_metadata_entry_points()

if name is None:
return importlib_metadata_entry_points()[group]

for entry_point in importlib_metadata_entry_points()[group]:
if entry_point.name == name:
yield entry_point
return [entry_point]

__all__ = [
"entry_points",
"version",
]

else:
from importlib.metadata import entry_points, version
from importlib.metadata import (
EntryPoint,
EntryPoints,
SelectableGroups,
entry_points,
version,
)

__all__ = ["entry_points", "version"]
__all__ = [
"entry_points",
"version",
"EntryPoint",
"SelectableGroups",
"EntryPoints",
]
64 changes: 62 additions & 2 deletions opentelemetry-api/tests/util/test__importlib_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@
# limitations under the License.

from unittest import TestCase
from warnings import catch_warnings, filterwarnings

from opentelemetry.metrics import MeterProvider
from opentelemetry.util._importlib_metadata import entry_points
from opentelemetry.util._importlib_metadata import EntryPoint
from opentelemetry.util._importlib_metadata import (
entry_points as entry_points_function, # SelectableGroups,; EntryPoints
)


class TestEntryPoints(TestCase):
Expand All @@ -24,11 +28,67 @@ def test_entry_points(self):
self.assertIsInstance(
next(
iter(
entry_points(
entry_points_function(
group="opentelemetry_meter_provider",
name="default_meter_provider",
)
)
).load()(),
MeterProvider,
)

def test_uniform_behavior(self):
"""
Test that entry_points behaves the same regardless of the Python
version.
"""

selectable_groups = entry_points_function()

# self.assertIsInstance(selectable_groups, SelectableGroups)

# Supressing the following warning here:
# DeprecationWarning: SelectableGroups dict interface is deprecated. Use select.
# The behavior of the importlib metadata library is hard to understand,
# this is True: selectable_groups is selectable_groups.select(). So,
# using select, as the warning says yields the same problem. Also
# select does not accept any parameters.

with catch_warnings():
filterwarnings("ignore", category=DeprecationWarning)
entry_points = selectable_groups.select()[
"opentelemetry_propagator"
]

# Supressing the following warning here:
# DeprecationWarning: DeprecationWarning: Accessing entry points by index is deprecated. Cast to tuple if needed.
# The behavior of the importlib metadata library is hard to understand,
# this is True: entry_points == .select(). So, using select, as the
# warning says yields the same problem. Also select does not accept any
# parameters.
with catch_warnings():
filterwarnings("ignore", category=DeprecationWarning)

self.assertIsInstance(entry_points.select()[0], EntryPoint)

entry_points = entry_points_function(
group="opentelemetry_propagator"
)

self.assertIsInstance(entry_points.select()[0], EntryPoint)

entry_points = entry_points_function(
group="opentelemetry_propagator", name="baggage"
)

self.assertIsInstance(entry_points.select()[0], EntryPoint)

entry_points = entry_points_function(group="abc")

self.assertEqual(entry_points, [])

entry_points = entry_points_function(
group="opentelemetry_propagator", name="abc"
)

self.assertEqual(entry_points, [])
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import math
import os
from abc import ABC, abstractmethod
from enum import Enum
Expand All @@ -23,7 +24,6 @@
from typing import IO, Callable, Dict, Iterable, Optional

from typing_extensions import final
import math

# This kind of import is needed to avoid Sphinx errors.
import opentelemetry.sdk.metrics._internal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import math
from time import sleep, time_ns
from typing import Sequence
from unittest.mock import Mock

from flaky import flaky
import math

from opentelemetry.sdk.metrics import Counter
from opentelemetry.sdk.metrics._internal import _Counter
Expand Down Expand Up @@ -139,7 +139,9 @@ def test_ticker_not_called_on_infinity(self):
collect_mock = Mock()
exporter = FakeMetricsExporter()
exporter.export = Mock()
pmr = PeriodicExportingMetricReader(exporter, export_interval_millis=math.inf)
pmr = PeriodicExportingMetricReader(
exporter, export_interval_millis=math.inf
)
pmr._set_collect_callback(collect_mock)
sleep(0.1)
self.assertTrue(collect_mock.assert_not_called)
Expand All @@ -149,16 +151,20 @@ def test_ticker_value_exception_on_zero(self):
exporter = FakeMetricsExporter()
exporter.export = Mock()
self.assertRaises(
ValueError, PeriodicExportingMetricReader,
exporter, export_interval_millis=0
ValueError,
PeriodicExportingMetricReader,
exporter,
export_interval_millis=0,
)

def test_ticker_value_exception_on_negative(self):
exporter = FakeMetricsExporter()
exporter.export = Mock()
self.assertRaises(
ValueError, PeriodicExportingMetricReader,
exporter, export_interval_millis=-100
ValueError,
PeriodicExportingMetricReader,
exporter,
export_interval_millis=-100,
)

@flaky(max_runs=3, min_passes=1)
Expand Down

0 comments on commit df15cfb

Please sign in to comment.