From 4c636a9795ad7cfc39dddf10e17a24e9eac1a55b Mon Sep 17 00:00:00 2001 From: rdobuilder Date: Jan 08 2024 08:07:16 +0000 Subject: Update to 0.17.1 Related-to: https://review.rdoproject.org/r/q/I74624a4a7f88cc2f4b47b62a7ead8d4481e0e451 --- diff --git a/.python-prometheus_client.metadata b/.python-prometheus_client.metadata new file mode 100644 index 0000000..f204f7e --- /dev/null +++ b/.python-prometheus_client.metadata @@ -0,0 +1 @@ +041e8eff627eb0947a18e380ad9b69e0e26925ff SOURCES/prometheus_client-0.17.1.tar.gz diff --git a/SOURCES/0001-Remove-the-bundled-decorator-package.patch b/SOURCES/0001-Remove-the-bundled-decorator-package.patch new file mode 100644 index 0000000..e6865b1 --- /dev/null +++ b/SOURCES/0001-Remove-the-bundled-decorator-package.patch @@ -0,0 +1,520 @@ +From 6f211537cc51525fddc61b6af56ec814ba44fc40 Mon Sep 17 00:00:00 2001 +From: mprahl +Date: Thu, 16 Jun 2022 22:26:53 +0200 +Subject: [PATCH] Remove the bundled decorator package +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Co-Authored-By: Miro Hrončok +--- + NOTICE | 3 - + prometheus_client/context_managers.py | 2 +- + prometheus_client/decorator.py | 427 -------------------------- + setup.py | 1 + + tests/test_core.py | 12 +- + 5 files changed, 13 insertions(+), 432 deletions(-) + delete mode 100644 prometheus_client/decorator.py + +diff --git a/NOTICE b/NOTICE +index 59efb6c..0675ae1 100644 +--- a/NOTICE ++++ b/NOTICE +@@ -1,5 +1,2 @@ + Prometheus instrumentation library for Python applications + Copyright 2015 The Prometheus Authors +- +-This product bundles decorator 4.0.10 which is available under a "2-clause BSD" +-license. For details, see prometheus_client/decorator.py. +diff --git a/prometheus_client/context_managers.py b/prometheus_client/context_managers.py +index b229b17..32eb6f6 100644 +--- a/prometheus_client/context_managers.py ++++ b/prometheus_client/context_managers.py +@@ -6,7 +6,7 @@ from typing import Any, Callable, Optional, Type, TYPE_CHECKING, TypeVar + if sys.version_info >= (3, 8, 0): + from typing import Literal + +-from .decorator import decorate ++from decorator import decorate + + if TYPE_CHECKING: + from . import Counter +diff --git a/prometheus_client/decorator.py b/prometheus_client/decorator.py +deleted file mode 100644 +index 1ad2c97..0000000 +--- a/prometheus_client/decorator.py ++++ /dev/null +@@ -1,427 +0,0 @@ +-# ######################### LICENSE ############################ # +- +-# Copyright (c) 2005-2016, Michele Simionato +-# All rights reserved. +- +-# Redistribution and use in source and binary forms, with or without +-# modification, are permitted provided that the following conditions are +-# met: +- +-# Redistributions of source code must retain the above copyright +-# notice, this list of conditions and the following disclaimer. +-# Redistributions in bytecode form must reproduce the above copyright +-# notice, this list of conditions and the following disclaimer in +-# the documentation and/or other materials provided with the +-# distribution. +- +-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +-# HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +-# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +-# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +-# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +-# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +-# DAMAGE. +- +-""" +-Decorator module, see http://pypi.python.org/pypi/decorator +-for the documentation. +-""" +-from __future__ import print_function +- +-import collections +-import inspect +-import itertools +-import operator +-import re +-import sys +- +-__version__ = '4.0.10' +- +-if sys.version_info >= (3,): +- from inspect import getfullargspec +- +- +- def get_init(cls): +- return cls.__init__ +-else: +- class getfullargspec(object): +- "A quick and dirty replacement for getfullargspec for Python 2.X" +- +- def __init__(self, f): +- self.args, self.varargs, self.varkw, self.defaults = \ +- inspect.getargspec(f) +- self.kwonlyargs = [] +- self.kwonlydefaults = None +- +- def __iter__(self): +- yield self.args +- yield self.varargs +- yield self.varkw +- yield self.defaults +- +- getargspec = inspect.getargspec +- +- +- def get_init(cls): +- return cls.__init__.__func__ +- +-# getargspec has been deprecated in Python 3.5 +-ArgSpec = collections.namedtuple( +- 'ArgSpec', 'args varargs varkw defaults') +- +- +-def getargspec(f): +- """A replacement for inspect.getargspec""" +- spec = getfullargspec(f) +- return ArgSpec(spec.args, spec.varargs, spec.varkw, spec.defaults) +- +- +-DEF = re.compile(r'\s*def\s*([_\w][_\w\d]*)\s*\(') +- +- +-# basic functionality +-class FunctionMaker(object): +- """ +- An object with the ability to create functions with a given signature. +- It has attributes name, doc, module, signature, defaults, dict and +- methods update and make. +- """ +- +- # Atomic get-and-increment provided by the GIL +- _compile_count = itertools.count() +- +- def __init__(self, func=None, name=None, signature=None, +- defaults=None, doc=None, module=None, funcdict=None): +- self.shortsignature = signature +- if func: +- # func can be a class or a callable, but not an instance method +- self.name = func.__name__ +- if self.name == '': # small hack for lambda functions +- self.name = '_lambda_' +- self.doc = func.__doc__ +- self.module = func.__module__ +- if inspect.isfunction(func): +- argspec = getfullargspec(func) +- self.annotations = getattr(func, '__annotations__', {}) +- for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs', +- 'kwonlydefaults'): +- setattr(self, a, getattr(argspec, a)) +- for i, arg in enumerate(self.args): +- setattr(self, 'arg%d' % i, arg) +- if sys.version_info < (3,): # easy way +- self.shortsignature = self.signature = ( +- inspect.formatargspec( +- formatvalue=lambda val: "", *argspec)[1:-1]) +- else: # Python 3 way +- allargs = list(self.args) +- allshortargs = list(self.args) +- if self.varargs: +- allargs.append('*' + self.varargs) +- allshortargs.append('*' + self.varargs) +- elif self.kwonlyargs: +- allargs.append('*') # single star syntax +- for a in self.kwonlyargs: +- allargs.append('%s=None' % a) +- allshortargs.append('%s=%s' % (a, a)) +- if self.varkw: +- allargs.append('**' + self.varkw) +- allshortargs.append('**' + self.varkw) +- self.signature = ', '.join(allargs) +- self.shortsignature = ', '.join(allshortargs) +- self.dict = func.__dict__.copy() +- # func=None happens when decorating a caller +- if name: +- self.name = name +- if signature is not None: +- self.signature = signature +- if defaults: +- self.defaults = defaults +- if doc: +- self.doc = doc +- if module: +- self.module = module +- if funcdict: +- self.dict = funcdict +- # check existence required attributes +- assert hasattr(self, 'name') +- if not hasattr(self, 'signature'): +- raise TypeError('You are decorating a non function: %s' % func) +- +- def update(self, func, **kw): +- "Update the signature of func with the data in self" +- func.__name__ = self.name +- func.__doc__ = getattr(self, 'doc', None) +- func.__dict__ = getattr(self, 'dict', {}) +- func.__defaults__ = getattr(self, 'defaults', ()) +- func.__kwdefaults__ = getattr(self, 'kwonlydefaults', None) +- func.__annotations__ = getattr(self, 'annotations', None) +- try: +- frame = sys._getframe(3) +- except AttributeError: # for IronPython and similar implementations +- callermodule = '?' +- else: +- callermodule = frame.f_globals.get('__name__', '?') +- func.__module__ = getattr(self, 'module', callermodule) +- func.__dict__.update(kw) +- +- def make(self, src_templ, evaldict=None, addsource=False, **attrs): +- "Make a new function from a given template and update the signature" +- src = src_templ % vars(self) # expand name and signature +- evaldict = evaldict or {} +- mo = DEF.match(src) +- if mo is None: +- raise SyntaxError('not a valid function template\n%s' % src) +- name = mo.group(1) # extract the function name +- names = set([name] + [arg.strip(' *') for arg in +- self.shortsignature.split(',')]) +- for n in names: +- if n in ('_func_', '_call_'): +- raise NameError('%s is overridden in\n%s' % (n, src)) +- +- if not src.endswith('\n'): # add a newline for old Pythons +- src += '\n' +- +- # Ensure each generated function has a unique filename for profilers +- # (such as cProfile) that depend on the tuple of (, +- # , ) being unique. +- filename = '' % (next(self._compile_count),) +- try: +- code = compile(src, filename, 'single') +- exec(code, evaldict) +- except: +- print('Error in generated code:', file=sys.stderr) +- print(src, file=sys.stderr) +- raise +- func = evaldict[name] +- if addsource: +- attrs['__source__'] = src +- self.update(func, **attrs) +- return func +- +- @classmethod +- def create(cls, obj, body, evaldict, defaults=None, +- doc=None, module=None, addsource=True, **attrs): +- """ +- Create a function from the strings name, signature and body. +- evaldict is the evaluation dictionary. If addsource is true an +- attribute __source__ is added to the result. The attributes attrs +- are added, if any. +- """ +- if isinstance(obj, str): # "name(signature)" +- name, rest = obj.strip().split('(', 1) +- signature = rest[:-1] # strip a right parens +- func = None +- else: # a function +- name = None +- signature = None +- func = obj +- self = cls(func, name, signature, defaults, doc, module) +- ibody = '\n'.join(' ' + line for line in body.splitlines()) +- return self.make('def %(name)s(%(signature)s):\n' + ibody, +- evaldict, addsource, **attrs) +- +- +-def decorate(func, caller): +- """ +- decorate(func, caller) decorates a function using a caller. +- """ +- evaldict = dict(_call_=caller, _func_=func) +- fun = FunctionMaker.create( +- func, "return _call_(_func_, %(shortsignature)s)", +- evaldict, __wrapped__=func) +- if hasattr(func, '__qualname__'): +- fun.__qualname__ = func.__qualname__ +- return fun +- +- +-def decorator(caller, _func=None): +- """decorator(caller) converts a caller function into a decorator""" +- if _func is not None: # return a decorated function +- # this is obsolete behavior; you should use decorate instead +- return decorate(_func, caller) +- # else return a decorator function +- if inspect.isclass(caller): +- name = caller.__name__.lower() +- doc = 'decorator(%s) converts functions/generators into ' \ +- 'factories of %s objects' % (caller.__name__, caller.__name__) +- elif inspect.isfunction(caller): +- if caller.__name__ == '': +- name = '_lambda_' +- else: +- name = caller.__name__ +- doc = caller.__doc__ +- else: # assume caller is an object with a __call__ method +- name = caller.__class__.__name__.lower() +- doc = caller.__call__.__doc__ +- evaldict = dict(_call_=caller, _decorate_=decorate) +- return FunctionMaker.create( +- '%s(func)' % name, 'return _decorate_(func, _call_)', +- evaldict, doc=doc, module=caller.__module__, +- __wrapped__=caller) +- +- +-# ####################### contextmanager ####################### # +- +-try: # Python >= 3.2 +- from contextlib import _GeneratorContextManager +-except ImportError: # Python >= 2.5 +- from contextlib import GeneratorContextManager as _GeneratorContextManager +- +- +-class ContextManager(_GeneratorContextManager): +- def __call__(self, func): +- """Context manager decorator""" +- return FunctionMaker.create( +- func, "with _self_: return _func_(%(shortsignature)s)", +- dict(_self_=self, _func_=func), __wrapped__=func) +- +- +-init = getfullargspec(_GeneratorContextManager.__init__) +-n_args = len(init.args) +-if n_args == 2 and not init.varargs: # (self, genobj) Python 2.7 +- def __init__(self, g, *a, **k): +- return _GeneratorContextManager.__init__(self, g(*a, **k)) +- +- +- ContextManager.__init__ = __init__ +-elif n_args == 2 and init.varargs: # (self, gen, *a, **k) Python 3.4 +- pass +-elif n_args == 4: # (self, gen, args, kwds) Python 3.5 +- def __init__(self, g, *a, **k): +- return _GeneratorContextManager.__init__(self, g, a, k) +- +- +- ContextManager.__init__ = __init__ +- +-contextmanager = decorator(ContextManager) +- +- +-# ############################ dispatch_on ############################ # +- +-def append(a, vancestors): +- """ +- Append ``a`` to the list of the virtual ancestors, unless it is already +- included. +- """ +- add = True +- for j, va in enumerate(vancestors): +- if issubclass(va, a): +- add = False +- break +- if issubclass(a, va): +- vancestors[j] = a +- add = False +- if add: +- vancestors.append(a) +- +- +-# inspired from simplegeneric by P.J. Eby and functools.singledispatch +-def dispatch_on(*dispatch_args): +- """ +- Factory of decorators turning a function into a generic function +- dispatching on the given arguments. +- """ +- assert dispatch_args, 'No dispatch args passed' +- dispatch_str = '(%s,)' % ', '.join(dispatch_args) +- +- def check(arguments, wrong=operator.ne, msg=''): +- """Make sure one passes the expected number of arguments""" +- if wrong(len(arguments), len(dispatch_args)): +- raise TypeError('Expected %d arguments, got %d%s' % +- (len(dispatch_args), len(arguments), msg)) +- +- def gen_func_dec(func): +- """Decorator turning a function into a generic function""" +- +- # first check the dispatch arguments +- argset = set(getfullargspec(func).args) +- if not set(dispatch_args) <= argset: +- raise NameError('Unknown dispatch arguments %s' % dispatch_str) +- +- typemap = {} +- +- def vancestors(*types): +- """ +- Get a list of sets of virtual ancestors for the given types +- """ +- check(types) +- ras = [[] for _ in range(len(dispatch_args))] +- for types_ in typemap: +- for t, type_, ra in zip(types, types_, ras): +- if issubclass(t, type_) and type_ not in t.__mro__: +- append(type_, ra) +- return [set(ra) for ra in ras] +- +- def ancestors(*types): +- """ +- Get a list of virtual MROs, one for each type +- """ +- check(types) +- lists = [] +- for t, vas in zip(types, vancestors(*types)): +- n_vas = len(vas) +- if n_vas > 1: +- raise RuntimeError( +- 'Ambiguous dispatch for %s: %s' % (t, vas)) +- elif n_vas == 1: +- va, = vas +- mro = type('t', (t, va), {}).__mro__[1:] +- else: +- mro = t.__mro__ +- lists.append(mro[:-1]) # discard t and object +- return lists +- +- def register(*types): +- """ +- Decorator to register an implementation for the given types +- """ +- check(types) +- +- def dec(f): +- check(getfullargspec(f).args, operator.lt, ' in ' + f.__name__) +- typemap[types] = f +- return f +- +- return dec +- +- def dispatch_info(*types): +- """ +- An utility to introspect the dispatch algorithm +- """ +- check(types) +- lst = [] +- for anc in itertools.product(*ancestors(*types)): +- lst.append(tuple(a.__name__ for a in anc)) +- return lst +- +- def _dispatch(dispatch_args, *args, **kw): +- types = tuple(type(arg) for arg in dispatch_args) +- try: # fast path +- f = typemap[types] +- except KeyError: +- pass +- else: +- return f(*args, **kw) +- combinations = itertools.product(*ancestors(*types)) +- next(combinations) # the first one has been already tried +- for types_ in combinations: +- f = typemap.get(types_) +- if f is not None: +- return f(*args, **kw) +- +- # else call the default implementation +- return func(*args, **kw) +- +- return FunctionMaker.create( +- func, 'return _f_(%s, %%(shortsignature)s)' % dispatch_str, +- dict(_f_=_dispatch), register=register, default=func, +- typemap=typemap, vancestors=vancestors, ancestors=ancestors, +- dispatch_info=dispatch_info, __wrapped__=func) +- +- gen_func_dec.__name__ = 'dispatch_on' + dispatch_str +- return gen_func_dec +diff --git a/setup.py b/setup.py +index 733b5e5..369f483 100644 +--- a/setup.py ++++ b/setup.py +@@ -26,6 +26,7 @@ setup( + package_data={ + 'prometheus_client': ['py.typed'] + }, ++ install_requires=['decorator'], + extras_require={ + 'twisted': ['twisted'], + }, +diff --git a/tests/test_core.py b/tests/test_core.py +index 6f7c9d1..0555e08 100644 +--- a/tests/test_core.py ++++ b/tests/test_core.py +@@ -1,4 +1,6 @@ + from concurrent.futures import ThreadPoolExecutor ++import collections ++from inspect import getfullargspec + import os + import time + import unittest +@@ -12,10 +14,18 @@ from prometheus_client.core import ( + HistogramMetricFamily, Info, InfoMetricFamily, Metric, Sample, + StateSetMetricFamily, Summary, SummaryMetricFamily, UntypedMetricFamily, + ) +-from prometheus_client.decorator import getargspec + from prometheus_client.metrics import _get_use_created + + ++ArgSpec = collections.namedtuple( ++ 'ArgSpec', 'args varargs varkw defaults') ++ ++def getargspec(f): ++ """A replacement for inspect.getargspec""" ++ spec = getfullargspec(f) ++ return ArgSpec(spec.args, spec.varargs, spec.varkw, spec.defaults) ++ ++ + def assert_not_observable(fn, *args, **kwargs): + """ + Assert that a function call falls with a ValueError exception containing +-- +2.37.3 + diff --git a/SOURCES/0001-Unbundle-decorator.patch b/SOURCES/0001-Unbundle-decorator.patch new file mode 100644 index 0000000..fb2fc3d --- /dev/null +++ b/SOURCES/0001-Unbundle-decorator.patch @@ -0,0 +1,499 @@ +From 49af450b7abfbbb4bf29f17d34339029b2a424ca Mon Sep 17 00:00:00 2001 +From: Igor Raits +Date: Sat, 12 Dec 2020 14:43:19 +0100 +Subject: [PATCH] Unbundle decorator + +Signed-off-by: Igor Raits +--- + NOTICE | 3 - + prometheus_client/context_managers.py | 2 +- + prometheus_client/decorator.py | 427 -------------------------- + setup.py | 1 + + tests/test_core.py | 2 +- + 5 files changed, 3 insertions(+), 432 deletions(-) + delete mode 100644 prometheus_client/decorator.py + +diff --git a/NOTICE b/NOTICE +index 59efb6c..0675ae1 100644 +--- a/NOTICE ++++ b/NOTICE +@@ -1,5 +1,2 @@ + Prometheus instrumentation library for Python applications + Copyright 2015 The Prometheus Authors +- +-This product bundles decorator 4.0.10 which is available under a "2-clause BSD" +-license. For details, see prometheus_client/decorator.py. +diff --git a/prometheus_client/context_managers.py b/prometheus_client/context_managers.py +index 2b271a7..d18400f 100644 +--- a/prometheus_client/context_managers.py ++++ b/prometheus_client/context_managers.py +@@ -2,7 +2,7 @@ from __future__ import unicode_literals + + from timeit import default_timer + +-from .decorator import decorate ++from decorator import decorate + + + class ExceptionCounter(object): +diff --git a/prometheus_client/decorator.py b/prometheus_client/decorator.py +deleted file mode 100644 +index 1ad2c97..0000000 +--- a/prometheus_client/decorator.py ++++ /dev/null +@@ -1,427 +0,0 @@ +-# ######################### LICENSE ############################ # +- +-# Copyright (c) 2005-2016, Michele Simionato +-# All rights reserved. +- +-# Redistribution and use in source and binary forms, with or without +-# modification, are permitted provided that the following conditions are +-# met: +- +-# Redistributions of source code must retain the above copyright +-# notice, this list of conditions and the following disclaimer. +-# Redistributions in bytecode form must reproduce the above copyright +-# notice, this list of conditions and the following disclaimer in +-# the documentation and/or other materials provided with the +-# distribution. +- +-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +-# HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +-# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +-# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +-# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +-# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +-# DAMAGE. +- +-""" +-Decorator module, see http://pypi.python.org/pypi/decorator +-for the documentation. +-""" +-from __future__ import print_function +- +-import collections +-import inspect +-import itertools +-import operator +-import re +-import sys +- +-__version__ = '4.0.10' +- +-if sys.version_info >= (3,): +- from inspect import getfullargspec +- +- +- def get_init(cls): +- return cls.__init__ +-else: +- class getfullargspec(object): +- "A quick and dirty replacement for getfullargspec for Python 2.X" +- +- def __init__(self, f): +- self.args, self.varargs, self.varkw, self.defaults = \ +- inspect.getargspec(f) +- self.kwonlyargs = [] +- self.kwonlydefaults = None +- +- def __iter__(self): +- yield self.args +- yield self.varargs +- yield self.varkw +- yield self.defaults +- +- getargspec = inspect.getargspec +- +- +- def get_init(cls): +- return cls.__init__.__func__ +- +-# getargspec has been deprecated in Python 3.5 +-ArgSpec = collections.namedtuple( +- 'ArgSpec', 'args varargs varkw defaults') +- +- +-def getargspec(f): +- """A replacement for inspect.getargspec""" +- spec = getfullargspec(f) +- return ArgSpec(spec.args, spec.varargs, spec.varkw, spec.defaults) +- +- +-DEF = re.compile(r'\s*def\s*([_\w][_\w\d]*)\s*\(') +- +- +-# basic functionality +-class FunctionMaker(object): +- """ +- An object with the ability to create functions with a given signature. +- It has attributes name, doc, module, signature, defaults, dict and +- methods update and make. +- """ +- +- # Atomic get-and-increment provided by the GIL +- _compile_count = itertools.count() +- +- def __init__(self, func=None, name=None, signature=None, +- defaults=None, doc=None, module=None, funcdict=None): +- self.shortsignature = signature +- if func: +- # func can be a class or a callable, but not an instance method +- self.name = func.__name__ +- if self.name == '': # small hack for lambda functions +- self.name = '_lambda_' +- self.doc = func.__doc__ +- self.module = func.__module__ +- if inspect.isfunction(func): +- argspec = getfullargspec(func) +- self.annotations = getattr(func, '__annotations__', {}) +- for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs', +- 'kwonlydefaults'): +- setattr(self, a, getattr(argspec, a)) +- for i, arg in enumerate(self.args): +- setattr(self, 'arg%d' % i, arg) +- if sys.version_info < (3,): # easy way +- self.shortsignature = self.signature = ( +- inspect.formatargspec( +- formatvalue=lambda val: "", *argspec)[1:-1]) +- else: # Python 3 way +- allargs = list(self.args) +- allshortargs = list(self.args) +- if self.varargs: +- allargs.append('*' + self.varargs) +- allshortargs.append('*' + self.varargs) +- elif self.kwonlyargs: +- allargs.append('*') # single star syntax +- for a in self.kwonlyargs: +- allargs.append('%s=None' % a) +- allshortargs.append('%s=%s' % (a, a)) +- if self.varkw: +- allargs.append('**' + self.varkw) +- allshortargs.append('**' + self.varkw) +- self.signature = ', '.join(allargs) +- self.shortsignature = ', '.join(allshortargs) +- self.dict = func.__dict__.copy() +- # func=None happens when decorating a caller +- if name: +- self.name = name +- if signature is not None: +- self.signature = signature +- if defaults: +- self.defaults = defaults +- if doc: +- self.doc = doc +- if module: +- self.module = module +- if funcdict: +- self.dict = funcdict +- # check existence required attributes +- assert hasattr(self, 'name') +- if not hasattr(self, 'signature'): +- raise TypeError('You are decorating a non function: %s' % func) +- +- def update(self, func, **kw): +- "Update the signature of func with the data in self" +- func.__name__ = self.name +- func.__doc__ = getattr(self, 'doc', None) +- func.__dict__ = getattr(self, 'dict', {}) +- func.__defaults__ = getattr(self, 'defaults', ()) +- func.__kwdefaults__ = getattr(self, 'kwonlydefaults', None) +- func.__annotations__ = getattr(self, 'annotations', None) +- try: +- frame = sys._getframe(3) +- except AttributeError: # for IronPython and similar implementations +- callermodule = '?' +- else: +- callermodule = frame.f_globals.get('__name__', '?') +- func.__module__ = getattr(self, 'module', callermodule) +- func.__dict__.update(kw) +- +- def make(self, src_templ, evaldict=None, addsource=False, **attrs): +- "Make a new function from a given template and update the signature" +- src = src_templ % vars(self) # expand name and signature +- evaldict = evaldict or {} +- mo = DEF.match(src) +- if mo is None: +- raise SyntaxError('not a valid function template\n%s' % src) +- name = mo.group(1) # extract the function name +- names = set([name] + [arg.strip(' *') for arg in +- self.shortsignature.split(',')]) +- for n in names: +- if n in ('_func_', '_call_'): +- raise NameError('%s is overridden in\n%s' % (n, src)) +- +- if not src.endswith('\n'): # add a newline for old Pythons +- src += '\n' +- +- # Ensure each generated function has a unique filename for profilers +- # (such as cProfile) that depend on the tuple of (, +- # , ) being unique. +- filename = '' % (next(self._compile_count),) +- try: +- code = compile(src, filename, 'single') +- exec(code, evaldict) +- except: +- print('Error in generated code:', file=sys.stderr) +- print(src, file=sys.stderr) +- raise +- func = evaldict[name] +- if addsource: +- attrs['__source__'] = src +- self.update(func, **attrs) +- return func +- +- @classmethod +- def create(cls, obj, body, evaldict, defaults=None, +- doc=None, module=None, addsource=True, **attrs): +- """ +- Create a function from the strings name, signature and body. +- evaldict is the evaluation dictionary. If addsource is true an +- attribute __source__ is added to the result. The attributes attrs +- are added, if any. +- """ +- if isinstance(obj, str): # "name(signature)" +- name, rest = obj.strip().split('(', 1) +- signature = rest[:-1] # strip a right parens +- func = None +- else: # a function +- name = None +- signature = None +- func = obj +- self = cls(func, name, signature, defaults, doc, module) +- ibody = '\n'.join(' ' + line for line in body.splitlines()) +- return self.make('def %(name)s(%(signature)s):\n' + ibody, +- evaldict, addsource, **attrs) +- +- +-def decorate(func, caller): +- """ +- decorate(func, caller) decorates a function using a caller. +- """ +- evaldict = dict(_call_=caller, _func_=func) +- fun = FunctionMaker.create( +- func, "return _call_(_func_, %(shortsignature)s)", +- evaldict, __wrapped__=func) +- if hasattr(func, '__qualname__'): +- fun.__qualname__ = func.__qualname__ +- return fun +- +- +-def decorator(caller, _func=None): +- """decorator(caller) converts a caller function into a decorator""" +- if _func is not None: # return a decorated function +- # this is obsolete behavior; you should use decorate instead +- return decorate(_func, caller) +- # else return a decorator function +- if inspect.isclass(caller): +- name = caller.__name__.lower() +- doc = 'decorator(%s) converts functions/generators into ' \ +- 'factories of %s objects' % (caller.__name__, caller.__name__) +- elif inspect.isfunction(caller): +- if caller.__name__ == '': +- name = '_lambda_' +- else: +- name = caller.__name__ +- doc = caller.__doc__ +- else: # assume caller is an object with a __call__ method +- name = caller.__class__.__name__.lower() +- doc = caller.__call__.__doc__ +- evaldict = dict(_call_=caller, _decorate_=decorate) +- return FunctionMaker.create( +- '%s(func)' % name, 'return _decorate_(func, _call_)', +- evaldict, doc=doc, module=caller.__module__, +- __wrapped__=caller) +- +- +-# ####################### contextmanager ####################### # +- +-try: # Python >= 3.2 +- from contextlib import _GeneratorContextManager +-except ImportError: # Python >= 2.5 +- from contextlib import GeneratorContextManager as _GeneratorContextManager +- +- +-class ContextManager(_GeneratorContextManager): +- def __call__(self, func): +- """Context manager decorator""" +- return FunctionMaker.create( +- func, "with _self_: return _func_(%(shortsignature)s)", +- dict(_self_=self, _func_=func), __wrapped__=func) +- +- +-init = getfullargspec(_GeneratorContextManager.__init__) +-n_args = len(init.args) +-if n_args == 2 and not init.varargs: # (self, genobj) Python 2.7 +- def __init__(self, g, *a, **k): +- return _GeneratorContextManager.__init__(self, g(*a, **k)) +- +- +- ContextManager.__init__ = __init__ +-elif n_args == 2 and init.varargs: # (self, gen, *a, **k) Python 3.4 +- pass +-elif n_args == 4: # (self, gen, args, kwds) Python 3.5 +- def __init__(self, g, *a, **k): +- return _GeneratorContextManager.__init__(self, g, a, k) +- +- +- ContextManager.__init__ = __init__ +- +-contextmanager = decorator(ContextManager) +- +- +-# ############################ dispatch_on ############################ # +- +-def append(a, vancestors): +- """ +- Append ``a`` to the list of the virtual ancestors, unless it is already +- included. +- """ +- add = True +- for j, va in enumerate(vancestors): +- if issubclass(va, a): +- add = False +- break +- if issubclass(a, va): +- vancestors[j] = a +- add = False +- if add: +- vancestors.append(a) +- +- +-# inspired from simplegeneric by P.J. Eby and functools.singledispatch +-def dispatch_on(*dispatch_args): +- """ +- Factory of decorators turning a function into a generic function +- dispatching on the given arguments. +- """ +- assert dispatch_args, 'No dispatch args passed' +- dispatch_str = '(%s,)' % ', '.join(dispatch_args) +- +- def check(arguments, wrong=operator.ne, msg=''): +- """Make sure one passes the expected number of arguments""" +- if wrong(len(arguments), len(dispatch_args)): +- raise TypeError('Expected %d arguments, got %d%s' % +- (len(dispatch_args), len(arguments), msg)) +- +- def gen_func_dec(func): +- """Decorator turning a function into a generic function""" +- +- # first check the dispatch arguments +- argset = set(getfullargspec(func).args) +- if not set(dispatch_args) <= argset: +- raise NameError('Unknown dispatch arguments %s' % dispatch_str) +- +- typemap = {} +- +- def vancestors(*types): +- """ +- Get a list of sets of virtual ancestors for the given types +- """ +- check(types) +- ras = [[] for _ in range(len(dispatch_args))] +- for types_ in typemap: +- for t, type_, ra in zip(types, types_, ras): +- if issubclass(t, type_) and type_ not in t.__mro__: +- append(type_, ra) +- return [set(ra) for ra in ras] +- +- def ancestors(*types): +- """ +- Get a list of virtual MROs, one for each type +- """ +- check(types) +- lists = [] +- for t, vas in zip(types, vancestors(*types)): +- n_vas = len(vas) +- if n_vas > 1: +- raise RuntimeError( +- 'Ambiguous dispatch for %s: %s' % (t, vas)) +- elif n_vas == 1: +- va, = vas +- mro = type('t', (t, va), {}).__mro__[1:] +- else: +- mro = t.__mro__ +- lists.append(mro[:-1]) # discard t and object +- return lists +- +- def register(*types): +- """ +- Decorator to register an implementation for the given types +- """ +- check(types) +- +- def dec(f): +- check(getfullargspec(f).args, operator.lt, ' in ' + f.__name__) +- typemap[types] = f +- return f +- +- return dec +- +- def dispatch_info(*types): +- """ +- An utility to introspect the dispatch algorithm +- """ +- check(types) +- lst = [] +- for anc in itertools.product(*ancestors(*types)): +- lst.append(tuple(a.__name__ for a in anc)) +- return lst +- +- def _dispatch(dispatch_args, *args, **kw): +- types = tuple(type(arg) for arg in dispatch_args) +- try: # fast path +- f = typemap[types] +- except KeyError: +- pass +- else: +- return f(*args, **kw) +- combinations = itertools.product(*ancestors(*types)) +- next(combinations) # the first one has been already tried +- for types_ in combinations: +- f = typemap.get(types_) +- if f is not None: +- return f(*args, **kw) +- +- # else call the default implementation +- return func(*args, **kw) +- +- return FunctionMaker.create( +- func, 'return _f_(%s, %%(shortsignature)s)' % dispatch_str, +- dict(_f_=_dispatch), register=register, default=func, +- typemap=typemap, vancestors=vancestors, ancestors=ancestors, +- dispatch_info=dispatch_info, __wrapped__=func) +- +- gen_func_dec.__name__ = 'dispatch_on' + dispatch_str +- return gen_func_dec +diff --git a/setup.py b/setup.py +index 0c80a56..7a434b2 100644 +--- a/setup.py ++++ b/setup.py +@@ -27,6 +27,7 @@ setup( + 'prometheus_client.openmetrics', + 'prometheus_client.twisted', + ], ++ install_requires=['decorator'], + extras_require={ + 'twisted': ['twisted'], + }, +diff --git a/tests/test_core.py b/tests/test_core.py +index 5a81f12..d81f0a8 100644 +--- a/tests/test_core.py ++++ b/tests/test_core.py +@@ -11,7 +11,7 @@ from prometheus_client.core import ( + HistogramMetricFamily, Info, InfoMetricFamily, Metric, Sample, + StateSetMetricFamily, Summary, SummaryMetricFamily, UntypedMetricFamily, + ) +-from prometheus_client.decorator import getargspec ++from inspect import getargspec + + try: + import unittest2 as unittest +-- +2.29.2 + diff --git a/SPECS/python-prometheus_client.spec b/SPECS/python-prometheus_client.spec new file mode 100644 index 0000000..49b9ff8 --- /dev/null +++ b/SPECS/python-prometheus_client.spec @@ -0,0 +1,169 @@ +## START: Set by rpmautospec +## (rpmautospec version 0.3.5) +## RPMAUTOSPEC: autorelease, autochangelog +%define autorelease(e:s:pb:n) %{?-p:0.}%{lua: + release_number = 1; + base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}")); + print(release_number + base_release_number - 1); +}%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}} +## END: Set by rpmautospec + +%global srcname prometheus_client + +Name: python-%{srcname} +Version: 0.17.1 +Release: %autorelease +Summary: Python client for Prometheus + +License: Apache-2.0 +URL: https://github.com/prometheus/client_python +Source: %{url}/archive/v%{version}/%{srcname}-%{version}.tar.gz +Patch0001: 0001-Remove-the-bundled-decorator-package.patch + +BuildArch: noarch + +%description +%{summary}. + +%package -n python3-%{srcname} +Summary: %{summary} +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3dist(decorator) +BuildRequires: python3dist(pytest) +%{?python_provide:%python_provide python3-%{srcname}} + +%description -n python3-%{srcname} +%{summary}. + +%package -n python3-%{srcname}+twisted +Summary: %{summary} +Requires: python3-%{srcname} = %{?epoch:%{epoch}:}%{version}-%{release} +Requires: python%{python3_version}dist(twisted) +BuildRequires: python3dist(twisted) +%{?python_provide:%python_provide python3-%{srcname}+twisted} + +%description -n python3-%{srcname}+twisted +%{summary}. + +"twisted" extras. + +%prep +%autosetup -p1 -n client_python-%{version} +sed -i -e '1{/^#!/d}' prometheus_client/__init__.py + +%build +%py3_build + +%install +%py3_install + +%check +%{__python3} -m pytest -v + +%files -n python3-%{srcname} +%license LICENSE +%doc README.md MAINTAINERS.md +%{python3_sitelib}/%{srcname}/ +%{python3_sitelib}/%{srcname}-*.egg-info/ + +%files -n python3-%{srcname}+twisted +%{?python_extras_subpkg:%ghost %{python3_sitelib}/%{srcname}-*.egg-info/} + +%changelog +* Sat Aug 19 2023 Kai A. Hiller - 0.17.1-1 +- Update to v1.17.1 + +* Sat Aug 19 2023 Kai A. Hiller - 0.16.0-4 +- SPDX migration + +* Fri Jul 21 2023 Fedora Release Engineering - 0.16.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + +* Wed Jun 28 2023 Python Maint - 0.16.0-2 +- Rebuilt for Python 3.12 + +* Wed Mar 29 2023 Kai A. Hiller - 0.16.0-1 +- Update to v0.16.0 + +* Fri Jan 20 2023 Fedora Release Engineering - 0.13.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild + +* Fri Jul 22 2022 Fedora Release Engineering - 0.13.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild + +* Tue Jun 14 2022 Python Maint - 0.13.1-2 +- Rebuilt for Python 3.11 + +* Tue Feb 01 2022 Matt Prahl - 0.13.1-1 +- Update to 0.13.1 + +* Fri Jan 21 2022 Fedora Release Engineering - 0.9.0-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild + +* Fri Jul 23 2021 Fedora Release Engineering - 0.9.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild + +* Fri Jun 04 2021 Python Maint - 0.9.0-3 +- Rebuilt for Python 3.10 + +* Wed Jan 27 2021 Fedora Release Engineering - 0.9.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Sat Dec 12 2020 Igor Raits - 0.9.0-1 +- Update to 0.9.0 + +* Sat Aug 01 2020 Fedora Release Engineering - 0.7.1-6 +- Second attempt - Rebuilt for + https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Wed Jul 29 2020 Fedora Release Engineering - 0.7.1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Fri Jul 10 2020 Miro Hrončok - 0.7.1-4 +- Add metadata for Python extras subpackages + +* Sun May 24 2020 Miro Hrončok - 0.7.1-3 +- Rebuilt for Python 3.9 + +* Thu Jan 30 2020 Fedora Release Engineering - 0.7.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Wed Oct 23 2019 Igor Gnatenko - 0.7.1-1 +- Update to 0.7.1 +- Split twisted extras into a separate subpackage + +* Thu Oct 03 2019 Miro Hrončok - 0.6.0-4 +- Rebuilt for Python 3.8.0rc1 (#1748018) + +* Sun Aug 18 2019 Miro Hrončok - 0.6.0-3 +- Rebuilt for Python 3.8 + +* Fri Jul 26 2019 Fedora Release Engineering - 0.6.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Thu Feb 21 2019 mprahl - 0.6.0-1 +- Update to 0.6.0 + +* Wed Feb 20 2019 mprahl - 0.5.0-2 +- Remove #!/usr/bin/python line from prometheus_client/openmetrics/*.py + +* Thu Feb 07 2019 mprahl - 0.5.0-1 +- Update to 0.5.0 + +* Sat Feb 02 2019 Fedora Release Engineering - 0.2.0-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Mon Jan 14 2019 Miro Hrončok - 0.2.0-4 +- Subpackage python2-prometheus_client has been removed + See https://fedoraproject.org/wiki/Changes/Mass_Python_2_Package_Removal + +* Sat Jul 14 2018 Fedora Release Engineering - 0.2.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Tue Jun 19 2018 Miro Hrončok - 0.2.0-2 +- Rebuilt for Python 3.7 + +* Sat Jun 09 2018 Jeremy Cline - 0.2.0-1 +- Initial package +