Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-prometheus-client for openSUSE:Factory checked in at 2023-01-24 19:43:46 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-prometheus-client (Old) and /work/SRC/openSUSE:Factory/.python-prometheus-client.new.32243 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-prometheus-client" Tue Jan 24 19:43:46 2023 rev:8 rq:1060598 version:0.16.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-prometheus-client/python-prometheus-client.changes 2022-10-14 15:44:01.068066532 +0200 +++ /work/SRC/openSUSE:Factory/.python-prometheus-client.new.32243/python-prometheus-client.changes 2023-01-24 20:32:41.356488453 +0100 @@ -1,0 +2,11 @@ +Tue Jan 24 07:59:49 UTC 2023 - Matej Cepl <mc...@suse.com> + +- Update to 0.16.0: + * [FEATURE] Support HELP text in multiprocess mode. + * [ENHANCEMENT] Reduce the mmap minimum size. + * [BUGFIX] Use the correct OpenMetrics encoder when + application/openmetrics-text is requested in ASGI apps. + * [BUGFIX] Allow Prometheus format parser to handle a missing + space after labels. + +------------------------------------------------------------------- Old: ---- v0.15.0.tar.gz New: ---- v0.16.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-prometheus-client.spec ++++++ --- /var/tmp/diff_new_pack.KPxXYq/_old 2023-01-24 20:32:41.788490740 +0100 +++ /var/tmp/diff_new_pack.KPxXYq/_new 2023-01-24 20:32:41.792490761 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-prometheus-client # -# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-prometheus-client -Version: 0.15.0 +Version: 0.16.0 Release: 0 Summary: Python client for the Prometheus monitoring system License: Apache-2.0 ++++++ v0.15.0.tar.gz -> v0.16.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/.circleci/config.yml new/client_python-0.16.0/.circleci/config.yml --- old/client_python-0.15.0/.circleci/config.yml 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/.circleci/config.yml 2023-01-23 23:05:11.000000000 +0100 @@ -30,7 +30,7 @@ python: type: string docker: - - image: circleci/python:<< parameters.python >> + - image: cimg/python:<< parameters.python >> environment: TOXENV: "py<< parameters.python >>" steps: @@ -80,6 +80,7 @@ - "3.8" - "3.9" - "3.10" + - "3.11" - test_nooptionals: matrix: parameters: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/README.md new/client_python-0.16.0/README.md --- old/client_python-0.15.0/README.md 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/README.md 2023-01-23 23:05:11.000000000 +0100 @@ -487,7 +487,7 @@ ```python from prometheus_client import CollectorRegistry, Gauge, push_to_gateway -from prometheus_client.exposition import tls_handler +from prometheus_client.exposition import tls_auth_handler def my_auth_handler(url, method, timeout, headers, data): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/prometheus_client/asgi.py new/client_python-0.16.0/prometheus_client/asgi.py --- old/client_python-0.15.0/prometheus_client/asgi.py 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/prometheus_client/asgi.py 2023-01-23 23:05:11.000000000 +0100 @@ -12,7 +12,7 @@ assert scope.get("type") == "http" # Prepare parameters params = parse_qs(scope.get('query_string', b'')) - accept_header = "Accept: " + ",".join([ + accept_header = ",".join([ value.decode("utf8") for (name, value) in scope.get('headers') if name.decode("utf8").lower() == 'accept' ]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/prometheus_client/context_managers.py new/client_python-0.16.0/prometheus_client/context_managers.py --- old/client_python-0.15.0/prometheus_client/context_managers.py 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/prometheus_client/context_managers.py 2023-01-23 23:05:11.000000000 +0100 @@ -1,7 +1,9 @@ import sys from timeit import default_timer from types import TracebackType -from typing import Any, Callable, Optional, Type, TYPE_CHECKING, TypeVar +from typing import ( + Any, Callable, Optional, Tuple, Type, TYPE_CHECKING, TypeVar, Union, +) if sys.version_info >= (3, 8, 0): from typing import Literal @@ -14,7 +16,7 @@ class ExceptionCounter: - def __init__(self, counter: "Counter", exception: Type[BaseException]) -> None: + def __init__(self, counter: "Counter", exception: Union[Type[BaseException], Tuple[Type[BaseException], ...]]) -> None: self._counter = counter self._exception = exception diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/prometheus_client/exposition.py new/client_python-0.16.0/prometheus_client/exposition.py --- old/client_python-0.15.0/prometheus_client/exposition.py 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/prometheus_client/exposition.py 2023-01-23 23:05:11.000000000 +0100 @@ -370,8 +370,8 @@ timeout: Optional[float], headers: List[Tuple[str, str]], data: bytes, - username: str = None, - password: str = None, + username: Optional[str] = None, + password: Optional[str] = None, ) -> Callable[[], None]: """Handler that implements HTTP/HTTPS connections with Basic Auth. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/prometheus_client/metrics.py new/client_python-0.16.0/prometheus_client/metrics.py --- old/client_python-0.15.0/prometheus_client/metrics.py 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/prometheus_client/metrics.py 2023-01-23 23:05:11.000000000 +0100 @@ -3,8 +3,8 @@ import time import types from typing import ( - Any, Callable, Dict, Iterable, List, Optional, Sequence, Type, TypeVar, - Union, + Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple, Type, + TypeVar, Union, ) from . import values # retain this import style for testability @@ -275,7 +275,7 @@ def _metric_init(self) -> None: self._value = values.ValueClass(self._type, self._name, self._name + '_total', self._labelnames, - self._labelvalues) + self._labelvalues, self._documentation) self._created = time.time() def inc(self, amount: float = 1, exemplar: Optional[Dict[str, str]] = None) -> None: @@ -288,7 +288,7 @@ _validate_exemplar(exemplar) self._value.set_exemplar(Exemplar(exemplar, amount, time.time())) - def count_exceptions(self, exception: Type[BaseException] = Exception) -> ExceptionCounter: + def count_exceptions(self, exception: Union[Type[BaseException], Tuple[Type[BaseException], ...]] = Exception) -> ExceptionCounter: """Count exceptions in a block of code or function. Can be used as a function decorator or context manager. @@ -377,7 +377,7 @@ def _metric_init(self) -> None: self._value = values.ValueClass( self._type, self._name, self._name, self._labelnames, self._labelvalues, - multiprocess_mode=self._multiprocess_mode + self._documentation, multiprocess_mode=self._multiprocess_mode ) def inc(self, amount: float = 1) -> None: @@ -469,8 +469,8 @@ def _metric_init(self) -> None: self._count = values.ValueClass(self._type, self._name, self._name + '_count', self._labelnames, - self._labelvalues) - self._sum = values.ValueClass(self._type, self._name, self._name + '_sum', self._labelnames, self._labelvalues) + self._labelvalues, self._documentation) + self._sum = values.ValueClass(self._type, self._name, self._name + '_sum', self._labelnames, self._labelvalues, self._documentation) self._created = time.time() def observe(self, amount: float) -> None: @@ -583,14 +583,15 @@ self._buckets: List[values.ValueClass] = [] self._created = time.time() bucket_labelnames = self._labelnames + ('le',) - self._sum = values.ValueClass(self._type, self._name, self._name + '_sum', self._labelnames, self._labelvalues) + self._sum = values.ValueClass(self._type, self._name, self._name + '_sum', self._labelnames, self._labelvalues, self._documentation) for b in self._upper_bounds: self._buckets.append(values.ValueClass( self._type, self._name, self._name + '_bucket', bucket_labelnames, - self._labelvalues + (floatToGoString(b),)) + self._labelvalues + (floatToGoString(b),), + self._documentation) ) def observe(self, amount: float, exemplar: Optional[Dict[str, str]] = None) -> None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/prometheus_client/metrics_core.py new/client_python-0.16.0/prometheus_client/metrics_core.py --- old/client_python-0.15.0/prometheus_client/metrics_core.py 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/prometheus_client/metrics_core.py 2023-01-23 23:05:11.000000000 +0100 @@ -113,7 +113,7 @@ name: str, documentation: str, value: Optional[float] = None, - labels: Sequence[str] = None, + labels: Optional[Sequence[str]] = None, created: Optional[float] = None, unit: str = '', ): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/prometheus_client/mmap_dict.py new/client_python-0.16.0/prometheus_client/mmap_dict.py --- old/client_python-0.15.0/prometheus_client/mmap_dict.py 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/prometheus_client/mmap_dict.py 2023-01-23 23:05:11.000000000 +0100 @@ -2,8 +2,9 @@ import mmap import os import struct +from typing import List -_INITIAL_MMAP_SIZE = 1 << 20 +_INITIAL_MMAP_SIZE = 1 << 16 _pack_integer_func = struct.Struct(b'i').pack _pack_double_func = struct.Struct(b'd').pack _unpack_integer = struct.Struct(b'i').unpack_from @@ -137,8 +138,8 @@ self._f = None -def mmap_key(metric_name, name, labelnames, labelvalues): +def mmap_key(metric_name: str, name: str, labelnames: List[str], labelvalues: List[str], help_text: str) -> str: """Format a key for use in the mmap file.""" # ensure labels are in consistent order for identity labels = dict(zip(labelnames, labelvalues)) - return json.dumps([metric_name, name, labels], sort_keys=True) + return json.dumps([metric_name, name, labels, help_text], sort_keys=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/prometheus_client/multiprocess.py new/client_python-0.16.0/prometheus_client/multiprocess.py --- old/client_python-0.15.0/prometheus_client/multiprocess.py 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/prometheus_client/multiprocess.py 2023-01-23 23:05:11.000000000 +0100 @@ -15,8 +15,6 @@ except NameError: # Python >= 2.5 FileNotFoundError = IOError -MP_METRIC_HELP = 'Multiprocess metric' - class MultiProcessCollector: """Collector for files for multi-process mode.""" @@ -53,9 +51,9 @@ def _parse_key(key): val = key_cache.get(key) if not val: - metric_name, name, labels = json.loads(key) + metric_name, name, labels, help_text = json.loads(key) labels_key = tuple(sorted(labels.items())) - val = key_cache[key] = (metric_name, name, labels, labels_key) + val = key_cache[key] = (metric_name, name, labels, labels_key, help_text) return val for f in files: @@ -71,11 +69,11 @@ continue raise for key, value, _ in file_values: - metric_name, name, labels, labels_key = _parse_key(key) + metric_name, name, labels, labels_key, help_text = _parse_key(key) metric = metrics.get(metric_name) if metric is None: - metric = Metric(metric_name, MP_METRIC_HELP, typ) + metric = Metric(metric_name, help_text, typ) metrics[metric_name] = metric if typ == 'gauge': diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/prometheus_client/parser.py new/client_python-0.16.0/prometheus_client/parser.py --- old/client_python-0.15.0/prometheus_client/parser.py 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/prometheus_client/parser.py 2023-01-23 23:05:11.000000000 +0100 @@ -116,8 +116,8 @@ name = text[:label_start].strip() # We ignore the starting curly brace label = text[label_start + 1:label_end] - # The value is after the label end (ignoring curly brace and space) - value, timestamp = _parse_value_and_timestamp(text[label_end + 2:]) + # The value is after the label end (ignoring curly brace) + value, timestamp = _parse_value_and_timestamp(text[label_end + 1:]) return Sample(name, _parse_labels(label), value, timestamp) # We don't have labels diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/prometheus_client/values.py new/client_python-0.16.0/prometheus_client/values.py --- old/client_python-0.15.0/prometheus_client/values.py 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/prometheus_client/values.py 2023-01-23 23:05:11.000000000 +0100 @@ -10,7 +10,7 @@ _multiprocess = False - def __init__(self, typ, metric_name, name, labelnames, labelvalues, **kwargs): + def __init__(self, typ, metric_name, name, labelnames, labelvalues, help_text, **kwargs): self._value = 0.0 self._exemplar = None self._lock = Lock() @@ -57,8 +57,8 @@ _multiprocess = True - def __init__(self, typ, metric_name, name, labelnames, labelvalues, multiprocess_mode='', **kwargs): - self._params = typ, metric_name, name, labelnames, labelvalues, multiprocess_mode + def __init__(self, typ, metric_name, name, labelnames, labelvalues, help_text, multiprocess_mode='', **kwargs): + self._params = typ, metric_name, name, labelnames, labelvalues, help_text, multiprocess_mode # This deprecation warning can go away in a few releases when removing the compatibility if 'prometheus_multiproc_dir' in os.environ and 'PROMETHEUS_MULTIPROC_DIR' not in os.environ: os.environ['PROMETHEUS_MULTIPROC_DIR'] = os.environ['prometheus_multiproc_dir'] @@ -69,7 +69,7 @@ values.append(self) def __reset(self): - typ, metric_name, name, labelnames, labelvalues, multiprocess_mode = self._params + typ, metric_name, name, labelnames, labelvalues, help_text, multiprocess_mode = self._params if typ == 'gauge': file_prefix = typ + '_' + multiprocess_mode else: @@ -81,7 +81,7 @@ files[file_prefix] = MmapedDict(filename) self._file = files[file_prefix] - self._key = mmap_key(metric_name, name, labelnames, labelvalues) + self._key = mmap_key(metric_name, name, labelnames, labelvalues, help_text) self._value = self._file.read_value(self._key) def __check_for_pid_change(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/setup.py new/client_python-0.16.0/setup.py --- old/client_python-0.15.0/setup.py 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/setup.py 2023-01-23 23:05:11.000000000 +0100 @@ -8,7 +8,7 @@ setup( name="prometheus_client", - version="0.15.0", + version="0.16.0", author="Brian Brazil", author_email="brian.bra...@robustperception.io", description="Python client for the Prometheus monitoring system.", @@ -43,6 +43,7 @@ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: System :: Monitoring", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/tests/openmetrics/test_parser.py new/client_python-0.16.0/tests/openmetrics/test_parser.py --- old/client_python-0.15.0/tests/openmetrics/test_parser.py 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/tests/openmetrics/test_parser.py 2023-01-23 23:05:11.000000000 +0100 @@ -642,6 +642,8 @@ ('a{a""} 1\n# EOF\n'), ('a{a=} 1\n# EOF\n'), ('a{a="} 1\n# EOF\n'), + # Missing delimiters. + ('a{a="1"}1\n# EOF\n'), # Missing or extra commas. ('a{a="1"b="2"} 1\n# EOF\n'), ('a{a="1",,b="2"} 1\n# EOF\n'), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/tests/test_asgi.py new/client_python-0.16.0/tests/test_asgi.py --- old/client_python-0.15.0/tests/test_asgi.py 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/tests/test_asgi.py 2023-01-23 23:05:11.000000000 +0100 @@ -75,6 +75,19 @@ break return outputs + def get_all_response_headers(self): + outputs = self.get_all_output() + response_start = next(o for o in outputs if o["type"] == "http.response.start") + return response_start["headers"] + + def get_response_header_value(self, header_name): + response_headers = self.get_all_response_headers() + return next( + value.decode("utf-8") + for name, value in response_headers + if name.decode("utf-8") == header_name + ) + def increment_metrics(self, metric_name, help_text, increments): c = Counter(metric_name, help_text, registry=self.registry) for _ in range(increments): @@ -158,3 +171,22 @@ # Assert outputs are not compressed. outputs = self.get_all_output() self.assert_outputs(outputs, metric_name, help_text, increments, compressed=False) + + def test_openmetrics_encoding(self): + """Response content type is application/openmetrics-text when appropriate Accept header is in request""" + app = make_asgi_app(self.registry) + self.seed_app(app) + self.scope["headers"] = [(b"Accept", b"application/openmetrics-text")] + self.send_input({"type": "http.request", "body": b""}) + + content_type = self.get_response_header_value('Content-Type').split(";")[0] + assert content_type == "application/openmetrics-text" + + def test_plaintext_encoding(self): + """Response content type is text/plain when Accept header is missing in request""" + app = make_asgi_app(self.registry) + self.seed_app(app) + self.send_input({"type": "http.request", "body": b""}) + + content_type = self.get_response_header_value('Content-Type').split(";")[0] + assert content_type == "text/plain" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/tests/test_multiprocess.py new/client_python-0.16.0/tests/test_multiprocess.py --- old/client_python-0.15.0/tests/test_multiprocess.py 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/tests/test_multiprocess.py 2023-01-23 23:05:11.000000000 +0100 @@ -281,6 +281,31 @@ self.assertEqual(metrics['h'].samples, expected_histogram) + def test_collect_preserves_help(self): + pid = 0 + values.ValueClass = MultiProcessValue(lambda: pid) + labels = {i: i for i in 'abcd'} + + c = Counter('c', 'c help', labelnames=labels.keys(), registry=None) + g = Gauge('g', 'g help', labelnames=labels.keys(), registry=None) + h = Histogram('h', 'h help', labelnames=labels.keys(), registry=None) + + c.labels(**labels).inc(1) + g.labels(**labels).set(1) + h.labels(**labels).observe(1) + + pid = 1 + + c.labels(**labels).inc(1) + g.labels(**labels).set(1) + h.labels(**labels).observe(5) + + metrics = {m.name: m for m in self.collector.collect()} + + self.assertEqual(metrics['c'].documentation, 'c help') + self.assertEqual(metrics['g'].documentation, 'g help') + self.assertEqual(metrics['h'].documentation, 'h help') + def test_merge_no_accumulate(self): pid = 0 values.ValueClass = MultiProcessValue(lambda: pid) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/tests/test_parser.py new/client_python-0.16.0/tests/test_parser.py --- old/client_python-0.15.0/tests/test_parser.py 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/tests/test_parser.py 2023-01-23 23:05:11.000000000 +0100 @@ -146,6 +146,7 @@ a { foo = "buz" } 3 a\t { \t foo\t = "biz"\t } \t 4 a \t{\t foo = "boz"\t}\t 5 +a{foo="bez"}6 """) metric_family = CounterMetricFamily("a", "help", labels=["foo"]) metric_family.add_metric(["bar"], 1) @@ -153,6 +154,7 @@ metric_family.add_metric(["buz"], 3) metric_family.add_metric(["biz"], 4) metric_family.add_metric(["boz"], 5) + metric_family.add_metric(["bez"], 6) self.assertEqualMetrics([metric_family], list(families)) def test_commas(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/client_python-0.15.0/tox.ini new/client_python-0.16.0/tox.ini --- old/client_python-0.15.0/tox.ini 2022-10-13 15:55:57.000000000 +0200 +++ new/client_python-0.16.0/tox.ini 2023-01-23 23:05:11.000000000 +0100 @@ -1,6 +1,5 @@ [tox] -envlist = coverage-clean,py3.6,py3.7,py3.8,py3.9,py3.10,pypy3.7,py3.9-nooptionals,coverage-report,flake8,isort,mypy - +envlist = coverage-clean,py3.6,py3.7,py3.8,py3.9,py3.10,py3.11,pypy3.7,py3.9-nooptionals,coverage-report,flake8,isort,mypy [base] deps = @@ -23,7 +22,6 @@ skip_install = true commands = coverage erase - [testenv:coverage-report] deps = coverage skip_install = true @@ -31,19 +29,18 @@ coverage combine coverage report - [testenv:flake8] deps = - flake8==3.7.8 - flake8-docstrings==1.5.0 - flake8-import-order==0.18.1 + flake8==6.0.0 + flake8-docstrings==1.6.0 + flake8-import-order==0.18.2 skip_install = true commands = flake8 prometheus_client/ tests/ setup.py [testenv:isort] deps = - isort==5.5.4 + isort==5.10.1 skip_install = true commands = isort --check prometheus_client/ tests/ setup.py @@ -52,7 +49,7 @@ deps = pytest asgiref - mypy==0.910 + mypy==0.991 skip_install = true commands = mypy --install-types --non-interactive prometheus_client/ tests/ @@ -77,7 +74,6 @@ import-order-style = google application-import-names = prometheus_client - [isort] force_alphabetical_sort_within_sections = True force_sort_within_sections = True