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 2021-04-10 15:27:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-prometheus_client (Old)
and /work/SRC/openSUSE:Factory/.python-prometheus_client.new.2401 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-prometheus_client"
Sat Apr 10 15:27:06 2021 rev:12 rq:883902 version:0.10.1
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-prometheus_client/python-prometheus_client.changes
2020-11-23 10:45:25.374298532 +0100
+++
/work/SRC/openSUSE:Factory/.python-prometheus_client.new.2401/python-prometheus_client.changes
2021-04-10 15:28:08.426432318 +0200
@@ -1,0 +2,19 @@
+Thu Apr 8 17:16:38 UTC 2021 - Michael Str??der <[email protected]>
+
+- Update to upstream 0.10.1 release
+ * [BUGFIX] Support lowercase prometheus_multiproc_dir environment
+ variable in mark_process_dead.
+
+-------------------------------------------------------------------
+Mon Apr 5 23:44:20 UTC 2021 - Michael Str??der <[email protected]>
+
+- Update to upstream 0.10.0 release
+ * [CHANGE] Python 2.6 is no longer supported. #592
+ * [CHANGE] The prometheus_multiproc_dir environment variable is
+ deprecated in favor of PROMETHEUS_MULTIPROC_DIR. #624
+ * [FEATURE] Follow redirects when pushing to Pushgateway using
+ passthrough_redirect_handler. #622
+ * [FEATURE] Metrics support a clear() method to remove all children. #642
+ * [ENHANCEMENT] Tag support in GraphiteBridge. #618
+
+-------------------------------------------------------------------
Old:
----
v0.9.0.tar.gz
New:
----
v0.10.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-prometheus_client.spec ++++++
--- /var/tmp/diff_new_pack.6LgICQ/_old 2021-04-10 15:28:08.782432736 +0200
+++ /var/tmp/diff_new_pack.6LgICQ/_new 2021-04-10 15:28:08.786432741 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-prometheus_client
#
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2021 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-%{**}}
%bcond_without python2
Name: python-prometheus_client
-Version: 0.9.0
+Version: 0.10.1
Release: 0
Summary: Python client for the Prometheus monitoring system
License: Apache-2.0
++++++ v0.9.0.tar.gz -> v0.10.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/.circleci/config.yml
new/client_python-0.10.1/.circleci/config.yml
--- old/client_python-0.9.0/.circleci/config.yml 1970-01-01
01:00:00.000000000 +0100
+++ new/client_python-0.10.1/.circleci/config.yml 2021-04-08
18:30:13.000000000 +0200
@@ -0,0 +1,89 @@
+---
+version: 2.1
+
+executors:
+ python:
+ docker:
+ - image: cimg/python:3.9
+
+jobs:
+ flake8_lint:
+ executor: python
+ steps:
+ - checkout
+ - run: pip install tox
+ - run: tox -e flake8
+ isort_lint:
+ executor: python
+ steps:
+ - checkout
+ - run: pip install tox
+ - run: tox -e isort
+ test:
+ parameters:
+ python:
+ type: string
+ docker:
+ - image: circleci/python:<< parameters.python >>
+ environment:
+ TOXENV: "py<< parameters.python >>"
+ steps:
+ - checkout
+ - run: echo 'export PATH=$HOME/.local/bin:$PATH' >> $BASH_ENV
+ - run: pip install --user tox
+ - run: tox
+ test_nooptionals:
+ parameters:
+ python:
+ type: string
+ docker:
+ - image: cimg/python:<< parameters.python >>
+ environment:
+ TOXENV: "py<< parameters.python >>-nooptionals"
+ steps:
+ - checkout
+ - run: pip install tox
+ - run: tox
+ test_pypy:
+ parameters:
+ python:
+ type: string
+ docker:
+ - image: pypy:<< parameters.python >>
+ environment:
+ TOXENV: "pypy<< parameters.python >>"
+ steps:
+ - checkout
+ - run: pip install tox
+ - run: tox
+
+
+workflows:
+ version: 2
+ client_python:
+ jobs:
+ - flake8_lint
+ - isort_lint
+ - test:
+ matrix:
+ parameters:
+ python:
+ - "2.7"
+ - "3.4"
+ - "3.5"
+ - "3.6"
+ - "3.7"
+ - "3.8"
+ - "3.9"
+ - test_nooptionals:
+ matrix:
+ parameters:
+ python:
+ - "2.7"
+ - "3.9"
+ - test_pypy:
+ matrix:
+ parameters:
+ python:
+ - "2.7"
+ - "3.7"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/.travis.yml
new/client_python-0.10.1/.travis.yml
--- old/client_python-0.9.0/.travis.yml 2020-11-16 14:26:28.000000000 +0100
+++ new/client_python-0.10.1/.travis.yml 1970-01-01 01:00:00.000000000
+0100
@@ -1,64 +0,0 @@
-os: linux
-dist: xenial
-cache:
- directories:
- - $HOME/.cache/pip
-
-language: python
-
-jobs:
- include:
- - stage: lint
- name: flake8_lint
- script:
- - tox -e flake8
- - stage: lint
- name: isort_lint
- script:
- - tox -e isort
- - stage: test
- python: "2.6"
- env: TOXENV=py26
- dist: trusty
- - stage: test
- python: "2.7"
- env: TOXENV=py27
- - stage: test
- python: "2.7"
- env: TOXENV=py27-nooptionals
- - stage: test
- python: "3.4"
- env: TOXENV=py34
- - stage: test
- python: "3.5"
- env: TOXENV=py35
- - stage: test
- python: "3.6"
- env: TOXENV=py36
- - stage: test
- python: "3.7"
- env: TOXENV=py37
- - stage: test
- python: "3.8"
- env: TOXENV=py38
- - stage: test
- python: "3.9"
- env: TOXENV=py39
- - stage: test
- python: "3.9"
- env: TOXENV=py39-nooptionals
- - stage: test
- python: "pypy"
- env: TOXENV=pypy
- - stage: test
- python: "pypy3"
- env: TOXENV=pypy3
-
-install:
- - pip install tox
-
-script:
- - tox
-
-notifications:
- email: false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/MAINTAINERS.md
new/client_python-0.10.1/MAINTAINERS.md
--- old/client_python-0.9.0/MAINTAINERS.md 2020-11-16 14:26:28.000000000
+0100
+++ new/client_python-0.10.1/MAINTAINERS.md 2021-04-08 18:30:13.000000000
+0200
@@ -1 +1 @@
-* Brian Brazil <[email protected]>
+* Chris Marchbanks <[email protected]> @csmarchbanks
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/README.md
new/client_python-0.10.1/README.md
--- old/client_python-0.9.0/README.md 2020-11-16 14:26:28.000000000 +0100
+++ new/client_python-0.10.1/README.md 2021-04-08 18:30:13.000000000 +0200
@@ -6,7 +6,7 @@
**One**: Install the client:
```
-pip install prometheus_client
+pip install prometheus-client
```
**Two**: Paste the following into a Python interpreter:
@@ -447,6 +447,17 @@
gb.start(10.0)
```
+Graphite
[tags](https://grafana.com/blog/2018/01/11/graphite-1.1-teaching-an-old-dog-new-tricks/)
are also supported.
+
+```python
+from prometheus_client.bridge.graphite import GraphiteBridge
+
+gb = GraphiteBridge(('graphite.your.org', 2003), tags=True)
+c = Counter('my_requests_total', 'HTTP Failures', ['method', 'endpoint'])
+c.labels('get', '/').inc()
+gb.push()
+```
+
## Custom Collectors
Sometimes it is not possible to directly instrument code, as it is not
@@ -468,7 +479,7 @@
REGISTRY.register(CustomCollector())
```
-`SummaryMetricFamily` and `HistogramMetricFamily` work similarly.
+`SummaryMetricFamily`, `HistogramMetricFamily` and `InfoMetricFamily` work
similarly.
A collector may implement a `describe` method which returns metrics in the same
format as `collect` (though you don't have to include the samples). This is
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/SECURITY.md
new/client_python-0.10.1/SECURITY.md
--- old/client_python-0.9.0/SECURITY.md 1970-01-01 01:00:00.000000000 +0100
+++ new/client_python-0.10.1/SECURITY.md 2021-04-08 18:30:13.000000000
+0200
@@ -0,0 +1,6 @@
+# Reporting a security issue
+
+The Prometheus security policy, including how to report vulnerabilities, can be
+found here:
+
+https://prometheus.io/docs/operating/security/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/client_python-0.9.0/prometheus_client/bridge/graphite.py
new/client_python-0.10.1/prometheus_client/bridge/graphite.py
--- old/client_python-0.9.0/prometheus_client/bridge/graphite.py
2020-11-16 14:26:28.000000000 +0100
+++ new/client_python-0.10.1/prometheus_client/bridge/graphite.py
2021-04-08 18:30:13.000000000 +0200
@@ -46,9 +46,10 @@
class GraphiteBridge(object):
- def __init__(self, address, registry=REGISTRY, timeout_seconds=30,
_timer=time.time):
+ def __init__(self, address, registry=REGISTRY, timeout_seconds=30,
_timer=time.time, tags=False):
self._address = address
self._registry = registry
+ self._tags = tags
self._timeout = timeout_seconds
self._timer = _timer
@@ -63,8 +64,14 @@
for metric in self._registry.collect():
for s in metric.samples:
if s.labels:
- labelstr = '.' + '.'.join(
- ['{0}.{1}'.format(
+ if self._tags:
+ sep = ';'
+ fmt = '{0}={1}'
+ else:
+ sep = '.'
+ fmt = '{0}.{1}'
+ labelstr = sep + sep.join(
+ [fmt.format(
_sanitize(k), _sanitize(v))
for k, v in sorted(s.labels.items())])
else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/prometheus_client/exposition.py
new/client_python-0.10.1/prometheus_client/exposition.py
--- old/client_python-0.9.0/prometheus_client/exposition.py 2020-11-16
14:26:28.000000000 +0100
+++ new/client_python-0.10.1/prometheus_client/exposition.py 2021-04-08
18:30:13.000000000 +0200
@@ -17,22 +17,86 @@
from BaseHTTPServer import BaseHTTPRequestHandler
from SocketServer import ThreadingMixIn
- from urllib2 import build_opener, HTTPHandler, Request
+ from urllib2 import (
+ build_opener, HTTPError, HTTPHandler, HTTPRedirectHandler, Request,
+ )
from urlparse import parse_qs, urlparse
except ImportError:
# Python 3
from http.server import BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
+ from urllib.error import HTTPError
from urllib.parse import parse_qs, quote_plus, urlparse
- from urllib.request import build_opener, HTTPHandler, Request
+ from urllib.request import (
+ build_opener, HTTPHandler, HTTPRedirectHandler, Request,
+ )
CONTENT_TYPE_LATEST = str('text/plain; version=0.0.4; charset=utf-8')
"""Content type of the latest text format"""
-
+PYTHON27_OR_OLDER = sys.version_info < (3, )
PYTHON26_OR_OLDER = sys.version_info < (2, 7)
PYTHON376_OR_NEWER = sys.version_info > (3, 7, 5)
+class _PrometheusRedirectHandler(HTTPRedirectHandler):
+ """
+ Allow additional methods (e.g. PUT) and data forwarding in redirects.
+
+ Use of this class constitute a user's explicit agreement to the
+ redirect responses the Prometheus client will receive when using it.
+ You should only use this class if you control or otherwise trust the
+ redirect behavior involved and are certain it is safe to full transfer
+ the original request (method and data) to the redirected URL. For
+ example, if you know there is a cosmetic URL redirect in front of a
+ local deployment of a Prometheus server, and all redirects are safe,
+ this is the class to use to handle redirects in that case.
+
+ The standard HTTPRedirectHandler does not forward request data nor
+ does it allow redirected PUT requests (which Prometheus uses for some
+ operations, for example `push_to_gateway`) because these cannot
+ generically guarantee no violations of HTTP RFC 2616 requirements for
+ the user to explicitly confirm redirects that could have unexpected
+ side effects (such as rendering a PUT request non-idempotent or
+ creating multiple resources not named in the original request).
+ """
+
+ def redirect_request(self, req, fp, code, msg, headers, newurl):
+ """
+ Apply redirect logic to a request.
+
+ See parent HTTPRedirectHandler.redirect_request for parameter info.
+
+ If the redirect is disallowed, this raises the corresponding HTTP
error.
+ If the redirect can't be determined, return None to allow other
handlers
+ to try. If the redirect is allowed, return the new request.
+
+ This method specialized for the case when (a) the user knows that the
+ redirect will not cause unacceptable side effects for any request
method,
+ and (b) the user knows that any request data should be passed through
to
+ the redirect. If either condition is not met, this should not be used.
+ """
+ # note that requests being provided by a handler will use get_method to
+ # indicate the method, by monkeypatching this, instead of setting the
+ # Request object's method attribute.
+ m = getattr(req, "method", req.get_method())
+ if not (code in (301, 302, 303, 307) and m in ("GET", "HEAD")
+ or code in (301, 302, 303) and m in ("POST", "PUT")):
+ raise HTTPError(req.full_url, code, msg, headers, fp)
+ new_request = Request(
+ newurl.replace(' ', '%20'), # space escaping in new url if needed.
+ headers=req.headers,
+ origin_req_host=req.origin_req_host,
+ unverifiable=True,
+ data=req.data,
+ )
+ if PYTHON27_OR_OLDER:
+ # the `method` attribute did not exist for Request in Python 2.7.
+ new_request.get_method = lambda: m
+ else:
+ new_request.method = m
+ return new_request
+
+
def _bake_output(registry, accept_header, params):
"""Bake output for metrics output."""
encoder, content_type = choose_encoder(accept_header)
@@ -49,8 +113,14 @@
# Prepare parameters
accept_header = environ.get('HTTP_ACCEPT')
params = parse_qs(environ.get('QUERY_STRING', ''))
- # Bake output
- status, header, output = _bake_output(registry, accept_header, params)
+ if environ['PATH_INFO'] == '/favicon.ico':
+ # Serve empty response for browsers
+ status = '200 OK'
+ header = ('', '')
+ output = b''
+ else:
+ # Bake output
+ status, header, output = _bake_output(registry, accept_header,
params)
# Return output
start_response(status, [header])
return [output]
@@ -141,7 +211,7 @@
raise
for suffix, lines in sorted(om_samples.items()):
- output.append('# HELP {0}{1} {2}\n'.format(metric.name, suffix,
+ output.append('# HELP {0}{1} {2}\n'.format(metric.name, suffix,
metric.documentation.replace('\\', r'\\').replace('\n', r'\n')))
output.append('# TYPE {0}{1} gauge\n'.format(metric.name, suffix))
output.extend(lines)
@@ -205,17 +275,14 @@
os.rename(tmppath, path)
-def default_handler(url, method, timeout, headers, data):
- """Default handler that implements HTTP/HTTPS connections.
-
- Used by the push_to_gateway functions. Can be re-used by other handlers."""
+def _make_handler(url, method, timeout, headers, data, base_handler):
def handle():
request = Request(url, data=data)
request.get_method = lambda: method
for k, v in headers:
request.add_header(k, v)
- resp = build_opener(HTTPHandler).open(request, timeout=timeout)
+ resp = build_opener(base_handler).open(request, timeout=timeout)
if resp.code >= 400:
raise IOError("error talking to pushgateway: {0} {1}".format(
resp.code, resp.msg))
@@ -223,6 +290,28 @@
return handle
+def default_handler(url, method, timeout, headers, data):
+ """Default handler that implements HTTP/HTTPS connections.
+
+ Used by the push_to_gateway functions. Can be re-used by other handlers."""
+
+ return _make_handler(url, method, timeout, headers, data, HTTPHandler)
+
+
+def passthrough_redirect_handler(url, method, timeout, headers, data):
+ """
+ Handler that automatically trusts redirect responses for all HTTP methods.
+
+ Augments standard HTTPRedirectHandler capability by permitting PUT
requests,
+ preserving the method upon redirect, and passing through all headers and
+ data from the original request. Only use this handler if you control or
+ trust the source of redirect responses you encounter when making requests
+ via the Prometheus client. This handler will simply repeat the identical
+ request, including same method and data, to the new redirect URL."""
+
+ return _make_handler(url, method, timeout, headers, data,
_PrometheusRedirectHandler)
+
+
def basic_auth_handler(url, method, timeout, headers, data, username=None,
password=None):
"""Handler that implements HTTP/HTTPS connections with Basic Auth.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/prometheus_client/metrics.py
new/client_python-0.10.1/prometheus_client/metrics.py
--- old/client_python-0.9.0/prometheus_client/metrics.py 2020-11-16
14:26:28.000000000 +0100
+++ new/client_python-0.10.1/prometheus_client/metrics.py 2021-04-08
18:30:13.000000000 +0200
@@ -186,6 +186,11 @@
with self._lock:
del self._metrics[labelvalues]
+ def clear(self):
+ """Remove all labelsets from the metric"""
+ with self._lock:
+ self._metrics = {}
+
def _samples(self):
if self._is_parent():
return self._multi_samples()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/client_python-0.9.0/prometheus_client/multiprocess.py
new/client_python-0.10.1/prometheus_client/multiprocess.py
--- old/client_python-0.9.0/prometheus_client/multiprocess.py 2020-11-16
14:26:28.000000000 +0100
+++ new/client_python-0.10.1/prometheus_client/multiprocess.py 2021-04-08
18:30:13.000000000 +0200
@@ -4,6 +4,7 @@
import glob
import json
import os
+import warnings
from .metrics_core import Metric
from .mmap_dict import MmapedDict
@@ -23,9 +24,13 @@
def __init__(self, registry, path=None):
if path is None:
- path = os.environ.get('prometheus_multiproc_dir')
+ # 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']
+ warnings.warn("prometheus_multiproc_dir variable has been
deprecated in favor of the upper case naming PROMETHEUS_MULTIPROC_DIR",
DeprecationWarning)
+ path = os.environ.get('PROMETHEUS_MULTIPROC_DIR')
if not path or not os.path.isdir(path):
- raise ValueError('env prometheus_multiproc_dir is not set or not a
directory')
+ raise ValueError('env PROMETHEUS_MULTIPROC_DIR is not set or not a
directory')
self._path = path
if registry:
registry.register(self)
@@ -66,7 +71,7 @@
# the file is missing
continue
raise
- for key, value, pos in file_values:
+ for key, value, _ in file_values:
metric_name, name, labels, labels_key = _parse_key(key)
metric = metrics.get(metric_name)
@@ -152,7 +157,7 @@
def mark_process_dead(pid, path=None):
"""Do bookkeeping for when one process dies in a multi-process setup."""
if path is None:
- path = os.environ.get('prometheus_multiproc_dir')
+ path = os.environ.get('PROMETHEUS_MULTIPROC_DIR',
os.environ.get('prometheus_multiproc_dir'))
for f in glob.glob(os.path.join(path, 'gauge_livesum_{0}.db'.format(pid))):
os.remove(f)
for f in glob.glob(os.path.join(path, 'gauge_liveall_{0}.db'.format(pid))):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/client_python-0.9.0/prometheus_client/openmetrics/parser.py
new/client_python-0.10.1/prometheus_client/openmetrics/parser.py
--- old/client_python-0.9.0/prometheus_client/openmetrics/parser.py
2020-11-16 14:26:28.000000000 +0100
+++ new/client_python-0.10.1/prometheus_client/openmetrics/parser.py
2021-04-08 18:30:13.000000000 +0200
@@ -529,10 +529,7 @@
if parts[1] == 'HELP':
if documentation is not None:
raise ValueError("More than one HELP for metric: " + line)
- if len(parts) == 4:
- documentation = _unescape_help(parts[3])
- elif len(parts) == 3:
- raise ValueError("Invalid line: " + line)
+ documentation = _unescape_help(parts[3])
elif parts[1] == 'TYPE':
if typ is not None:
raise ValueError("More than one TYPE for metric: " + line)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/prometheus_client/values.py
new/client_python-0.10.1/prometheus_client/values.py
--- old/client_python-0.9.0/prometheus_client/values.py 2020-11-16
14:26:28.000000000 +0100
+++ new/client_python-0.10.1/prometheus_client/values.py 2021-04-08
18:30:13.000000000 +0200
@@ -2,6 +2,7 @@
import os
from threading import Lock
+import warnings
from .mmap_dict import mmap_key, MmapedDict
@@ -51,6 +52,10 @@
def __init__(self, typ, metric_name, name, labelnames, labelvalues,
multiprocess_mode='', **kwargs):
self._params = typ, metric_name, name, labelnames, labelvalues,
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']
+ warnings.warn("prometheus_multiproc_dir variable has been
deprecated in favor of the upper case naming PROMETHEUS_MULTIPROC_DIR",
DeprecationWarning)
with lock:
self.__check_for_pid_change()
self.__reset()
@@ -64,7 +69,7 @@
file_prefix = typ
if file_prefix not in files:
filename = os.path.join(
- os.environ['prometheus_multiproc_dir'],
+ os.environ.get('PROMETHEUS_MULTIPROC_DIR'),
'{0}_{1}.db'.format(file_prefix, pid['value']))
files[file_prefix] = MmapedDict(filename)
@@ -108,7 +113,7 @@
# This needs to be chosen before the first metric is constructed,
# and as that may be in some arbitrary library the user/admin has
# no control over we use an environment variable.
- if 'prometheus_multiproc_dir' in os.environ:
+ if 'prometheus_multiproc_dir' in os.environ or 'PROMETHEUS_MULTIPROC_DIR'
in os.environ:
return MultiProcessValue()
else:
return MutexValue
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/setup.py
new/client_python-0.10.1/setup.py
--- old/client_python-0.9.0/setup.py 2020-11-16 14:26:28.000000000 +0100
+++ new/client_python-0.10.1/setup.py 2021-04-08 18:30:13.000000000 +0200
@@ -12,7 +12,7 @@
setup(
name="prometheus_client",
- version="0.9.0",
+ version="0.10.1",
author="Brian Brazil",
author_email="[email protected]",
description="Python client for the Prometheus monitoring system.",
@@ -31,6 +31,7 @@
'twisted': ['twisted'],
},
test_suite="tests",
+ python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
classifiers=[
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
@@ -38,7 +39,6 @@
"Intended Audience :: System Administrators",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
- "Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/client_python-0.9.0/tests/openmetrics/test_exposition.py
new/client_python-0.10.1/tests/openmetrics/test_exposition.py
--- old/client_python-0.9.0/tests/openmetrics/test_exposition.py
2020-11-16 14:26:28.000000000 +0100
+++ new/client_python-0.10.1/tests/openmetrics/test_exposition.py
2021-04-08 18:30:13.000000000 +0200
@@ -48,6 +48,12 @@
self.assertEqual(b'# HELP cc A counter\n# TYPE cc counter\ncc_total
1.0\ncc_created 123.456\n# EOF\n',
generate_latest(self.registry))
+ def test_counter_unit(self):
+ c = Counter('cc_seconds', 'A counter', registry=self.registry,
unit="seconds")
+ c.inc()
+ self.assertEqual(b'# HELP cc_seconds A counter\n# TYPE cc_seconds
counter\n# UNIT cc_seconds seconds\ncc_seconds_total 1.0\ncc_seconds_created
123.456\n# EOF\n',
+ generate_latest(self.registry))
+
def test_gauge(self):
g = Gauge('gg', 'A gauge', registry=self.registry)
g.set(17)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/tests/openmetrics/test_parser.py
new/client_python-0.10.1/tests/openmetrics/test_parser.py
--- old/client_python-0.9.0/tests/openmetrics/test_parser.py 2020-11-16
14:26:28.000000000 +0100
+++ new/client_python-0.10.1/tests/openmetrics/test_parser.py 2021-04-08
18:30:13.000000000 +0200
@@ -221,6 +221,16 @@
cfm.add_sample("a_total", {}, 0.0, Timestamp(123, 0), Exemplar({"a":
"b"}, 0.5))
self.assertEqual([cfm], list(families))
+ def test_counter_exemplars_empty_brackets(self):
+ families = text_string_to_metric_families("""# TYPE a counter
+# HELP a help
+a_total{} 0 123 # {a="b"} 0.5
+# EOF
+""")
+ cfm = CounterMetricFamily("a", "help")
+ cfm.add_sample("a_total", {}, 0.0, Timestamp(123, 0), Exemplar({"a":
"b"}, 0.5))
+ self.assertEqual([cfm], list(families))
+
def test_simple_info(self):
families = text_string_to_metric_families("""# TYPE a info
# HELP a help
@@ -409,11 +419,15 @@
# HELP a he\\n\\\\l\\tp
a_total{foo="b\\"a\\nr"} 1
a_total{foo="b\\\\a\\z"} 2
+a_total{foo="b\\"a\\nr # "} 3
+a_total{foo="b\\\\a\\z # "} 4
# EOF
""")
metric_family = CounterMetricFamily("a", "he\n\\l\\tp", labels=["foo"])
metric_family.add_metric(["b\"a\nr"], 1)
metric_family.add_metric(["b\\a\\z"], 2)
+ metric_family.add_metric(["b\"a\nr # "], 3)
+ metric_family.add_metric(["b\\a\\z # "], 4)
self.assertEqual([metric_family], list(families))
def test_null_byte(self):
@@ -591,6 +605,10 @@
foo_count 17.0
foo_sum 324789.3
foo_created 1.520430000123e+09
+# HELP bar histogram Testing with labels
+# TYPE bar histogram
+bar_bucket{a="b",le="+Inf"} 0.0
+bar_bucket{a="c",le="+Inf"} 0.0
# EOF
"""
families = list(text_string_to_metric_families(text))
@@ -628,9 +646,14 @@
('a{a="1",b="2",} 1\n# EOF\n'),
# Invalid labels.
('a{1="1"} 1\n# EOF\n'),
+ ('a{1="1"}1\n# EOF\n'),
('a{a="1",a="1"} 1\n# EOF\n'),
+ ('a{a="1"b} 1\n# EOF\n'),
('a{1=" # "} 1\n# EOF\n'),
('a{a=" # ",a=" # "} 1\n# EOF\n'),
+ ('a{a=" # "}1\n# EOF\n'),
+ ('a{a=" # ",b=}1\n# EOF\n'),
+ ('a{a=" # "b}1\n# EOF\n'),
# Missing value.
('a\n# EOF\n'),
('a \n# EOF\n'),
@@ -667,6 +690,8 @@
('# HELP a x\n# HELP a x\n# EOF\n'),
('# TYPE a untyped\n# TYPE a untyped\n# EOF\n'),
('# UNIT a_s s\n# UNIT a_s s\n# EOF\n'),
+ # Bad metadata.
+ ('# FOO a x\n# EOF\n'),
# Bad metric names.
('0a 1\n# EOF\n'),
('a.b 1\n# EOF\n'),
@@ -706,6 +731,10 @@
'{a="23456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"}
1 1\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="+Inf"} 1 # {} 0x1p-3\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="+Inf"} 1 # {} 1 0x1p-3\n#
EOF\n'),
+ ('# TYPE a counter\na_total 1 1 # {id="a"} \n# EOF\n'),
+ ('# TYPE a counter\na_total 1 1 # id="a"} 1\n# EOF\n'),
+ ('# TYPE a counter\na_total 1 1 #id=" # "} 1\n# EOF\n'),
+ ('# TYPE a counter\na_total 1 1 id=" # "} 1\n# EOF\n'),
# Exemplars on unallowed samples.
('# TYPE a histogram\na_sum 1 # {a="b"} 0.5\n# EOF\n'),
('# TYPE a gaugehistogram\na_sum 1 # {a="b"} 0.5\n# EOF\n'),
@@ -750,13 +779,18 @@
('# TYPE a summary\na_sum -1\n# EOF\n'),
('# TYPE a summary\na_count -1\n# EOF\n'),
('# TYPE a summary\na{quantile="0.5"} -1\n# EOF\n'),
+ # Bad info and stateset values.
+ ('# TYPE a info\na_info{foo="bar"} 2\n# EOF\n'),
+ ('# TYPE a stateset\na{a="bar"} 2\n# EOF\n'),
# Bad histograms.
('# TYPE a histogram\na_sum 1\n# EOF\n'),
- ('# TYPE a histogram\na_bucket{le="+Inf"} 0\n#a_sum 0\n# EOF\n'),
- ('# TYPE a histogram\na_bucket{le="+Inf"} 0\n#a_count 0\n# EOF\n'),
+ ('# TYPE a histogram\na_bucket{le="+Inf"} 0\na_sum 0\n# EOF\n'),
+ ('# TYPE a histogram\na_bucket{le="+Inf"} 0\na_count 0\n# EOF\n'),
+ ('# TYPE a histogram\na_bucket{le="-1"} 0\na_bucket{le="+Inf"}
0\na_sum 0\na_count 0\n# EOF\n'),
('# TYPE a gaugehistogram\na_gsum 1\n# EOF\n'),
('# TYPE a gaugehistogram\na_bucket{le="+Inf"} 0\na_gsum 0\n#
EOF\n'),
('# TYPE a gaugehistogram\na_bucket{le="+Inf"} 0\na_gcount 0\n#
EOF\n'),
+ ('# TYPE a gaugehistogram\na_bucket{le="+Inf"} 1\na_gsum
-1\na_gcount 1\n# EOF\n'),
('# TYPE a histogram\na_count 1\na_bucket{le="+Inf"} 0\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="+Inf"} 0\na_count 1\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="+INF"} 0\n# EOF\n'),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/tests/test_core.py
new/client_python-0.10.1/tests/test_core.py
--- old/client_python-0.9.0/tests/test_core.py 2020-11-16 14:26:28.000000000
+0100
+++ new/client_python-0.10.1/tests/test_core.py 2021-04-08 18:30:13.000000000
+0200
@@ -456,6 +456,15 @@
self.assertEqual(None, self.registry.get_sample_value('c_total', {'l':
'x'}))
self.assertEqual(2, self.registry.get_sample_value('c_total', {'l':
'y'}))
+ def test_clear(self):
+ self.counter.labels('x').inc()
+ self.counter.labels('y').inc(2)
+ self.assertEqual(1, self.registry.get_sample_value('c_total', {'l':
'x'}))
+ self.assertEqual(2, self.registry.get_sample_value('c_total', {'l':
'y'}))
+ self.counter.clear()
+ self.assertEqual(None, self.registry.get_sample_value('c_total', {'l':
'x'}))
+ self.assertEqual(None, self.registry.get_sample_value('c_total', {'l':
'y'}))
+
def test_incorrect_label_count_raises(self):
self.assertRaises(ValueError, self.counter.labels)
self.assertRaises(ValueError, self.counter.labels, 'a', 'b')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/tests/test_exposition.py
new/client_python-0.10.1/tests/test_exposition.py
--- old/client_python-0.9.0/tests/test_exposition.py 2020-11-16
14:26:28.000000000 +0100
+++ new/client_python-0.10.1/tests/test_exposition.py 2021-04-08
18:30:13.000000000 +0200
@@ -14,6 +14,7 @@
from prometheus_client.core import GaugeHistogramMetricFamily, Timestamp
from prometheus_client.exposition import (
basic_auth_handler, default_handler, MetricsHandler,
+ passthrough_redirect_handler,
)
if sys.version_info < (2, 7):
@@ -208,6 +209,8 @@
class TestPushGateway(unittest.TestCase):
def setUp(self):
+ redirect_flag = 'testFlag'
+ self.redirect_flag = redirect_flag # preserve a copy for downstream
test assertions
self.registry = CollectorRegistry()
self.counter = Gauge('g', 'help', registry=self.registry)
self.requests = requests = []
@@ -216,6 +219,11 @@
def do_PUT(self):
if 'with_basic_auth' in self.requestline and
self.headers['authorization'] != 'Basic Zm9vOmJhcg==':
self.send_response(401)
+ elif 'redirect' in self.requestline and redirect_flag not in
self.requestline:
+ # checks for an initial test request with 'redirect' but
without the redirect_flag,
+ # and simulates a redirect to a url with the redirect_flag
(which will produce a 201)
+ self.send_response(301)
+ self.send_header('Location', getattr(self,
'redirect_address', None))
else:
self.send_response(201)
length = int(self.headers['content-length'])
@@ -225,6 +233,22 @@
do_POST = do_PUT
do_DELETE = do_PUT
+ # set up a separate server to serve a fake redirected request.
+ # the redirected URL will have `redirect_flag` added to it,
+ # which will cause the request handler to return 201.
+ httpd_redirect = HTTPServer(('localhost', 0), TestHandler)
+ self.redirect_address = TestHandler.redirect_address = \
+
'http://localhost:{0}/{1}'.format(httpd_redirect.server_address[1],
redirect_flag)
+
+ class TestRedirectServer(threading.Thread):
+ def run(self):
+ httpd_redirect.handle_request()
+
+ self.redirect_server = TestRedirectServer()
+ self.redirect_server.daemon = True
+ self.redirect_server.start()
+
+ # set up the normal server to serve the example requests across test
cases.
httpd = HTTPServer(('localhost', 0), TestHandler)
self.address = 'http://localhost:{0}'.format(httpd.server_address[1])
@@ -236,6 +260,7 @@
self.server.daemon = True
self.server.start()
+
def test_push(self):
push_to_gateway(self.address, "my_job", self.registry)
self.assertEqual(self.requests[0][0].command, 'PUT')
@@ -330,6 +355,27 @@
self.assertEqual(self.requests[0][0].headers.get('content-type'),
CONTENT_TYPE_LATEST)
self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g
gauge\ng 0.0\n')
+ def test_push_with_redirect_handler(self):
+ def my_redirect_handler(url, method, timeout, headers, data):
+ return passthrough_redirect_handler(url, method, timeout, headers,
data)
+
+ push_to_gateway(self.address, "my_job_with_redirect", self.registry,
handler=my_redirect_handler)
+ self.assertEqual(self.requests[0][0].command, 'PUT')
+ self.assertEqual(self.requests[0][0].path,
'/metrics/job/my_job_with_redirect')
+ self.assertEqual(self.requests[0][0].headers.get('content-type'),
CONTENT_TYPE_LATEST)
+ self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g
gauge\ng 0.0\n')
+
+ # ensure the redirect preserved request settings from the initial
request.
+ self.assertEqual(self.requests[0][0].command,
self.requests[1][0].command)
+ self.assertEqual(
+ self.requests[0][0].headers.get('content-type'),
+ self.requests[1][0].headers.get('content-type')
+ )
+ self.assertEqual(self.requests[0][1], self.requests[1][1])
+
+ # ensure the redirect took place at the expected redirect location.
+ self.assertEqual(self.requests[1][0].path, "/" + self.redirect_flag)
+
@unittest.skipIf(
sys.platform == "darwin",
"instance_ip_grouping_key() does not work on macOS."
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/tests/test_graphite_bridge.py
new/client_python-0.10.1/tests/test_graphite_bridge.py
--- old/client_python-0.9.0/tests/test_graphite_bridge.py 2020-11-16
14:26:28.000000000 +0100
+++ new/client_python-0.10.1/tests/test_graphite_bridge.py 2021-04-08
18:30:13.000000000 +0200
@@ -35,8 +35,11 @@
self.t.start()
# Explicitly use localhost as the target host, since connecting to
0.0.0.0 fails on Windows
- address = ('localhost', server.server_address[1])
- self.gb = GraphiteBridge(address, self.registry, _timer=fake_timer)
+ self.address = ('localhost', server.server_address[1])
+ self.gb = GraphiteBridge(self.address, self.registry,
_timer=fake_timer)
+
+ def _use_tags(self):
+ self.gb = GraphiteBridge(self.address, self.registry, tags=True,
_timer=fake_timer)
def test_nolabels(self):
gauge = Gauge('g', 'help', registry=self.registry)
@@ -56,6 +59,16 @@
self.assertEqual(b'labels.a.c.b.d 1.0 1434898897\n', self.data)
+ def test_labels_tags(self):
+ self._use_tags()
+ labels = Gauge('labels', 'help', ['a', 'b'], registry=self.registry)
+ labels.labels('c', 'd').inc()
+
+ self.gb.push()
+ self.t.join()
+
+ self.assertEqual(b'labels;a=c;b=d 1.0 1434898897\n', self.data)
+
def test_prefix(self):
labels = Gauge('labels', 'help', ['a', 'b'], registry=self.registry)
labels.labels('c', 'd').inc()
@@ -65,6 +78,16 @@
self.assertEqual(b'pre.fix.labels.a.c.b.d 1.0 1434898897\n', self.data)
+ def test_prefix_tags(self):
+ self._use_tags()
+ labels = Gauge('labels', 'help', ['a', 'b'], registry=self.registry)
+ labels.labels('c', 'd').inc()
+
+ self.gb.push(prefix='pre.fix')
+ self.t.join()
+
+ self.assertEqual(b'pre.fix.labels;a=c;b=d 1.0 1434898897\n', self.data)
+
def test_sanitizing(self):
labels = Gauge('labels', 'help', ['a'], registry=self.registry)
labels.labels('c.:8').inc()
@@ -73,3 +96,13 @@
self.t.join()
self.assertEqual(b'labels.a.c__8 1.0 1434898897\n', self.data)
+
+ def test_sanitizing_tags(self):
+ self._use_tags()
+ labels = Gauge('labels', 'help', ['a'], registry=self.registry)
+ labels.labels('c.:8').inc()
+
+ self.gb.push()
+ self.t.join()
+
+ self.assertEqual(b'labels;a=c__8 1.0 1434898897\n', self.data)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/tests/test_multiprocess.py
new/client_python-0.10.1/tests/test_multiprocess.py
--- old/client_python-0.9.0/tests/test_multiprocess.py 2020-11-16
14:26:28.000000000 +0100
+++ new/client_python-0.10.1/tests/test_multiprocess.py 2021-04-08
18:30:13.000000000 +0200
@@ -5,6 +5,7 @@
import shutil
import sys
import tempfile
+import warnings
from prometheus_client import mmap_dict, values
from prometheus_client.core import (
@@ -13,7 +14,9 @@
from prometheus_client.multiprocess import (
mark_process_dead, MultiProcessCollector,
)
-from prometheus_client.values import MultiProcessValue, MutexValue
+from prometheus_client.values import (
+ get_value_class, MultiProcessValue, MutexValue,
+)
if sys.version_info < (2, 7):
# We need the skip decorators from unittest2 on Python 2.6.
@@ -22,20 +25,50 @@
import unittest
-class TestMultiProcess(unittest.TestCase):
+class TestMultiProcessDeprecation(unittest.TestCase):
def setUp(self):
self.tempdir = tempfile.mkdtemp()
+
+ def tearDown(self):
+ os.environ.pop('prometheus_multiproc_dir', None)
+ os.environ.pop('PROMETHEUS_MULTIPROC_DIR', None)
+ values.ValueClass = MutexValue
+ shutil.rmtree(self.tempdir)
+
+ def test_deprecation_warning(self):
os.environ['prometheus_multiproc_dir'] = self.tempdir
+ with warnings.catch_warnings(record=True) as w:
+ values.ValueClass = get_value_class()
+ registry = CollectorRegistry()
+ collector = MultiProcessCollector(registry)
+ Counter('c', 'help', registry=None)
+
+ assert os.environ['PROMETHEUS_MULTIPROC_DIR'] == self.tempdir
+ assert len(w) == 1
+ assert issubclass(w[-1].category, DeprecationWarning)
+ assert "PROMETHEUS_MULTIPROC_DIR" in str(w[-1].message)
+
+ def test_mark_process_dead_respects_lowercase(self):
+ os.environ['prometheus_multiproc_dir'] = self.tempdir
+ # Just test that this does not raise with a lowercase env var. The
+ # logic is tested elsewhere.
+ mark_process_dead(123)
+
+
+class TestMultiProcess(unittest.TestCase):
+ def setUp(self):
+ self.tempdir = tempfile.mkdtemp()
+ os.environ['PROMETHEUS_MULTIPROC_DIR'] = self.tempdir
values.ValueClass = MultiProcessValue(lambda: 123)
self.registry = CollectorRegistry()
- self.collector = MultiProcessCollector(self.registry, self.tempdir)
+ self.collector = MultiProcessCollector(self.registry)
@property
def _value_class(self):
return
def tearDown(self):
- del os.environ['prometheus_multiproc_dir']
+ del os.environ['PROMETHEUS_MULTIPROC_DIR']
shutil.rmtree(self.tempdir)
values.ValueClass = MutexValue
@@ -80,7 +113,7 @@
self.assertEqual(0, self.registry.get_sample_value('g', {'pid':
'456'}))
g1.set(1)
g2.set(2)
- mark_process_dead(123, os.environ['prometheus_multiproc_dir'])
+ mark_process_dead(123)
self.assertEqual(1, self.registry.get_sample_value('g', {'pid':
'123'}))
self.assertEqual(2, self.registry.get_sample_value('g', {'pid':
'456'}))
@@ -94,7 +127,7 @@
g2.set(2)
self.assertEqual(1, self.registry.get_sample_value('g', {'pid':
'123'}))
self.assertEqual(2, self.registry.get_sample_value('g', {'pid':
'456'}))
- mark_process_dead(123, os.environ['prometheus_multiproc_dir'])
+ mark_process_dead(123, os.environ['PROMETHEUS_MULTIPROC_DIR'])
self.assertEqual(None, self.registry.get_sample_value('g', {'pid':
'123'}))
self.assertEqual(2, self.registry.get_sample_value('g', {'pid':
'456'}))
@@ -124,7 +157,7 @@
g1.set(1)
g2.set(2)
self.assertEqual(3, self.registry.get_sample_value('g'))
- mark_process_dead(123, os.environ['prometheus_multiproc_dir'])
+ mark_process_dead(123, os.environ['PROMETHEUS_MULTIPROC_DIR'])
self.assertEqual(2, self.registry.get_sample_value('g'))
def test_namespace_subsystem(self):
@@ -151,7 +184,7 @@
# can not inspect the files cache directly, as it's a closure, so we
# check for the actual files themselves
def files():
- fs = os.listdir(os.environ['prometheus_multiproc_dir'])
+ fs = os.listdir(os.environ['PROMETHEUS_MULTIPROC_DIR'])
fs.sort()
return fs
@@ -240,7 +273,7 @@
pid = 1
h.labels(**labels).observe(5)
- path = os.path.join(os.environ['prometheus_multiproc_dir'], '*.db')
+ path = os.path.join(os.environ['PROMETHEUS_MULTIPROC_DIR'], '*.db')
files = glob.glob(path)
metrics = dict(
(m.name, m) for m in self.collector.merge(files, accumulate=False)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/tests/test_wsgi.py
new/client_python-0.10.1/tests/test_wsgi.py
--- old/client_python-0.9.0/tests/test_wsgi.py 2020-11-16 14:26:28.000000000
+0100
+++ new/client_python-0.10.1/tests/test_wsgi.py 2021-04-08 18:30:13.000000000
+0200
@@ -1,10 +1,12 @@
from __future__ import absolute_import, unicode_literals
+import sys
+import unittest
from unittest import TestCase
from wsgiref.util import setup_testing_defaults
from prometheus_client import CollectorRegistry, Counter, make_wsgi_app
-from prometheus_client.exposition import CONTENT_TYPE_LATEST
+from prometheus_client.exposition import _bake_output, CONTENT_TYPE_LATEST
class WSGITest(TestCase):
@@ -65,3 +67,22 @@
def test_report_metrics_4(self):
self.validate_metrics("failed_requests", "Number of failed requests",
7)
+
+ @unittest.skipIf(sys.version_info < (3, 3), "Test requires Python 3.3+.")
+ def test_favicon_path(self):
+ from unittest.mock import patch
+
+ # Create mock to enable counting access of _bake_output
+ with patch("prometheus_client.exposition._bake_output",
side_effect=_bake_output) as mock:
+ # Create and run WSGI app
+ app = make_wsgi_app(self.registry)
+ # Try accessing the favicon path
+ favicon_environ = dict(self.environ)
+ favicon_environ['PATH_INFO'] = '/favicon.ico'
+ outputs = app(favicon_environ, self.capture)
+ # Test empty response
+ self.assertEqual(outputs, [b''])
+ self.assertEqual(mock.call_count, 0)
+ # Try accessing normal paths
+ app(self.environ, self.capture)
+ self.assertEqual(mock.call_count, 1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/client_python-0.9.0/tox.ini
new/client_python-0.10.1/tox.ini
--- old/client_python-0.9.0/tox.ini 2020-11-16 14:26:28.000000000 +0100
+++ new/client_python-0.10.1/tox.ini 2021-04-08 18:30:13.000000000 +0200
@@ -1,5 +1,5 @@
[tox]
-envlist =
coverage-clean,py26,py27,py34,py35,py36,py37,py38,py39,pypy,pypy3,{py27,py39}-nooptionals,coverage-report,flake8,isort
+envlist =
coverage-clean,py2.7,py3.4,py3.5,py3.6,py3.7,py3.8,py3.9,pypy2.7,pypy3.7,{py2.7,py3.9}-nooptionals,coverage-report,flake8,isort
[base]
@@ -7,21 +7,12 @@
coverage
pytest
-[testenv:py26]
-; Last pytest and py version supported on py26 .
-deps =
- unittest2
- py==1.4.31
- pytest==2.9.2
- coverage
- futures
-
-[testenv:py27]
+[testenv:py2.7]
deps =
{[base]deps}
futures
-[testenv:pypy]
+[testenv:pypy2.7]
deps =
{[base]deps}
futures
@@ -29,18 +20,18 @@
[testenv]
deps =
{[base]deps}
- {py27,py37,pypy,pypy3}: twisted
- {py37,pypy3}: asgiref
+ {py2.7,py3.7,pypy2.7,pypy3.7}: twisted
+ {py3.7,pypy3.7}: asgiref
commands = coverage run --parallel -m pytest {posargs}
; Ensure test suite passes if no optional dependencies are present.
-[testenv:py27-nooptionals]
+[testenv:py2.7-nooptionals]
deps =
{[base]deps}
futures
commands = coverage run --parallel -m pytest {posargs}
-[testenv:py39-nooptionals]
+[testenv:py3.9-nooptionals]
commands = coverage run --parallel -m pytest {posargs}
[testenv:coverage-clean]