"""
domonic.decorators
====================================
"""
import functools
import warnings
from functools import wraps
from typing import Callable
[docs]def el(element="div", string: bool = False):
"""[wraps the results of a function in an element]"""
if isinstance(element, str):
from domonic.dom import Document
element = Document.createElement(element).__class__
def decorator(function):
def wrapper(*args, **kwargs):
result = function(*args, **kwargs)
if string == False:
return element(result)
else:
return str(element(result))
return wrapper
return decorator
# @el(div)
# @el(span)
# def doctype(doctype):
# """
# @doctype('html')
# @doctype('xhtml')
# @doctype('xml')
# """
# def decorator(f):
# @wraps(f)
# def wrapper(*args, **kwargs):
# return f(*args, **kwargs)
# return wrapper
# return decorator
[docs]def called(before=None, error: Callable[[Exception], None] = None):
"""
Decorator to call a function before and after a function call.
"""
def decorator(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
if before:
before()
try:
return f(*args, **kwargs)
except Exception as e:
if error:
error(e)
else:
raise
finally:
if before:
before()
return wrapper
return decorator
"""[calls before() passing the response as args to the decorated function.
optional error handler. run the decorated function immediately.
WARNING: this is not for the regular decorating of a function
its syntactical sugar for a callback i.e.
@called(
lambda: º.ajax('https://www.google.com'),
lambda err: print('error:', err))
def success(data=None):
print("sweet!")
print(data)
"""
def decorator(function):
nonlocal before
nonlocal error
try:
if before is None:
return function()
r = before()
return function(r)
except Exception as e:
if error is not None:
error(e)
else:
raise e
return decorator
iife = called # pass None for an iife
# def static(endpoint, update="11101"):
# '''
# render the endpoint to a cron timestamp. when user vists that function.
# it will load the rendered version instead of executing the function.
# '''
# def dont_do_it(f):
# return None
# return dont_do_it
# https://www.python.org/dev/peps/pep-0318/
# https://stackoverflow.com/questions/15299878/how-to-use-python-decorators-to-check-function-arguments
def accepts(*types):
def check_accepts(f):
assert len(types) == f.__code__.co_argcount
def new_f(*args, **kwds):
for (a, t) in zip(args, types):
assert isinstance(a, t), "arg %r does not match %s" % (a, t)
return f(*args, **kwds)
new_f.__name__ = f.__name__
return new_f
return check_accepts
# @accepts(int)
# CACHED = {}
# def memoize(f):
# """
# @memoize
# def fib(n):
# if n in (0, 1):
# return n
# return fib(n - 1) + fib(n - 2)
# """
# @functools.wraps(f)
# def new_f(*args):
# if args in CACHED:
# return CACHED[args]
# else:
# result = f(*args)
# CACHED[args] = result
# return result
# return new_f
# def requires_websocket(f): # decorate all functions that require websockets to warn user
[docs]def silence(*args, **kwargs):
"""stop a function from doing anything"""
def dont_do_it(f):
return None
return dont_do_it
# @silence
[docs]def check(f):
"""Prints entry and exit of a function to the console"""
def new_f(*args, **kwargs):
print("Entering", f.__name__)
f(*args, **kwargs)
print("Exited", f.__name__)
return new_f
# @check()
[docs]def log(logger, level="info"):
"""@log(logging.getLogger('main'), level='warning')"""
def log_decorator(fn):
@functools.wraps(fn)
def wrapper(*a, **kwa):
getattr(logger, level)(fn.__name__)
return fn(*a, **kwa)
return wrapper
return log_decorator
[docs]def instead(f, somethingelse):
"""what to return if it fails"""
def new_f():
try:
return f()
except Exception as e:
print("failed", e)
return somethingelse
return new_f
# @instead("something else instead of what was supposed to happen")
[docs]def deprecated(func):
"""
marks a function as deprecated.
"""
@functools.wraps(func)
def new_func(*args, **kwargs):
warnings.simplefilter("always", DeprecationWarning)
warnings.warn(
"Call to deprecated function {}.".format(func.__name__), category=DeprecationWarning, stacklevel=2
)
warnings.simplefilter("default", DeprecationWarning)
return func(*args, **kwargs)
return new_func
[docs]def as_json(func):
"""decorate any function to return json instead of a python obj
note - used by JSON.py
"""
def JSON_decorator(*args, **kwargs):
import json
return json.dumps(func(*args, **kwargs))
return JSON_decorator
# def evt(event, *args, **kwargs): #TODO
# """
# a decorator that will call a function when an event is triggered.
# """
# def decorator(f):
# def wrapper(*args, **kwargs):
# return f(*args, **kwargs)
# return wrapper
# return decorator
# @evt('event', 'args', 'kwargs')
# def catch(f):
# """ catch exceptions and return None """
# def new_f():
# try:
# return f()
# except Exception as e:
# print('failed', e)
# return None
# return new_f
# def lenient(*args, **kwargs):
# """ can try to remap args if passed incorrectly.
# i.e. if expecting array but gets string, puts string in arr
# should never switch order probably. just re-type
# prints warning and runs
# """
'''
def aka(names):
""" @aka(*mylist) """
def aka_decorator(fn):
@functools.wraps(fn)
def wrapper(*a, **kwa):
return fn(*a, **kwa)
return wrapper
return log_decorator
'''