Assorted function decorators.
Project description
Assorted function decorators.
Latest release 20251230: New @with_(func,obj) decorator to call func inside with obj:, primarily for Thread targets.
Short summary:
ALL: Include this function's name in its module's__all__list.attr: A decorator to set attributes on a function. Example:.cached: OBSOLETE version of cached, suggestion: cs.cache.cachedmethod.cachedmethod: OBSOLETE version of cachedmethod, suggestion: cs.cache.cachedmethod.contextdecorator: A decorator for a context manager functioncmgrfuncwhich turns it into a decorator for other functions.contextual: Wrap a simple function as a context manager.decorator: A decorator for decorator functions to support optional arguments and also to allow specifying additional attributes to apply to the decorated function.default_params: A decorator to provide factory functions for default parameters.fmtdoc: A decorator to format a function's docstring. This replaces the docstring with that string formatted against the function's module__dict__usingstr.format_map.logging_wrapper: Decorator for logging call shims which bumps thestacklevelkeyword argument so that the logging system chooses the correct frame to cite in messages.observable_class: Class decorator to make various instance attributes observable.OBSOLETE: A decorator for obsolete functions or classes.PR: A decorator to insert aPRargument into a function's cal for easyprint()style debugging or information.Promotable: A mixin class which supports the@promotedecorator by providing a default.promote(cls,obj)class method.promote: A decorator to promote argument values automatically in annotated functions.strable: Decorator for functions which may accept astrinstead of their core type.uses_cmd_options: A decorator to provide default keyword arguments from the prevailingcs.cmdutils.BaseCommandOptionsif available, otherwise fromoption_defaults.with_: A decorator to runfuncinside awith obj:.
Module contents:
-
ALL(func): Include this function's name in its module's__all__list.Example:
from cs.deco import ALL __all__ = [] def obscure_function(...): ... @ALL def well_known_function(...): ... -
attr(*da, **dkw): A decorator to set attributes on a function. Example:@attr(hook_names=('hook1', 'hook2')) def func(): .....This is just a more overt and clear form of:
def func(): ..... func.hook_names=('hook1', 'hook2') -
cached(*a, **kw): OBSOLETE version of cached, suggestion: cs.cache.cachedmethodFormer name for @cachedmethod.
-
cachedmethod(*a, **kw): OBSOLETE version of cachedmethod, suggestion: cs.cache.cachedmethod@cachedmethod is now in cs.cache.
-
contextdecorator(*da, **dkw): A decorator for a context manager functioncmgrfuncwhich turns it into a decorator for other functions.This supports easy implementation of "setup" and "teardown" code around other functions without the tedium of defining the wrapper function itself. See the examples below.
The resulting context manager accepts an optional keyword parameter
provide_context, defaultFalse. If true, the context returned from the context manager is provided as the first argument to the call to the wrapped function.Note that the context manager function
cmgrfunchas not yet been wrapped with@contextmanager, that is done by@contextdecorator.This decorator supports both normal functions and generator functions.
With a normal function the process is:
- call the context manager with
(func,a,kw,*da,**dkw), returningctxt, wheredaanddkware the positional and keyword parameters supplied when the decorator was defined. - within the context
return the value of
func(ctxt,*a,**kw)ifprovide_contextis true or the value offunc(*a,**kw)if not (the default)
With a generator function the process is:
- obtain an iterator by calling
func(*a,**kw) - for iterate over the iterator, yielding its results,
by calling the context manager with
(func,a,kw,**da,**dkw), around eachnext()Note that it is an error to provide a true value forprovide_contextif the decorated function is a generator function.
Some examples follow.
Trace the call and return of a specific function:
@contextdecorator def tracecall(func, a, kw): """ Trace the call and return from some function. This can easily be adapted to purposes such as timing a function call or logging use. """ print("call %s(*%r,**%r)" % (func, a, kw)) try: yield except Exception as e: print("exception from %s(*%r,**%r): %s" % (func, a, kw, e)) raise else: print("return from %s(*%r,**%r)" % (func, a, kw)) @tracecall def f(): """ Some function to trace. """ @tracecall(provide_context=True): def f(ctxt, *a, **kw): """ A function expecting the context object as its first argument, ahead of whatever other arguments it would normally require. """See who is making use of a generator's values, when a generator might be invoked in one place and consumed elsewhere:
from cs.py.stack import caller @contextdecorator def genuser(genfunc, *a, **kw): user = caller(-4) print(f"iterate over {genfunc}(*{a!r},**{kw!r}) from {user}") yield @genuser def linesof(filename): with open(filename) as f: yield from f # obtain a generator of lines here lines = linesof(__file__) # perhaps much later, or in another function for lineno, line in enumerate(lines, 1): print("line %d: %d words" % (lineno, len(line.split())))Turn on "verbose mode" around a particular function:
import sys import threading from cs.context import stackattrs class State(threading.local): def __init__(self): # verbose if stderr is on a terminal self.verbose = sys.stderr.isatty() # per thread global state state = State() @contextdecorator def verbose(func): with stackattrs(state, verbose=True) as old_attrs: if not old_attrs['verbose']: print(f"enabled verbose={state.verbose} for function {func}") # yield the previous verbosity as the context yield old_attrs['verbose'] # turn on verbose mode @verbose def func(x, y): if state.verbose: # print if verbose print("x =", x, "y =", y) # turn on verbose mode and also pass in the previous state # as the first argument @verbose(provide_context=True): def func2(old_verbose, x, y): if state.verbose: # print if verbose print("old_verbosity =", old_verbose, "x =", x, "y =", y) - call the context manager with
-
contextual(func): Wrap a simple function as a context manager.This was written to support users of
@strable, which requires itsopen_functo return a context manager; this turns an arbitrary function into a context manager.Example promoting a trivial function:
>>> f = lambda: 3 >>> cf = contextual(f) >>> with cf() as x: print(x) 3 -
decorator(deco): A decorator for decorator functions to support optional arguments and also to allow specifying additional attributes to apply to the decorated function.The decorated function is updated by
functools.update_wrapperand also has its__name__and__doc__set to those from before the decoration.The return of such a decorator is usually the conventional decorated function, but may alternatively be a
(decorated,attrs)2-tuple whereattrsis a mapping of additional attributes to apply todecorated. This allows overriding the restored__name__and__doc__from above, and potentially other useful attributes.The actual decorator function (eg
mydeco) ends up being called as:mydeco(func, *da, **dkw)allowing
daanddkwto affect the behaviour of the decoratormydeco.Examples:
# define your decorator as if always called with func and args @decorator def mydeco(func, *da, arg2=None): ... decorate func subject to the values of da and arg2 # @mydeco called with defaults @mydeco def func1(...): ... # @mydeco called with nondefault arguments @mydeco('foo', arg2='bah') def func2(...): ...The
@mydecodecorator itself is then written as though the arguments were always supplied. -
default_params(*da, **dkw): A decorator to provide factory functions for default parameters.This decorator accepts the following special keyword parameters:
_strict: defaultFalse; if true only replace genuinely missing parameters; if false also replace the traditionalNoneplaceholder value The remaining keyword parameters are factory functions providing the respective default values.
Typical use as a decorator factory:
# in your support module uses_ds3 = default_params(ds3client=get_ds3client) # calling code which needs a ds3client @uses_ds3 def do_something(.., *, ds3client, ...): ... make queries using ds3client ...This replaces the standard boilerplate and avoids replicating knowledge of the default factory as exhibited in this legacy code:
def do_something(.., *, ds3client=None, ...): if ds3client is None: ds3client = get_ds3client() ... make queries using ds3client ...It's quite common for me to associate one of these with a class. I have a
HasThreadStatemixin class which maintains a thread-local state object which I use to store a per-thread "ambient" instance of the class so that it does not need to be plumbed through every call (including all the intermediate calls which have no interest in the object, the horror!) So I'll often do this:class Thing(..., HasThreadState): .... uses_thing = default_params(thing=Thing.default)This can be used to provide the ambient instance of
Thingto functions while allowing the caller to omit any mention of aThingor to pass a specific instance if sensible. (In this examplke,Thing.defaultis a method provided by the mixin.)And then there's the atypical one off direct use, which is not really a big win over the conventional way:
@default_params(dbconn=open_default_dbconn,debug=lambda:settings.DB_DEBUG_MODE) def dbquery(query, *, dbconn): dbconn.query(query) -
fmtdoc(func): A decorator to format a function's docstring. This replaces the docstring with that string formatted against the function's module__dict__usingstr.format_map.A quirk of
format_mapallows us to also support:{name=}: the f-string{name=}notation{name==}: the f-string{name=}notation with the function module name prefixed
This supports simple formatted docstrings. Example:
FUNC_ENVVAR = 'FUNC_SETTING FUNC_DEFAUlT = 12 @fmtdoc def func(): """ Do something with the environment variable `${FUNC_ENVVAR}`. The default if no `${FUNC_ENVVAR}` comes from `{FUNC_DEFAUlT==}`. """ print(os.environ.get(FUNC_ENVVAR, FUNC_DEFAUlT))This gives
functhis docstring:Do something with the environment variable `$FUNC_SETTING`. The default if no `$FUNC_SETTING` comes from `module.func.FUNC_DEFAUlT=12`.Warning: this decorator is intended for wiring "constants" into docstrings, not for dynamic values. Use for other types of values should be considered with trepidation.
-
logging_wrapper(*da, **dkw): Decorator for logging call shims which bumps thestacklevelkeyword argument so that the logging system chooses the correct frame to cite in messages.Note: has no effect on Python < 3.8 because
stacklevelonly appeared in that version. -
observable_class(property_names, only_unequal=False): Class decorator to make various instance attributes observable.Parameters:
property_names: an interable of instance property names to set up as observable properties. As a special case a singlestrcan be supplied if only one attribute is to be observed.only_unequal: only call the observers if the new property value is not equal to the previous proerty value. This requires property values to be comparable for inequality. Default:False, meaning that all updates will be reported.
-
OBSOLETE(*da, **dkw): A decorator for obsolete functions or classes.Use:
@OBSOLETE def func(...):or
@OBSOLETE("new_func_name") def func(...):This emits a warning log message before calling the decorated function. Only one warning is emitted per calling location.
-
PR(func, print_args_f=None, print_func=None, pr_suffix=':'): A decorator to insert aPRargument into a function's cal for easyprint()style debugging or information.The default
PRfunction essentially callsprint(), prefixing the function name and its first argument to theprint()arguments.Example:
@PR def my_func(x, y, *, PR, z): PR(f'start with {x=} and {y=}') .... PR(f' did something, now {x=}') .... -
class Promotable: A mixin class which supports the@promotedecorator by providing a default.promote(cls,obj)class method.
Promotable.promote(obj, **from_t_kw):
Promote obj to an instance of cls or raise TypeError.
This method supports the @promote decorator.
This base method will call the from_typename(obj,**from_t_kw)
class factory method if present, where typename is
obj.__class__.__name__.
Subclasses may override this method to promote other types, typically:
@classmethod
def promote(cls, obj):
if isinstance(obj, cls):
return obj
... various specific type promotions
... not done via a from_typename factory method
# fall back to Promotable.promote
return super().promote(obj)
An typical from_typename` factory method:
class Foo(Promotable):
def __init__(self, dbkey, dbrow):
self.key = dbkey
self.row_data = row
@classmethod
def from_str(cls, s : str):
"""Accept a database key string, return a `Foo` instance."""
row = db_lookup(s)
return cls(s, row)
This supports using @promote on functions with Foo instances:
@promote
def do_it(foo : Foo):
... work with foo ...
but calling it as:
do_it("foo_key_value")
-
promote(*da, **dkw): A decorator to promote argument values automatically in annotated functions.If the annotation is
Optional[some_type]orUnion[some_type,None]then the promotion will be tosome_typebut a value ofNonewill be passed through unchanged.The decorator accepts optional parameters:
params: if supplied, only parameters in this list will be promotedtypes: if supplied, only types in this list will be considered for promotion
For any parameter with a type annotation, if that type has a
.promote(value)class method and the function is called with a value not of the type of the annotation, the.promotemethod will be called to promote the value to the expected type.Note that the
Promotablemixin provides a.promote()method which promotesobjto the class if the class has a factory class methodfrom_typename(obj)where typename isobj.__class__.__name__. A common case for me is lexical objects which have afrom_str(str)factory to produce an instance from its textual form.Additionally, if the
.promote(value)class method raises aTypeErrorandvaluehas a.as_typename attribute (where typename is the name of the type annotation), if that attribute is an instance method ofvaluethen promotion will be attempted by callingvalue.as_typename()otherwise the attribute will be used directly on the presumption that it is a property.A typical
promote(cls, obj)method looks like this:@classmethod def promote(cls, obj): if isinstance(obj, cls): return obj ... recognise various types ... ... and return a suitable instance of cls ... raise TypeError( "%s.promote: cannot promote %s:%r", cls.__name__, obj.__class__.__name__, obj)Example:
>>> from cs.timeseries import Epoch >>> from typeguard import typechecked >>> >>> @promote ... @typechecked ... def f(data, epoch:Epoch=None): ... print("epoch =", type(epoch), epoch) ... >>> f([1,2,3], epoch=12.0) epoch = <class 'cs.timeseries.Epoch'> Epoch(start=0, step=12)Example using a class with an
as_Pinstance method:>>> class P: ... def __init__(self, x): ... self.x = x ... @classmethod ... def promote(cls, obj): ... raise TypeError("dummy promote method") ... >>> class C: ... def __init__(self, n): ... self.n = n ... def as_P(self): ... return P(self.n + 1) ... >>> @promote ... def p(p: P): ... print("P =", type(p), p.x) ... >>> c = C(1) >>> p(c) P = <class 'cs.deco.P'> 2Note: one issue with this is due to the conflict in name between this decorator and the method it looks for in a class. The
promotemethod must appear after any methods in the class which are decorated with@promote, otherwise thepromotemethod supplants the namepromotemaking it unavailable as the decorator. I usually just make.promotethe last method.Failing example:
class Foo: @classmethod def promote(cls, obj): ... return promoted obj ... @promote def method(self, param:Type, ...): ...Working example:
class Foo: @promote def method(self, param:Type, ...): ... # promote method as the final method of the class @classmethod def promote(cls, obj): ... return promoted obj ... -
strable(*da, **dkw): Decorator for functions which may accept astrinstead of their core type.Parameters:
func: the function to decorateopen_func: the "open" factory to produce the core type if a string is provided; the default is the builtin "open" function. The returned value should be a context manager. Simpler functions can be decorated with@contextualto turn them into context managers if need be.
The usual (and default) example is a function to process an open file, designed to be handed a file object but which may be called with a filename. If the first argument is a
strthen that file is opened and the function called with the open file.Examples:
@strable def count_lines(f): return len(line for line in f) class Recording: "Class representing a video recording." ... @strable(open_func=Recording) def process_video(r): ... do stuff with `r` as a Recording instance ...Note: use of this decorator requires the
cs.pfxmodule. -
uses_cmd_options(*da, **dkw): A decorator to provide default keyword arguments from the prevailingcs.cmdutils.BaseCommandOptionsif available, otherwise fromoption_defaults.This exists to provide plumbing free access to options set up by a command line invocation using
cs.cmdutils.BaseCommand.If no
option_defaultsare provided, a singleoptionskeyword argument is provided which is the prevailingBaseCommand.Optionsinstance.The decorator accepts two optional "private" keyword arguments commencing with underscores:
_strict: defaultFalse; if true then anoption_defaultswill only be applied if the argument is missing from the function arguments, otherwise it will be applied if the argument is missing orNone_options_param_name: default'options'; this is the name of the singleoptionskeyword argument which will be supplied if there are nooption_defaults
Examples:
@uses_cmd_options(doit=True, quiet=False) def func(x, *, doit, quiet, **kw): if not quiet: print("something", x, kw) if doit: ... do the thing ... ... etc ... @uses_cmd_options() def func(x, *, options, **kw): if not options.quiet: print("something", x, kw) if options.doit: ... do the thing ... ... etc ... -
uses_doit(func):funcis not supplied, collect the arguments supplied and return a decorator which takes the subsequent callable and returnsdeco(func, *da, **kw). -
uses_force(func):funcis not supplied, collect the arguments supplied and return a decorator which takes the subsequent callable and returnsdeco(func, *da, **kw). -
uses_quiet(func):funcis not supplied, collect the arguments supplied and return a decorator which takes the subsequent callable and returnsdeco(func, *da, **kw). -
uses_verbose(func):funcis not supplied, collect the arguments supplied and return a decorator which takes the subsequent callable and returnsdeco(func, *da, **kw). -
with_(func, obj): A decorator to runfuncinside awith obj:.Example:
T = Thread(target=with_(some_context, target_func))
Release Log
Release 20251230: New @with_(func,obj) decorator to call func inside with obj:, primarily for Thread targets.
Release 20250914: Remove a warning which was really just debugging noise.
Release 20250724:
- @fmtdoc: support {name=} and {name==} format.
- Promotable.promote: improve the final TypeError on failure of the fallback cls(obj).
Release 20250601: @OBSOLETE: update to use the new @decorator mode to set name and doc.
Release 20250531: @decorator: optionally accept (decorated,attrs) to allow override of doc etc.
Release 20250513: Fix incorrect requirements.
Release 20250428:
- @decorator: bugfix the post decorate attribute update of name, doc etc - collect these values before the decoration.
- Promotable.promote: fall back to calling cls(obj) instead of raising a TypeError - the class init can do that.
Release 20250306: New @attr decorator for setting function attributes.
Release 20250103:
- @default_params, @promote: return regular function or generator depending on the nature of func.
- @cachedmethod moved to cs.cache.
Release 20241206: @uses_cmd_options: use an object subclass if there is no cs.cmdutils so that we can add attributes to the placeholder options object.
Release 20241109:
- Add @uses_force to @uses_doit, @uses_quiet, @uses_verbose decorator set.
- Fold @uses_cmd_option into @uses_cmd_options, provide "options" if no option_defaults.
- @promote: accept optional keyword arguments, plumb to the from_typename factory method.
Release 20241007: @uses_cmd_option: bugfix the infill of the defaults.
Release 20241003: New @uses_cmd_option and @uses_doit, @uses_quiet and @uses_verbose based on it.
Release 20240709: Bugfix @default_params: assemble the new signature with a complete set of parameters instead of only the defaulted ones.
Release 20240630:
- @default_params: apply modified signature parameters one at a time, as applying them in a single list seems to trigger some ordering checks.
- @promote: pass the original Parameter through to the wrapper so that we can use .default if needed, have the wrapper test for None last, so that we can promote None to something with a .from_NoneType method, make the check for the default value more specific.
Release 20240412: @decorator: apply the decorated function name to the metadecorator.
Release 20240326: default_params: update wrapper signature to mark the defaulted params as optional.
Release 20240316: Fixed release upload artifacts.
Release 20240314.1: New release with corrected install path.
Release 20240314: Tiny doc update.
Release 20240303: Promotable.promote: do not just handle str, handle anything with a from_typename factory method.
Release 20240211: Promotable: no longer abstract, provide a default promote() method which tries cls.from_str for str.
Release 20231129: @cachedmethod: ghastly hack for the revision attribute to accomodate objects which return None for missing attributes.
Release 20230331: @promote: pass None through for Optional parameters.
Release 20230212: New Promotable abstract class mixin, which requires the creation of a .promote(cls,obj)->cls class method.
Release 20230210: @promote: add support for .as_TypeName() instance method on the source object or a .as_TypeName property/attribut.
Release 20221214: @decorator: use functools.update_wrapper to propagate the decorated function's attributes to the wrapper (still legacy code for Python prior to 3.2).
Release 20221207: Small updates.
Release 20221106.1: @promote: support Optional[sometype] parameters.
Release 20221106: New @promote decorator to autopromote parameter values according to their type annotation.
Release 20220918.1: @default_param: append parameter descriptions to the docstring of the decorated function, bugfix name setting.
Release 20220918:
- @OBSOLETE: tweak message format.
- @default_params: docstring: simplify the example and improve the explaination.
- @default_params: set the name of the wrapper function.
Release 20220905:
- New @ALL decorator to include a function in all.
- New @default_params decorator for making decorators which provide default argument values from callables.
Release 20220805: @OBSOLETE: small improvements.
Release 20220327: Some fixes for @cachedmethod.
Release 20220311: @cachedmethod: change the meaning of poll_delay=None to mean "never goes stale" as I had thought it already did.
Release 20220227: @cachedmethod: more paranoid access to the revision attribute.
Release 20210823: @decorator: preserve the name of the wrapped function.
Release 20210123: Syntax backport for older Pythons.
Release 20201202: @decorator: tweak test for callable(da[0]) to accord with the docstring.
Release 20201025: New @contextdecorator decorator for context managers to turn them into setup/teardown decorators.
Release 20201020:
- @cachedmethod: bugfix cache logic.
- @strable: support generator functions.
Release 20200725: Overdue upgrade of @decorator to support combining the function and decorator args in one call.
Release 20200517.2: Minor upgrade to @OBSOLETE.
Release 20200517.1: Tweak @OBSOLETE and @cached (obsolete name for @cachedmethod).
Release 20200517: Get warning() from cs.gimmicks.
Release 20200417:
- @decorator: do not override doc on the decorated function, just provide default.
- New @logging_wrapper which bumps the
stacklevelparameter in Python 3.8 and above so that shims recite the correct caller.
Release 20200318.1: New @OBSOLETE to issue a warning on a call to an obsolete function, like an improved @cs.logutils.OBSOLETE (which needs to retire).
Release 20200318: @cachedmethod: tighten up the "is the value changed" try/except.
Release 20191012:
- New @contextual decorator to turn a simple function into a context manager.
- @strable: mention context manager requirement and @contextual as workaround.
Release 20191006: Rename @cached to @cachedmethod, leave compatible @cached behind which issues a warning (will be removed in a future release).
Release 20191004: Avoid circular import with cs.pfx by removing requirement and doing the import later if needed.
Release 20190905: Bugfix @deco: it turns out that you may not set the .module attribute on a property object.
Release 20190830.2: Make some getattr calls robust.
Release 20190830.1: @decorator: set the module of the wrapper.
Release 20190830: @decorator: set the module of the wrapper from the decorated target, aids cs.distinf.
Release 20190729: @cached: sidestep uninitialised value.
Release 20190601.1: @strable: fix the example in the docstring.
Release 20190601:
- Bugfix @decorator to correctly propagate the docstring of the subdecorator.
- Improve other docstrings.
Release 20190526: @decorator: add support for positional arguments and rewrite - simpler and clearer.
Release 20190512: @fmtdoc: add caveat against misuse of this decorator.
Release 20190404: New @fmtdoc decorator to format a function's doctsring against its module's globals.
Release 20190403:
- @cached: bugfix: avoid using unset sig_func value on first pass.
- @observable_class: further tweaks.
Release 20190322.1: @observable_class: bugfix init wrapper function.
Release 20190322:
- New class decorator @observable_class.
- Bugfix import of "warning".
Release 20190309: @cached: improve the exception handling.
Release 20190307.2: Fix docstring typo.
Release 20190307.1: Bugfix @decorator: final plumbing step for decorated decorator.
Release 20190307:
- @decorator: drop unused arguments, they get used by the returned decorator.
- Rework the @cached logic.
Release 20190220:
- Bugfix @decorator decorator, do not decorate twice.
- Have a cut at inheriting the decorated function's docstring.
Release 20181227:
- New decoartor @strable for function which may accept a str instead of their primary type.
- Improvements to @cached.
Release 20171231: Initial PyPI release.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cs_deco-20251230.tar.gz.
File metadata
- Download URL: cs_deco-20251230.tar.gz
- Upload date:
- Size: 27.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
009978320734330a2a3906e3c48b0992c2a4fca9b19a6e76bbb47c6089538cba
|
|
| MD5 |
ddaf46402cba8cd31a10bdce2736a7d9
|
|
| BLAKE2b-256 |
bcbcf63b5c27598f3a702dfdc8fc33fa4c538b54c5f84a2709a5b09b724f577b
|
File details
Details for the file cs_deco-20251230-py2.py3-none-any.whl.
File metadata
- Download URL: cs_deco-20251230-py2.py3-none-any.whl
- Upload date:
- Size: 22.3 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b4c11a29c1b9a11aa4fabe98d578fc627906c02de0fa9ccf94e7e54bf4dca13a
|
|
| MD5 |
67be1dfb72cb02263d61a5b52c529fbf
|
|
| BLAKE2b-256 |
6b80fe04cc8140b07be1efac1e8636f4c0e299d336a3cfa88ff95159562306ff
|