/usr/lib/python2.7/dist-packages/passlib/utils/decor.py is in python-passlib 1.7.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | """
passlib.utils.decor -- helper decorators & properties
"""
#=============================================================================
# imports
#=============================================================================
# core
from __future__ import absolute_import, division, print_function
import logging
log = logging.getLogger(__name__)
from functools import wraps, update_wrapper
import types
from warnings import warn
# site
# pkg
from passlib.utils.compat import PY3
# local
__all__ = [
"classproperty",
"hybrid_method",
"memoize_single_value",
"memoized_property",
"deprecated_function",
"deprecated_method",
]
#=============================================================================
# class-level decorators
#=============================================================================
class classproperty(object):
"""Function decorator which acts like a combination of classmethod+property (limited to read-only properties)"""
def __init__(self, func):
self.im_func = func
def __get__(self, obj, cls):
return self.im_func(cls)
@property
def __func__(self):
"""py3 compatible alias"""
return self.im_func
class hybrid_method(object):
"""
decorator which invokes function with class if called as class method,
and with object if called at instance level.
"""
def __init__(self, func):
self.func = func
update_wrapper(self, func)
def __get__(self, obj, cls):
if obj is None:
obj = cls
if PY3:
return types.MethodType(self.func, obj)
else:
return types.MethodType(self.func, obj, cls)
#=============================================================================
# memoization
#=============================================================================
def memoize_single_value(func):
"""
decorator for function which takes no args,
and memoizes result. exposes a ``.clear_cache`` method
to clear the cached value.
"""
cache = {}
@wraps(func)
def wrapper():
try:
return cache[True]
except KeyError:
pass
value = cache[True] = func()
return value
def clear_cache():
cache.pop(True, None)
wrapper.clear_cache = clear_cache
return wrapper
class memoized_property(object):
"""
decorator which invokes method once, then replaces attr with result
"""
def __init__(self, func):
self.__func__ = func
self.__name__ = func.__name__
self.__doc__ = func.__doc__
def __get__(self, obj, cls):
if obj is None:
return self
value = self.__func__(obj)
setattr(obj, self.__name__, value)
return value
if not PY3:
@property
def im_func(self):
"""py2 alias"""
return self.__func__
def clear_cache(self, obj):
"""
class-level helper to clear stored value (if any).
usage: :samp:`type(self).{attr}.clear_cache(self)`
"""
obj.__dict__.pop(self.__name__, None)
def peek_cache(self, obj, default=None):
"""
class-level helper to peek at stored value
usage: :samp:`value = type(self).{attr}.clear_cache(self)`
"""
return obj.__dict__.get(self.__name__, default)
# works but not used
##class memoized_class_property(object):
## """function decorator which calls function as classmethod,
## and replaces itself with result for current and all future invocations.
## """
## def __init__(self, func):
## self.im_func = func
##
## def __get__(self, obj, cls):
## func = self.im_func
## value = func(cls)
## setattr(cls, func.__name__, value)
## return value
##
## @property
## def __func__(self):
## "py3 compatible alias"
#=============================================================================
# deprecation
#=============================================================================
def deprecated_function(msg=None, deprecated=None, removed=None, updoc=True,
replacement=None, _is_method=False,
func_module=None):
"""decorator to deprecate a function.
:arg msg: optional msg, default chosen if omitted
:kwd deprecated: version when function was first deprecated
:kwd removed: version when function will be removed
:kwd replacement: alternate name / instructions for replacing this function.
:kwd updoc: add notice to docstring (default ``True``)
"""
if msg is None:
if _is_method:
msg = "the method %(mod)s.%(klass)s.%(name)s() is deprecated"
else:
msg = "the function %(mod)s.%(name)s() is deprecated"
if deprecated:
msg += " as of Passlib %(deprecated)s"
if removed:
msg += ", and will be removed in Passlib %(removed)s"
if replacement:
msg += ", use %s instead" % replacement
msg += "."
def build(func):
is_classmethod = _is_method and isinstance(func, classmethod)
if is_classmethod:
# NOTE: PY26 doesn't support "classmethod().__func__" directly...
func = func.__get__(None, type).__func__
opts = dict(
mod=func_module or func.__module__,
name=func.__name__,
deprecated=deprecated,
removed=removed,
)
if _is_method:
def wrapper(*args, **kwds):
tmp = opts.copy()
klass = args[0] if is_classmethod else args[0].__class__
tmp.update(klass=klass.__name__, mod=klass.__module__)
warn(msg % tmp, DeprecationWarning, stacklevel=2)
return func(*args, **kwds)
else:
text = msg % opts
def wrapper(*args, **kwds):
warn(text, DeprecationWarning, stacklevel=2)
return func(*args, **kwds)
update_wrapper(wrapper, func)
if updoc and (deprecated or removed) and \
wrapper.__doc__ and ".. deprecated::" not in wrapper.__doc__:
txt = deprecated or ''
if removed or replacement:
txt += "\n "
if removed:
txt += "and will be removed in version %s" % (removed,)
if replacement:
if removed:
txt += ", "
txt += "use %s instead" % replacement
txt += "."
if not wrapper.__doc__.strip(" ").endswith("\n"):
wrapper.__doc__ += "\n"
wrapper.__doc__ += "\n.. deprecated:: %s\n" % (txt,)
if is_classmethod:
wrapper = classmethod(wrapper)
return wrapper
return build
def deprecated_method(msg=None, deprecated=None, removed=None, updoc=True,
replacement=None):
"""decorator to deprecate a method.
:arg msg: optional msg, default chosen if omitted
:kwd deprecated: version when method was first deprecated
:kwd removed: version when method will be removed
:kwd replacement: alternate name / instructions for replacing this method.
:kwd updoc: add notice to docstring (default ``True``)
"""
return deprecated_function(msg, deprecated, removed, updoc, replacement,
_is_method=True)
#=============================================================================
# eof
#=============================================================================
|