Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Annotate few functions and methods #705

Merged
merged 1 commit into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions prometheus_client/context_managers.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
from timeit import default_timer
from types import TracebackType
from typing import (
Any, Callable, Literal, Optional, Type, TYPE_CHECKING, TypeVar,
)

from .decorator import decorate

if TYPE_CHECKING:
from . import Counter
F = TypeVar("F", bound=Callable[..., Any])


class ExceptionCounter:
def __init__(self, counter, exception):
def __init__(self, counter: "Counter", exception: Type[BaseException]) -> None:
csmarchbanks marked this conversation as resolved.
Show resolved Hide resolved
self._counter = counter
self._exception = exception

def __enter__(self):
def __enter__(self) -> None:
pass

def __exit__(self, typ, value, traceback):
def __exit__(self, typ: Optional[Type[BaseException]], value: Optional[BaseException], traceback: Optional[TracebackType]) -> Literal[False]:
if isinstance(value, self._exception):
self._counter.inc()
return False

def __call__(self, f):
def __call__(self, f: "F") -> "F":
def wrapped(func, *args, **kwargs):
with self:
return func(*args, **kwargs)
Expand Down
70 changes: 38 additions & 32 deletions prometheus_client/metrics.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
from threading import Lock
import time
import types
from typing import (
Any, Callable, Dict, Optional, Sequence, Tuple, Type, TypeVar,
)

from . import values # retain this import style for testability
from .context_managers import ExceptionCounter, InprogressTracker, Timer
from .metrics_core import (
Metric, METRIC_LABEL_NAME_RE, METRIC_NAME_RE,
RESERVED_METRIC_LABEL_NAME_RE,
)
from .registry import REGISTRY
from .registry import CollectorRegistry, REGISTRY
from .samples import Exemplar
from .utils import floatToGoString, INF

T = TypeVar('T', bound='MetricWrapperBase')
csmarchbanks marked this conversation as resolved.
Show resolved Hide resolved
F = TypeVar("F", bound=Callable[..., Any])


def _build_full_name(metric_type, name, namespace, subsystem, unit):
full_name = ''
Expand Down Expand Up @@ -56,8 +62,8 @@ def _validate_exemplar(exemplar):


class MetricWrapperBase:
_type = None
_reserved_labelnames = ()
_type: Optional[str] = None
_reserved_labelnames: Sequence[str] = ()

def _is_observable(self):
# Whether this metric is observable, i.e.
Expand Down Expand Up @@ -94,20 +100,20 @@ def __repr__(self):
metric_type = type(self)
return f"{metric_type.__module__}.{metric_type.__name__}({self._name})"

def __init__(self,
name,
documentation,
labelnames=(),
namespace='',
subsystem='',
unit='',
registry=REGISTRY,
_labelvalues=None,
):
def __init__(self: T,
name: str,
documentation: str,
labelnames: Sequence[str]=(),
namespace: str='',
subsystem: str='',
unit: str='',
registry: CollectorRegistry=REGISTRY,
_labelvalues: Optional[Sequence[str]]=None,
) -> None:
self._name = _build_full_name(self._type, name, namespace, subsystem, unit)
self._labelnames = _validate_labelnames(self, labelnames)
self._labelvalues = tuple(_labelvalues or ())
self._kwargs = {}
self._kwargs: Dict[str, Any] = {}
self._documentation = documentation
self._unit = unit

Expand All @@ -117,7 +123,7 @@ def __init__(self,
if self._is_parent():
# Prepare the fields needed for child metrics.
self._lock = Lock()
self._metrics = {}
self._metrics: Dict[Sequence[str], T] = {}

if self._is_observable():
self._metric_init()
Expand All @@ -127,7 +133,7 @@ def __init__(self,
if registry:
registry.register(self)

def labels(self, *labelvalues, **labelkwargs):
def labels(self: T, *labelvalues: str, **labelkwargs: str) -> T:
"""Return the child for the given labelset.

All metrics can have labels, allowing grouping of related time series.
Expand Down Expand Up @@ -193,7 +199,7 @@ def remove(self, *labelvalues):
with self._lock:
del self._metrics[labelvalues]

def clear(self):
def clear(self) -> None:
"""Remove all labelsets from the metric"""
with self._lock:
self._metrics = {}
Expand All @@ -212,7 +218,7 @@ def _multi_samples(self):
for suffix, sample_labels, value, timestamp, exemplar in metric._samples():
yield (suffix, dict(series_labels + list(sample_labels.items())), value, timestamp, exemplar)

def _child_samples(self): # pragma: no cover
def _child_samples(self) -> Sequence[Tuple[str, Dict[str, str], float]]: # pragma: no cover
raise NotImplementedError('_child_samples() must be implemented by %r' % self)

def _metric_init(self): # pragma: no cover
Expand Down Expand Up @@ -258,12 +264,12 @@ def f():
"""
_type = 'counter'

def _metric_init(self):
def _metric_init(self) -> None:
self._value = values.ValueClass(self._type, self._name, self._name + '_total', self._labelnames,
self._labelvalues)
self._created = time.time()

def inc(self, amount=1, exemplar=None):
def inc(self, amount: float=1, exemplar: Optional[Dict[str, str]]=None) -> None:
"""Increment counter by the given amount."""
self._raise_if_not_observable()
if amount < 0:
Expand All @@ -273,7 +279,7 @@ def inc(self, amount=1, exemplar=None):
_validate_exemplar(exemplar)
self._value.set_exemplar(Exemplar(exemplar, amount, time.time()))

def count_exceptions(self, exception=Exception):
def count_exceptions(self, exception: Type[BaseException]=Exception) -> ExceptionCounter:
"""Count exceptions in a block of code or function.

Can be used as a function decorator or context manager.
Expand Down Expand Up @@ -667,15 +673,15 @@ class Enum(MetricWrapperBase):
_type = 'stateset'

def __init__(self,
name,
documentation,
labelnames=(),
namespace='',
subsystem='',
unit='',
registry=REGISTRY,
_labelvalues=None,
states=None,
name: str,
documentation: str,
labelnames: Sequence[str]=(),
namespace: str='',
subsystem: str='',
unit: str='',
registry: CollectorRegistry=REGISTRY,
_labelvalues: Optional[Sequence[str]]=None,
states: Optional[Sequence[str]]=None,
):
super().__init__(
name=name,
Expand All @@ -693,11 +699,11 @@ def __init__(self,
raise ValueError(f'No states provided for Enum metric: {name}')
self._kwargs['states'] = self._states = states

def _metric_init(self):
def _metric_init(self) -> None:
self._value = 0
self._lock = Lock()

def state(self, state):
def state(self, state: str) -> None:
"""Set enum metric state."""
self._raise_if_not_observable()
with self._lock:
Expand Down
7 changes: 1 addition & 6 deletions prometheus_client/openmetrics/parser.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
#!/usr/bin/python


import io as StringIO
import math
import re

from ..metrics_core import Metric, METRIC_LABEL_NAME_RE
from ..samples import Exemplar, Sample, Timestamp
from ..utils import floatToGoString

try:
import StringIO
except ImportError:
# Python 3
import io as StringIO


def text_string_to_metric_families(text):
"""Parse Openmetrics text format from a unicode string.
Expand Down
7 changes: 1 addition & 6 deletions prometheus_client/parser.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import io as StringIO
import re

from .metrics_core import Metric
from .samples import Sample

try:
import StringIO
except ImportError:
# Python 3
import io as StringIO


def text_string_to_metric_families(text):
"""Parse Prometheus text format from a unicode string.
Expand Down
Empty file added prometheus_client/py.typed
Empty file.
19 changes: 13 additions & 6 deletions prometheus_client/samples.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from collections import namedtuple
from typing import Dict, NamedTuple, Optional


class Timestamp:
Expand Down Expand Up @@ -36,8 +36,15 @@ def __gt__(self, other):
# Timestamp can be a float containing a unixtime in seconds,
# a Timestamp object, or None.
# Exemplar can be an Exemplar object, or None.
Sample = namedtuple('Sample', ['name', 'labels', 'value', 'timestamp', 'exemplar'])
Sample.__new__.__defaults__ = (None, None)

Exemplar = namedtuple('Exemplar', ['labels', 'value', 'timestamp'])
Exemplar.__new__.__defaults__ = (None,)
class Exemplar(NamedTuple):
labels: Dict[str, str]
value: float
timestamp: Optional[float] = None


class Sample(NamedTuple):
name: str
labels: Dict[str, str]
value: float
timestamp: Optional[float] = None
exemplar: Optional[Exemplar] = None
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
'prometheus_client.openmetrics',
'prometheus_client.twisted',
],
package_data={
'prometheus_client': ['py.typed']
},
extras_require={
'twisted': ['twisted'],
},
Expand Down