diff --git a/opentelemetry-api/src/opentelemetry/_metrics/__init__.py b/opentelemetry-api/src/opentelemetry/_metrics/__init__.py index 584e3cb5d7a..6447135743b 100644 --- a/opentelemetry-api/src/opentelemetry/_metrics/__init__.py +++ b/opentelemetry-api/src/opentelemetry/_metrics/__init__.py @@ -13,7 +13,6 @@ # limitations under the License. # pylint: disable=too-many-ancestors -# type: ignore """ The OpenTelemetry metrics API describes the classes used to generate @@ -46,9 +45,10 @@ from logging import getLogger from os import environ from threading import Lock -from typing import List, Optional, Set, Tuple, cast +from typing import List, Optional, Sequence, Set, Tuple, Union, cast from opentelemetry._metrics.instrument import ( + CallbackT, Counter, Histogram, NoOpCounter, @@ -63,7 +63,6 @@ UpDownCounter, _ProxyCounter, _ProxyHistogram, - _ProxyInstrument, _ProxyObservableCounter, _ProxyObservableGauge, _ProxyObservableUpDownCounter, @@ -78,6 +77,16 @@ _logger = getLogger(__name__) +ProxyInstrumentT = Union[ + _ProxyCounter, + _ProxyHistogram, + _ProxyObservableCounter, + _ProxyObservableGauge, + _ProxyObservableUpDownCounter, + _ProxyUpDownCounter, +] + + class MeterProvider(ABC): """ MeterProvider is the entry point of the API. It provides access to `Meter` instances. @@ -87,8 +96,8 @@ class MeterProvider(ABC): def get_meter( self, name: str, - version: str = None, - schema_url: str = None, + version: Optional[str] = None, + schema_url: Optional[str] = None, ) -> "Meter": """Returns a `Meter` for use by the given instrumentation library. @@ -123,9 +132,9 @@ class NoOpMeterProvider(MeterProvider): def get_meter( self, - name, - version=None, - schema_url=None, + name: str, + version: Optional[str] = None, + schema_url: Optional[str] = None, ) -> "Meter": """Returns a NoOpMeter.""" super().get_meter(name, version=version, schema_url=schema_url) @@ -140,9 +149,9 @@ def __init__(self) -> None: def get_meter( self, - name, - version=None, - schema_url=None, + name: str, + version: Optional[str] = None, + schema_url: Optional[str] = None, ) -> "Meter": with self._lock: if self._real_meter_provider is not None: @@ -168,7 +177,12 @@ class Meter(ABC): used to produce measurements. """ - def __init__(self, name: str, version: str = None, schema_url: str = None): + def __init__( + self, + name: str, + version: Optional[str] = None, + schema_url: Optional[str] = None, + ) -> None: super().__init__() self._name = name self._version = version @@ -177,21 +191,21 @@ def __init__(self, name: str, version: str = None, schema_url: str = None): self._instrument_ids_lock = Lock() @property - def name(self): + def name(self) -> str: """ The name of the instrumenting module. """ return self._name @property - def version(self): + def version(self) -> Optional[str]: """ The version string of the instrumenting library. """ return self._version @property - def schema_url(self): + def schema_url(self) -> Optional[str]: """ Specifies the Schema URL of the emitted telemetry """ @@ -225,7 +239,10 @@ def _is_instrument_registered( @abstractmethod def create_counter( - self, name: str, unit: str = "", description: str = "" + self, + name: str, + unit: str = "", + description: str = "", ) -> Counter: """Creates a `Counter` instrument @@ -238,7 +255,10 @@ def create_counter( @abstractmethod def create_up_down_counter( - self, name: str, unit: str = "", description: str = "" + self, + name: str, + unit: str = "", + description: str = "", ) -> UpDownCounter: """Creates an `UpDownCounter` instrument @@ -251,7 +271,11 @@ def create_up_down_counter( @abstractmethod def create_observable_counter( - self, name, callbacks=None, unit="", description="" + self, + name: str, + callbacks: Optional[Sequence[CallbackT]] = None, + unit: str = "", + description: str = "", ) -> ObservableCounter: """Creates an `ObservableCounter` instrument @@ -334,7 +358,12 @@ def cpu_time_callback(states_to_include: set[str]) -> Iterable[Iterable[Observat """ @abstractmethod - def create_histogram(self, name, unit="", description="") -> Histogram: + def create_histogram( + self, + name: str, + unit: str = "", + description: str = "", + ) -> Histogram: """Creates a `opentelemetry._metrics.instrument.Histogram` instrument Args: @@ -346,7 +375,11 @@ def create_histogram(self, name, unit="", description="") -> Histogram: @abstractmethod def create_observable_gauge( - self, name, callbacks=None, unit="", description="" + self, + name: str, + callbacks: Optional[Sequence[CallbackT]] = None, + unit: str = "", + description: str = "", ) -> ObservableGauge: """Creates an `ObservableGauge` instrument @@ -363,7 +396,11 @@ def create_observable_gauge( @abstractmethod def create_observable_up_down_counter( - self, name, callbacks=None, unit="", description="" + self, + name: str, + callbacks: Optional[Sequence[CallbackT]] = None, + unit: str = "", + description: str = "", ) -> ObservableUpDownCounter: """Creates an `ObservableUpDownCounter` instrument @@ -382,13 +419,13 @@ def create_observable_up_down_counter( class _ProxyMeter(Meter): def __init__( self, - name, - version=None, - schema_url=None, - ): + name: str, + version: Optional[str] = None, + schema_url: Optional[str] = None, + ) -> None: super().__init__(name, version=version, schema_url=schema_url) self._lock = Lock() - self._instruments: List[_ProxyInstrument] = [] + self._instruments: List[ProxyInstrumentT] = [] self._real_meter: Optional[Meter] = None def on_set_meter_provider(self, meter_provider: MeterProvider) -> None: @@ -408,7 +445,12 @@ def on_set_meter_provider(self, meter_provider: MeterProvider) -> None: for instrument in self._instruments: instrument.on_meter_set(real_meter) - def create_counter(self, name, unit="", description="") -> Counter: + def create_counter( + self, + name: str, + unit: str = "", + description: str = "", + ) -> Counter: with self._lock: if self._real_meter: return self._real_meter.create_counter(name, unit, description) @@ -417,7 +459,10 @@ def create_counter(self, name, unit="", description="") -> Counter: return proxy def create_up_down_counter( - self, name, unit="", description="" + self, + name: str, + unit: str = "", + description: str = "", ) -> UpDownCounter: with self._lock: if self._real_meter: @@ -429,7 +474,11 @@ def create_up_down_counter( return proxy def create_observable_counter( - self, name, callbacks=None, unit="", description="" + self, + name: str, + callbacks: Optional[Sequence[CallbackT]] = None, + unit: str = "", + description: str = "", ) -> ObservableCounter: with self._lock: if self._real_meter: @@ -442,7 +491,12 @@ def create_observable_counter( self._instruments.append(proxy) return proxy - def create_histogram(self, name, unit="", description="") -> Histogram: + def create_histogram( + self, + name: str, + unit: str = "", + description: str = "", + ) -> Histogram: with self._lock: if self._real_meter: return self._real_meter.create_histogram( @@ -453,7 +507,11 @@ def create_histogram(self, name, unit="", description="") -> Histogram: return proxy def create_observable_gauge( - self, name, callbacks=None, unit="", description="" + self, + name: str, + callbacks: Optional[Sequence[CallbackT]] = None, + unit: str = "", + description: str = "", ) -> ObservableGauge: with self._lock: if self._real_meter: @@ -467,7 +525,11 @@ def create_observable_gauge( return proxy def create_observable_up_down_counter( - self, name, callbacks=None, unit="", description="" + self, + name: str, + callbacks: Optional[Sequence[CallbackT]] = None, + unit: str = "", + description: str = "", ) -> ObservableUpDownCounter: with self._lock: if self._real_meter: @@ -490,7 +552,12 @@ class NoOpMeter(Meter): All operations are no-op. """ - def create_counter(self, name, unit="", description="") -> Counter: + def create_counter( + self, + name: str, + unit: str = "", + description: str = "", + ) -> Counter: """Returns a no-op Counter.""" super().create_counter(name, unit=unit, description=description) if self._is_instrument_registered( @@ -507,7 +574,10 @@ def create_counter(self, name, unit="", description="") -> Counter: return NoOpCounter(name, unit=unit, description=description) def create_up_down_counter( - self, name, unit="", description="" + self, + name: str, + unit: str = "", + description: str = "", ) -> UpDownCounter: """Returns a no-op UpDownCounter.""" super().create_up_down_counter( @@ -527,7 +597,11 @@ def create_up_down_counter( return NoOpUpDownCounter(name, unit=unit, description=description) def create_observable_counter( - self, name, callbacks=None, unit="", description="" + self, + name: str, + callbacks: Optional[Sequence[CallbackT]] = None, + unit: str = "", + description: str = "", ) -> ObservableCounter: """Returns a no-op ObservableCounter.""" super().create_observable_counter( @@ -551,7 +625,12 @@ def create_observable_counter( description=description, ) - def create_histogram(self, name, unit="", description="") -> Histogram: + def create_histogram( + self, + name: str, + unit: str = "", + description: str = "", + ) -> Histogram: """Returns a no-op Histogram.""" super().create_histogram(name, unit=unit, description=description) if self._is_instrument_registered( @@ -568,7 +647,11 @@ def create_histogram(self, name, unit="", description="") -> Histogram: return NoOpHistogram(name, unit=unit, description=description) def create_observable_gauge( - self, name, callbacks=None, unit="", description="" + self, + name: str, + callbacks: Optional[Sequence[CallbackT]] = None, + unit: str = "", + description: str = "", ) -> ObservableGauge: """Returns a no-op ObservableGauge.""" super().create_observable_gauge( @@ -593,7 +676,11 @@ def create_observable_gauge( ) def create_observable_up_down_counter( - self, name, callbacks=None, unit="", description="" + self, + name: str, + callbacks: Optional[Sequence[CallbackT]] = None, + unit: str = "", + description: str = "", ) -> ObservableUpDownCounter: """Returns a no-op ObservableUpDownCounter.""" super().create_observable_up_down_counter( @@ -670,7 +757,7 @@ def get_meter_provider() -> MeterProvider: if OTEL_PYTHON_METER_PROVIDER not in environ.keys(): return _PROXY_METER_PROVIDER - meter_provider: MeterProvider = _load_provider( + meter_provider: MeterProvider = _load_provider( # type: ignore OTEL_PYTHON_METER_PROVIDER, "meter_provider" ) _set_meter_provider(meter_provider, log=False) diff --git a/opentelemetry-api/src/opentelemetry/_metrics/instrument.py b/opentelemetry-api/src/opentelemetry/_metrics/instrument.py index d79b0d9aa60..1a855621f4d 100644 --- a/opentelemetry-api/src/opentelemetry/_metrics/instrument.py +++ b/opentelemetry-api/src/opentelemetry/_metrics/instrument.py @@ -14,7 +14,6 @@ # pylint: disable=too-many-ancestors -# type: ignore from abc import ABC, abstractmethod from logging import getLogger @@ -24,6 +23,7 @@ Generic, Iterable, Optional, + Sequence, TypeVar, Union, ) @@ -31,6 +31,7 @@ # pylint: disable=unused-import; needed for typing and sphinx from opentelemetry import _metrics as metrics from opentelemetry._metrics.observation import Observation +from opentelemetry.util.types import Attributes InstrumentT = TypeVar("InstrumentT", bound="Instrument") CallbackT = Union[ @@ -46,7 +47,12 @@ class Instrument(ABC): """Abstract class that serves as base for all instruments.""" @abstractmethod - def __init__(self, name, unit="", description=""): + def __init__( + self, + name: str, + unit: str = "", + description: str = "", + ) -> None: pass # FIXME check that the instrument name is valid @@ -55,7 +61,12 @@ def __init__(self, name, unit="", description=""): class _ProxyInstrument(ABC, Generic[InstrumentT]): - def __init__(self, name, unit, description) -> None: + def __init__( + self, + name: str, + unit: str = "", + description: str = "", + ) -> None: self._name = name self._unit = unit self._description = description @@ -75,7 +86,13 @@ def _create_real_instrument(self, meter: "metrics.Meter") -> InstrumentT: class _ProxyAsynchronousInstrument(_ProxyInstrument[InstrumentT]): - def __init__(self, name, callbacks, unit, description) -> None: + def __init__( + self, + name: str, + callbacks: Optional[Sequence[CallbackT]] = None, + unit: str = "", + description: str = "", + ) -> None: super().__init__(name, unit, description) self._callbacks = callbacks @@ -88,11 +105,11 @@ class Asynchronous(Instrument): @abstractmethod def __init__( self, - name, - callbacks=None, - unit="", - description="", - ): + name: str, + callbacks: Optional[Sequence[CallbackT]] = None, + unit: str = "", + description: str = "", + ) -> None: super().__init__(name, unit=unit, description=description) @@ -116,7 +133,11 @@ class Counter(_Monotonic, Synchronous): """A Counter is a synchronous `Instrument` which supports non-negative increments.""" @abstractmethod - def add(self, amount, attributes=None): + def add( + self, + amount: Union[int, float], + attributes: Optional[Attributes] = None, + ) -> None: # FIXME check that the amount is non negative pass @@ -124,15 +145,28 @@ def add(self, amount, attributes=None): class NoOpCounter(Counter): """No-op implementation of `Counter`.""" - def __init__(self, name, unit="", description=""): + def __init__( + self, + name: str, + unit: str = "", + description: str = "", + ) -> None: super().__init__(name, unit=unit, description=description) - def add(self, amount, attributes=None): + def add( + self, + amount: Union[int, float], + attributes: Optional[Attributes] = None, + ) -> None: return super().add(amount, attributes=attributes) class _ProxyCounter(_ProxyInstrument[Counter], Counter): - def add(self, amount, attributes=None): + def add( + self, + amount: Union[int, float], + attributes: Optional[Attributes] = None, + ) -> None: if self._real_instrument: self._real_instrument.add(amount, attributes) @@ -144,22 +178,39 @@ class UpDownCounter(_NonMonotonic, Synchronous): """An UpDownCounter is a synchronous `Instrument` which supports increments and decrements.""" @abstractmethod - def add(self, amount, attributes=None): + def add( + self, + amount: Union[int, float], + attributes: Optional[Attributes] = None, + ) -> None: pass class NoOpUpDownCounter(UpDownCounter): """No-op implementation of `UpDownCounter`.""" - def __init__(self, name, unit="", description=""): + def __init__( + self, + name: str, + unit: str = "", + description: str = "", + ) -> None: super().__init__(name, unit=unit, description=description) - def add(self, amount, attributes=None): + def add( + self, + amount: Union[int, float], + attributes: Optional[Attributes] = None, + ) -> None: return super().add(amount, attributes=attributes) class _ProxyUpDownCounter(_ProxyInstrument[UpDownCounter], UpDownCounter): - def add(self, amount, attributes=None): + def add( + self, + amount: Union[int, float], + attributes: Optional[Attributes] = None, + ) -> None: if self._real_instrument: self._real_instrument.add(amount, attributes) @@ -178,7 +229,13 @@ class ObservableCounter(_Monotonic, Asynchronous): class NoOpObservableCounter(ObservableCounter): """No-op implementation of `ObservableCounter`.""" - def __init__(self, name, callbacks=None, unit="", description=""): + def __init__( + self, + name: str, + callbacks: Optional[Sequence[CallbackT]] = None, + unit: str = "", + description: str = "", + ) -> None: super().__init__(name, callbacks, unit=unit, description=description) @@ -203,7 +260,13 @@ class ObservableUpDownCounter(_NonMonotonic, Asynchronous): class NoOpObservableUpDownCounter(ObservableUpDownCounter): """No-op implementation of `ObservableUpDownCounter`.""" - def __init__(self, name, callbacks=None, unit="", description=""): + def __init__( + self, + name: str, + callbacks: Optional[Sequence[CallbackT]] = None, + unit: str = "", + description: str = "", + ) -> None: super().__init__(name, callbacks, unit=unit, description=description) @@ -226,22 +289,39 @@ class Histogram(_Grouping, Synchronous): """ @abstractmethod - def record(self, amount, attributes=None): + def record( + self, + amount: Union[int, float], + attributes: Optional[Attributes] = None, + ) -> None: pass class NoOpHistogram(Histogram): """No-op implementation of `Histogram`.""" - def __init__(self, name, unit="", description=""): + def __init__( + self, + name: str, + unit: str = "", + description: str = "", + ) -> None: super().__init__(name, unit=unit, description=description) - def record(self, amount, attributes=None): + def record( + self, + amount: Union[int, float], + attributes: Optional[Attributes] = None, + ) -> None: return super().record(amount, attributes=attributes) class _ProxyHistogram(_ProxyInstrument[Histogram], Histogram): - def record(self, amount, attributes=None): + def record( + self, + amount: Union[int, float], + attributes: Optional[Attributes] = None, + ) -> None: if self._real_instrument: self._real_instrument.record(amount, attributes) @@ -261,7 +341,13 @@ class ObservableGauge(_Grouping, Asynchronous): class NoOpObservableGauge(ObservableGauge): """No-op implementation of `ObservableGauge`.""" - def __init__(self, name, callbacks=None, unit="", description=""): + def __init__( + self, + name: str, + callbacks: Optional[Sequence[CallbackT]] = None, + unit: str = "", + description: str = "", + ) -> None: super().__init__(name, callbacks, unit=unit, description=description) diff --git a/opentelemetry-api/src/opentelemetry/util/_providers.py b/opentelemetry-api/src/opentelemetry/util/_providers.py index 98c75ed06bd..f19c32ee86d 100644 --- a/opentelemetry-api/src/opentelemetry/util/_providers.py +++ b/opentelemetry-api/src/opentelemetry/util/_providers.py @@ -14,14 +14,15 @@ from logging import getLogger from os import environ -from typing import TYPE_CHECKING, Union, cast +from typing import TYPE_CHECKING, TypeVar, cast from pkg_resources import iter_entry_points if TYPE_CHECKING: + from opentelemetry._metrics import MeterProvider from opentelemetry.trace import TracerProvider -Provider = Union["TracerProvider"] +Provider = TypeVar("Provider", "TracerProvider", "MeterProvider") logger = getLogger(__name__) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/util/instrumentation.py b/opentelemetry-sdk/src/opentelemetry/sdk/util/instrumentation.py index 1b2c1c74a7d..a489c207a03 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/util/instrumentation.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/util/instrumentation.py @@ -86,26 +86,28 @@ def __init__( name: str, version: typing.Optional[str] = None, schema_url: typing.Optional[str] = None, - ): + ) -> None: self._name = name self._version = version self._schema_url = schema_url - def __repr__(self): + def __repr__(self) -> str: return f"{type(self).__name__}({self._name}, {self._version}, {self._schema_url})" - def __hash__(self): + def __hash__(self) -> int: return hash((self._name, self._version, self._schema_url)) - def __eq__(self, value): - return type(value) is type(self) and ( - self._name, - self._version, - self._schema_url, - ) == (value._name, value._version, value._schema_url) + def __eq__(self, value: object) -> bool: + if not isinstance(value, InstrumentationScope): + return NotImplemented + return (self._name, self._version, self._schema_url) == ( + value._name, + value._version, + value._schema_url, + ) - def __lt__(self, value): - if type(value) is not type(self): + def __lt__(self, value: object) -> bool: + if not isinstance(value, InstrumentationScope): return NotImplemented return (self._name, self._version, self._schema_url) < ( value._name, diff --git a/tox.ini b/tox.ini index e3a1c6e1a3f..73df1f69285 100644 --- a/tox.ini +++ b/tox.ini @@ -172,6 +172,7 @@ commands = coverage: {toxinidir}/scripts/coverage.sh mypy: mypy --install-types --non-interactive --namespace-packages --explicit-package-bases opentelemetry-api/src/opentelemetry/ + ; For test code, we don't want to enforce the full mypy strictness mypy: mypy --install-types --non-interactive --namespace-packages --config-file=mypy-relaxed.ini opentelemetry-api/tests/