PythonCK.decorators package¶
Submodules¶
PythonCK.decorators.cache_to_file module¶
cache_to_file and underlying shelf (dict with timestamp).
-
class
PythonCK.decorators.cache_to_file.cache_to_file(func=None, *args, **kwargs)[source]¶ Bases:
PythonCK.decorators.meta.AbstractClassbasedDecoratorCache the result of this function, persist on the disk (using pickle/shelve).
Extra flag:
force_reloadIf flag
force_reload=Trueis given additionally into decorated function, the wrapped function will be called regardless of the cache even if it’s available. This is useful in case where the user intent to refresh the cache to newer value, as well as prolonging cache expiredate.Extra flag:
early_giveupIf flag
early_giveup=Trueis given additionally into decorated function, the wrapped function will return None immediately if there’s no cache available before this call. This is useful in the situation where it’s antipicated that the function call will be slow (expensive), and the calling can be postponed to better context. - If cache is already expired, early_giveup will also return None. - The default return value is NoneNote
force_reloadandearly_giveupare mutually exclusive. Exception will be raised if both of them are True simultaneously.Note
Cannot be used on instance.method?
Parameters: - basedir (str) – Name of the directory where the cache should reside. If None, this will be determined automatically.
- timeout (int) – Timeout until the cache expire, in seconds.
- input_skip_write (None, bool, callable) – Input-dependent callback which, if true, will not persist the cache.
- output_skip_write (None, bool, callable) – Output-dependent callback which, if true, will not persist the cache.
- sharding (bool) – If True, instead of collection calls from same function into one shelve, shards the result into single-pickled-file, one file per one unique input. This is better in term of concurrency, but may make directory more dirty…
Usages:
>>> func = getfixture('f_cache_to_file') >>> func.counter # hits & misses (0, 0) >>> func(111) # simple call ((111,), {}) >>> func.counter # one miss (0, 1) >>> func.contains(111) # it's cached True >>> _ = func(111) # call again, expect hit >>> func.counter (1, 2) >>> _ = func(222) # call with second key >>> func.contains(222) True >>> func.counter (1, 3) >>> _ = func(222) # call with second key, again >>> func.contains(222) True >>> func.counter (2, 4) >>> func(111) # call with 1st key, again ((111,), {}) >>> func.contains(111) True >>> func.counter (3, 5)
>>> func(111, force_reload=True) # Using force_reload ((111,), {}) >>> func.counter (3, 6) >>> func(333, early_giveup=True) # Using early_giveup
>>> func.contains(333) False >>> func.counter (3, 6) >>> _ = func(333) # now there's cache >>> func(333, early_giveup=True) ((333,), {}) >>> func.counter (4, 8)
>>> func('arg', kw='kwarg') # same thing for kwargs (('arg',), {'kw': 'kwarg'}) >>> func.counter (4, 9)
-
__abstractmethods__= frozenset([])¶
-
__module__= 'PythonCK.decorators.cache_to_file'¶
-
__setitem__(args_kwargs, result)[source]¶ Backdoor interface to allow putting data into shelf directly without need for a call to host function at all.
Useful for case where batch-call is prefered, but optimize caching for single entry from the batch.
- Accept 2 style of keys:
- ready-key, made via staticmethod makekey
- raw-key, compose of 2-tuple of (args,kwargs)
- Usage:
>>> func = getfixture('f_cache_to_file')
>>> func.contains(111) False >>> func[(111,),{}] = 111 # Set args,kwargs and results manually >>> func.contains(111) True >>> func.counter (0, 0) >>> func(111) # a new call should hit instantly 111 >>> func.counter (1, 1)
>>> key = func.makekey('arg', kw='kwarg') # Another set style, via makekey >>> func[key] = 'key_via_makekey' >>> func.counter (1, 1) >>> func('arg', kw='kwarg') 'key_via_makekey' >>> func.counter # hit instantly (2, 2)
>>> func[1] = 2 # Other case is not accepted Traceback (most recent call last): ... ValueError: Invalid key for backdoor __setitem__
-
__slots__= ('_count_hit', '_count_total', '_extra', '_isw', '_osw', '_shelfid', '_shelf', '_timeout')¶
-
contains(*args, **kwargs)[source]¶ Return True if given args-kwargs has been cached.
>>> func = getfixture('f_cache_to_file') >>> func.contains(0) False >>> _ = func('111') >>> func.contains('111') True >>> func.contains('111', kw=222) False
-
counter¶ Return the hit/total stats of this cacher.
-
is_expired(time_last)[source]¶ Return True if data already expired. False (not expired) if timeout not given
>>> from datetime import datetime, timedelta >>> _ = getfixture('chtmpdir') >>> f = cache_to_file(func0, timeout=3600, basedir='.') >>> f.is_expired(datetime.now()) False >>> f.is_expired(datetime.now()-timedelta(10000)) True >>> f.is_expired(None) True
-
static
makekey(*args, **kwargs)[source]¶ Handle making unique key from args, kwargs, exact signature like a function.
-
report_stats()[source]¶ Report the hit/total stats.
>>> f = getfixture('f_cache_to_file') >>> c = getfixture('caplog2') >>> _ = f(42) >>> _ = f(42) >>> f.report_stats() >>> print(c.record_tuples[-1][-1]) cache_to_file: Hit rate : 1/2 = 0.50
-
shelf¶ Use for cache-viewer. Lazily create shelf (instead of opening dangle shelf when func is defined but unused)
-
shelfid¶
-
timeleft(key)[source]¶ Given a key of the shelf, return the time left until the cache is expired. Used in auxiliary method cache viewer:
>>> f = getfixture('f_cache_to_file') ## By default, there's no cache time-out >>> _ = f(42) >>> f.timeleft(f.makekey(42)) is None True ## Check the timeout >>> _ = getfixture('chtmpdir') >>> f = cache_to_file(func0, timeout=60, basedir='.') >>> _ = f(42) >>> f.counter (0, 1) >>> t = f.timeleft(f.makekey(42)).seconds >>> (t > 0) and (t < 3600) True >>> _ = f(42) # try again, without timeout >>> f.counter (1, 2)
PythonCK.decorators.decorators module¶
Collection of several useful decorators.
-
PythonCK.decorators.decorators.deprecated(func)[source]¶ This will print warning whenever this decorated function is called.
>>> caplog = getfixture('caplog2') >>> @deprecated ... def f_deprecated(): ... pass >>> f_deprecated()
>>> 'WARNING' in caplog.text and 'deprecated' in caplog.text True
-
PythonCK.decorators.decorators.report(*args, **kwargs)[source]¶ Decorator to print information about a function call for use while debugging. Prints function name, arguments, and call number when the function is called. Prints this information again along with the return value when the function returns.
It it’s used inside Gaudi, the debug level is too polluted. Hence additional flag if given
If hide_output, will show only the call, but not output result
>>> caplog = getfixture('caplog2')
>>> @report ... def foo(): ... return 'line1\nline2'
>>> _ = foo()
PythonCK.decorators.lazy module¶
Collection of lazy (caching) decorators
-
PythonCK.decorators.lazy.lazy_instance(func)[source]¶ To be used on the function that return some instance. The function will delay its call until its resultant instance is used (via __getattr__). A prime example is PyrootCK.import_tree.
Usage:
>>> IS_INIT = False >>> class Heavy(object): ... def __init__(self): ... global IS_INIT ... IS_INIT = True ... def foo(self): ... return 42 >>> @lazy_instance ... def get_heavy(): ... return Heavy() >>> x = get_heavy() >>> IS_INIT False >>> x <PythonCK.decorators.lazy...> >>> x.foo() 42 >>> IS_INIT True ## Triggered by setter >>> IS_INIT = False >>> y = get_heavy() >>> IS_INIT False >>> y.attr = 'val' >>> IS_INIT True >>> y.attr 'val'
-
PythonCK.decorators.lazy.lazy_property(func)[source]¶ Lazy function, only for getter instance-method!
Usage:
>>> class Foo(object): ... slow_count = 0 ... @lazy_property ... def slow(self): ... self.slow_count += 1 ... return 'some slow result'
>>> foo = Foo() >>> foo.slow_count 0 >>> foo.slow 'some slow result' >>> foo.slow_count # increase 1 >>> foo.slow 'some slow result' >>> foo.slow_count # not increase anymore! 1
PythonCK.decorators.meta module¶
-
class
PythonCK.decorators.meta.AbstractClassbasedDecorator(func=None, *args, **kwargs)[source]¶ Bases:
objectBaseclass to be used for all class-based decorator involving optional init arg.
The difficulty lies in the fact that there’re 2 ways to init a decorator instance.
Without kwargs:
__init__will havefuncequal to the decorated function.__call__will have all (args,kwargs) input for func
With kwargs:
__init__will have all args to init decorator, but no func available yet__call__will be invoked 2 times:- 1st-time: func will be passed as first arg, save it, then return self to invoke 2nd
- 2nd-time: The (args,kwargs) for decorated function will be received here.
Note: - Not possible to use simple args for init, too ambiguous. - The decorated function is accessible through property
self.funcIts setterself.func = xxxwill be handled implicitly under the hood, so there should be no need to call this manually.Test cases:
## Abstract, need implementation >>> class Foo(AbstractClassbasedDecorator): ... pass >>> Foo() Traceback (most recent call last): ... TypeError: Can't instantiate abstract class Foo with abstract methods _run, _setup >>> class foo(AbstractClassbasedDecorator): ... def _setup(self, *args, **kwargs): ... pass ... def _run(self, *args, **kwargs): ... return self.func(*args, **kwargs) ## Decorating function, with/without decorator kwarg. >>> @foo ... def func_without_kwargs(): ... return 'without' >>> func_without_kwargs() 'without' >>> @foo(kw='kwarg') ... def func_with_kwargs(): ... return 'with' >>> func_with_kwargs() 'with' ## Decorating instance method >>> class Aileus: ... @foo ... def bondus(self): ... return 'bondus' ... @foo(kw='kwargs') ... def callus(self): ... return 'callus' >>> a = Aileus() >>> a.bondus() 'bondus' >>> a.callus() 'callus'
REF:
- http://tech.novapost.fr/python-class-based-decorators-en.html
- http://code.activestate.com/recipes/577452-a-memoize-decorator-for-instance-methods/
-
__abstractmethods__= frozenset(['_run', '_setup'])¶
-
__dict__= dict_proxy({'_abc_cache': <_weakrefset.WeakSet object>, '_run': <function _run>, '__dict__': <attribute '__dict__' of 'AbstractClassbasedDecorator' objects>, '_abc_registry': <_weakrefset.WeakSet object>, '__abstractmethods__': frozenset(['_run', '_setup']), '_setup': <function _setup>, '__module__': 'PythonCK.decorators.meta', '__call__': <function __call__>, '_abc_negative_cache_version': 31, 'func': <property object>, '_abc_negative_cache': <_weakrefset.WeakSet object>, '_logd': <function _logd>, '__weakref__': <attribute '__weakref__' of 'AbstractClassbasedDecorator' objects>, '__doc__': "\n Baseclass to be used for all class-based decorator involving optional init arg.\n\n The difficulty lies in the fact that there're 2 ways to init a decorator instance.\n\n Without kwargs:\n\n - ``__init__`` will have ``func`` equal to the decorated function.\n - ``__call__`` will have all (args,kwargs) input for func\n\n With kwargs:\n\n - ``__init__`` will have all args to init decorator, but no func available yet\n - ``__call__`` will be invoked 2 times:\n\n * 1st-time: func will be passed as first arg, save it, then return self to invoke 2nd\n * 2nd-time: The (args,kwargs) for decorated function will be received here.\n\n Note:\n - Not possible to use simple args for init, too ambiguous.\n - The decorated function is accessible through property ``self.func``\n Its setter ``self.func = xxx`` will be handled implicitly under the hood,\n so there should be no need to call this manually.\n\n Test cases::\n\n ## Abstract, need implementation\n \n >>> class Foo(AbstractClassbasedDecorator):\n ... pass\n >>> Foo()\n Traceback (most recent call last):\n ...\n TypeError: Can't instantiate abstract class Foo with abstract methods _run, _setup\n\n >>> class foo(AbstractClassbasedDecorator):\n ... def _setup(self, *args, **kwargs):\n ... pass\n ... def _run(self, *args, **kwargs):\n ... return self.func(*args, **kwargs)\n\n ## Decorating function, with/without decorator kwarg.\n\n >>> @foo\n ... def func_without_kwargs():\n ... return 'without'\n >>> func_without_kwargs()\n 'without'\n\n >>> @foo(kw='kwarg')\n ... def func_with_kwargs():\n ... return 'with'\n >>> func_with_kwargs()\n 'with'\n\n ## Decorating instance method\n\n >>> class Aileus:\n ... @foo\n ... def bondus(self):\n ... return 'bondus'\n ... @foo(kw='kwargs')\n ... def callus(self):\n ... return 'callus'\n >>> a = Aileus()\n >>> a.bondus()\n 'bondus'\n >>> a.callus()\n 'callus'\n\n REF:\n\n - http://tech.novapost.fr/python-class-based-decorators-en.html\n - http://code.activestate.com/recipes/577452-a-memoize-decorator-for-instance-methods/\n\n ", '__init__': <function __init__>, '__get__': <function __get__>})¶
-
__init__(func=None, *args, **kwargs)[source]¶ x.__init__(…) initializes x; see help(type(x)) for signature
-
__module__= 'PythonCK.decorators.meta'¶
-
__weakref__¶ list of weak references to the object (if defined)
-
func¶ Return the instance of decorated function
-
PythonCK.decorators.meta.optional_arg_decorator(decorator)[source]¶ Meta-decorator to let the function-based decorator takes both argfull and argless constructor signature.
Usage:
## Define decorator >>> @optional_arg_decorator ... def foo(func, arg=None): ... def wrap(*args, **kwargs): ... return func(*args, **kwargs), arg ... return wrap ## Without arg >>> @foo ... def bar(): ... return 'bar' >>> bar() ('bar', None) ## With arg >>> @foo('more') ... def baz(): ... return 'baz' >>> baz() ('baz', 'more')
REF:
PythonCK.decorators.safe_makedir module¶
-
PythonCK.decorators.safe_makedir.safe_makedir(target)[source]¶ Workaround the race condition when multiple instances run on same node. https://stackoverflow.com/questions/1586648/race-condition-creating-folder-in-python
Also:
- make sure it’s string (or convert to string from py.local)
- expand var to abs path
- return the string path.
>>> import os >>> _ = getfixture('chtmpdir') >>> safe_makedir('subdir') 'subdir' >>> os.path.exists('./subdir') True
PythonCK.decorators.shelves module¶
Shelf is an underlying persistence for decorator cache_to_file where the expiration is also persisted.
-
class
PythonCK.decorators.shelves.ShardedShelf(shelfid)[source]¶ Bases:
_abcoll.MutableMappingPersist EACH keys into individual file, via pickle.
-
__abstractmethods__= frozenset([])¶
-
__module__= 'PythonCK.decorators.shelves'¶
-