1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
"""util functions for collections_extended."""
from functools import wraps
import textwrap
import warnings
__all__ = ('hash_iterable', 'deprecated', 'deprecation_warning')
def hash_iterable(it):
"""Perform a O(1) memory hash of an iterable of arbitrary length.
hash(tuple(it)) creates a temporary tuple containing all values from it
which could be a problem if it is large.
See discussion at:
https://groups.google.com/forum/#!msg/python-ideas/XcuC01a8SYs/e-doB9TbDwAJ
"""
hash_value = hash(type(it))
for value in it:
hash_value = hash((hash_value, value))
return hash_value
def deprecation_warning(msg):
"""Raise a deprecation warning."""
warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
def deprecated(msg, dep_version):
"""Decorate a function, method or class to mark as deprecated.
Raise DeprecationWarning and add a deprecation notice to the docstring.
Args:
msg: The message to document
dep_version: The version in which this was deprecated
See:
https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-deprecated
"""
def wrapper(func):
docstring = func.__doc__ or ''
docstring_msg = '.. deprecated:: {version} {msg}'.format(
version=dep_version,
msg=msg,
)
if docstring:
# We don't know how far to indent this message
# so instead we just dedent everything.
string_list = docstring.splitlines()
first_line = string_list[0]
remaining = textwrap.dedent(''.join(string_list[1:]))
docstring = '\n'.join([
first_line,
remaining,
'',
docstring_msg,
])
else:
docstring = docstring_msg
func.__doc__ = docstring
@wraps(func)
def inner(*args, **kwargs):
deprecation_warning(msg)
return func(*args, **kwargs)
return inner
return wrapper
|