def decorator(fn): func = tornado.gen.coroutine(fn) transmute_func = TransmuteFunction(fn) @tornado.gen.coroutine @wraps(transmute_func.raw_func) def wrapper(self, *passed_args, **kwargs): result, exc = None, None content_type = self.request.headers.get("Content-Type", None) param_extractor = ParamExtractorTornado(self, kwargs) try: args, kwargs = param_extractor.extract_params( context, transmute_func, content_type ) args = list(passed_args) + args result = yield func(self, *args, **kwargs) except Exception as e: exc = e exc.__traceback__ = sys.exc_info()[2] response = transmute_func.process_result( context, result, exc, content_type ) self.set_header("Content-Type", response["content-type"]) self.set_status(response["code"]) self.finish(response["body"]) wrapper.transmute_func = transmute_func return wrapper
def response_transmute_func(): @describe( paths="/api/v1/create_if_authorized/", response_types={ 401: { "type": str, "description": "unauthorized" }, 201: { "type": bool, "headers": { "location": { "type": str } } }, }, ) @annotate({"username": str}) def create_if_authorized(username): if username != "im the boss": return Response("this is unauthorized!", 201) else: return Response(True, 401) return TransmuteFunction(create_if_authorized)
def single_body_transmute_func(): @describe(paths="/", body_parameters="body") @annotate({"body": Pet}) def body_param_func(): return None return TransmuteFunction(body_param_func)
def complex_transmute_func(): @describe(paths="/api/v1/adopt") @annotate({"return": Pet}) def adopt(): return Pet({"kind": "dog", "age": 5}) return TransmuteFunction(adopt)
def transmute_func_custom_code(): @describe(paths="/api/v1/multiply", success_code=201) @annotate({"left": int, "right": int, "return": int}) def multiply(left, right): return left * right return TransmuteFunction(multiply)
def transmute_func_post(): @describe(paths="/api/v1/multiply", methods=["POST"]) @annotate({"left": int, "right": int, "return": int}) def multiply(left, right): return left * right return TransmuteFunction(multiply)
def test_large_str_benchmark(benchmark, context): """ a benchmark of a fake full execution flow of a transmute function. """ s = "a" * 100000 func = TransmuteFunction(body_string) obj_json = json.dumps(s) benchmark(lambda: execute(context, func, obj_json))
def decorator(fn): fn = describe(**kwargs)(fn) transmute_func = TransmuteFunction(fn) routes, handler = create_routes_and_handler(transmute_func, context) for r in routes: # push swagger info. if not hasattr(app_or_blueprint, SWAGGER_ATTR_NAME): setattr(app_or_blueprint, SWAGGER_ATTR_NAME, SwaggerSpec()) swagger_obj = getattr(app_or_blueprint, SWAGGER_ATTR_NAME) swagger_obj.add_func(transmute_func, context) app_or_blueprint.route(r, methods=transmute_func.methods)(handler) return handler
def test_complex_benchmark_attrs(benchmark, context): """ a benchmark of a fake full execution flow of a transmute function. """ obj = ComplexModelAttrs(user=UserAttrs(name="Richard Stallman", age=104), description="this is a test", is_allowed=True) complex_func = TransmuteFunction(complex_body_method_attrs) complex_json = json.dumps(context.serializers.dump(type(obj), obj)) benchmark(lambda: execute(context, complex_func, complex_json))
def add_route(app, fn, context=default_context): """ a decorator that adds a transmute route to the application. """ transmute_func = TransmuteFunction(fn, args_not_from_request=["request"]) handler = create_handler(transmute_func, context=context) get_swagger_spec(app).add_func(transmute_func, context) for p in transmute_func.paths: aiohttp_path = _convert_to_aiohttp_path(p) resource = app.router.add_resource(aiohttp_path) for method in transmute_func.methods: resource.add_route(method, handler)
def test_complex_benchmark(benchmark, context): """ a benchmark of a fake full execution flow of a transmute function. """ obj = ComplexModel( { "user": {"name": "Richard Stallman", "age": 104}, "description": "this is a test", "is_allowed": True, } ) complex_func = TransmuteFunction(complex_body_method) complex_json = json.dumps(context.serializers.dump(type(obj), obj)) benchmark(lambda: execute(context, complex_func, complex_json))
def test_swagger_parameter_description(): """ if parameter descriptions are added to a function, they should appear in the swagger json. """ parameter_descriptions = { "left": "the left operand", "right": "the right operand", "header": "the header", "path": "the path", "return": "the result", } @describe( paths="/api/v1/adopt/{path}", parameter_descriptions=parameter_descriptions, header_parameters=["header"], ) @annotate({ "left": int, "right": int, "header": str, "path": str, "return": int }) def adopt(left, right, header, path): return left + right func = TransmuteFunction(adopt) routes = SwaggerSpec() routes.add_func(func, default_context) spec = routes.swagger_definition() params = spec["paths"]["/api/v1/adopt/{path}"]["get"]["parameters"] for param in spec["paths"]["/api/v1/adopt/{path}"]["get"]["parameters"]: assert parameter_descriptions[param["name"]] == param["description"] assert (parameter_descriptions["return"] == spec["paths"] ["/api/v1/adopt/{path}"]["get"]["responses"]["200"]["schema"] ["description"])
def transmute_route(app, fn, context=default_context): """ this is the main interface to transmute. It will handle adding converting the python function into the a flask-compatible route, and adding it to the application. """ transmute_func = TransmuteFunction(fn) routes, handler = create_routes_and_handler(transmute_func, context) for r in routes: """ the route being attached is a great place to start building up a swagger spec. the SwaggerSpec object handles creating the swagger spec from transmute routes for you. almost all web frameworks provide some app-specific context that one can add values to. It's recommended to attach and retrieve the swagger spec from there. """ if not hasattr(app, SWAGGER_ATTR_NAME): setattr(app, SWAGGER_ATTR_NAME, SwaggerSpec()) swagger_obj = getattr(app, SWAGGER_ATTR_NAME) swagger_obj.add_func(transmute_func, context) app.route(r, methods=transmute_func.methods)(handler)
def test_simple_benchmark(benchmark, context): simple_func = TransmuteFunction(simple_body_method) simple_json = json.dumps(1) benchmark(lambda: execute(context, simple_func, simple_json))