def compile(source: "something compilable", filename: "where the compilable thing comes from", mode: "is this a single statement or a suite?"): ...
@app.route('/ugly_calc') def ugly_calc(): x, y = int(request.args['x']), int(request.args['y']) op = OPERATION[request.args['op']] # . , — (, ) return str(op(x, y))
@app.route('/calc') def calc(x:Arg(int), y:Arg(int), op:Arg(_from=OPERATION)): return str(op(x, y))
class Arg(object): """ A request argument. """ def __init__(self, p_type=str, default=None): self.type = p_type self.default = default def _validate(self, value): """Perform conversion and validation on ``value``.""" return self.type(value) def validated(self, value): """ Convert and validate the given value according to the ``p_type`` Sets default if value is None """ if value is None: return self.default or self.type() return self._validate(value)
__annotations__
. >>> def lol(yep, foo: "woof", bar: 32*2): pass >>> lol.__annotations__ {'foo': 'woof', 'bar': 64}
lol
function does not get its yep
. class Parser(object): def __call__(self, dct): """ Just for simplify """ return self.validated(dct) def __init__(self, structure): self.structure = structure def validated(self, dct): for key, arg_instatce in self.structure.items(): dct[key] = arg_instatce(dct.get(key, None)) return dct
__annotations__
and decorators. Therefore, it would be better to add a standard wraps
order to avoid problems. from functools import wraps as orig_wraps, WRAPPER_ASSIGNMENTS WRAPPER_ASSIGNMENTS += ('__annotations__',) wraps = lambda x: orig_wraps(x, WRAPPER_ASSIGNMENTS)
class Endpoint(object): """ >>> plus = Endpoint(plus) >>> plus(5.0, "4") 9 """ def __call__(self, *args, **kwargs): return self.callable(*args, **kwargs) def __init__(self, func): self.__annotations__ = func.__annotations__ self.__name__ = func.__name__ self.set_func(func) def set_func(self, func): if func.__annotations__: # self.parser = Parser(func.__annotations__) # . # , # self.callable = self._wrap_callable(func) else: self.callable = func def _wrap_callable(self, func): @wraps(func) def wrapper(*args, **kwargs): # , # , . # - # return func(*args, **self.parser(kwargs)) return wrapper
class Flask(OrigFlask): # . froute = OrigFlask.route def route(self, rule, **options): """ . """ def registrator(func): # : 1 - 1 . if 'methods' in options: method = options['methods'][0] else: method = 'GET' wrapped = self.register_endpoint(rule, func, options.get('name'), method) return wrapped return registrator def register_endpoint(self, rule, func, endpoint_name=None, method='GET'): endpoint_name = endpoint_name or func.__name__ endpoint = Endpoint(func) wrapped = self._arg_taker(endpoint) self.add_url_rule(rule, "%s.%s" % (endpoint_name, method), wrapped, methods=[method]) return wrapped def _arg_taker(self, func): """ . . """ @wraps(func) def wrapper(*args, **kwargs): for key_name in func.__annotations__.keys(): kwargs[key_name] = request.args.get(key_name) return func(*args, **kwargs) return wrapper
Source: https://habr.com/ru/post/223041/
All Articles