예제 #1
0
    async def test_unit__general_exception_handling__ok__nominal_case(
            self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        @hapic.with_api_doc()
        async def hello(request):
            return 1 / 0

        app = web.Application(debug=True)
        app.router.add_get("/", hello)
        context = AiohttpContext(
            app, default_error_builder=MarshmallowDefaultErrorBuilder())
        context.handle_exception(ZeroDivisionError, 400)
        hapic.set_context(context)

        client = await aiohttp_client(app)
        resp = await client.get("/")

        json = await resp.json()
        assert resp.status == 400
        assert {
            "details": {
                "error_detail": {}
            },
            "message": "division by zero",
            "code": None,
        } == json
예제 #2
0
파일: run.py 프로젝트: coolkat64/rolling
def run(args: argparse.Namespace) -> None:
    # Configure logging
    if args.debug:
        configure_logging(logging.DEBUG)
    else:
        configure_logging(logging.INFO)

    kernel = get_kernel(
        args.world_map_source,
        args.tile_maps_folder,
        args.game_config_folder,
        server_db_path=args.server_db_path,
    )
    server_logger.info("Create web application")
    app = get_application(kernel)

    # Configure hapic
    server_logger.info("Configure web api")
    context = AiohttpContext(app,
                             debug=args.debug,
                             default_error_builder=ErrorBuilder())
    context.handle_exception(HTTPNotFound, http_code=404)
    context.handle_exception(UserDisplayError, http_code=400)
    context.handle_exception(Exception, http_code=500)
    hapic.set_processor_class(RollingSerpycoProcessor)
    hapic.set_context(context)
    hapic.add_documentation_view("/doc")

    kernel.init()
    server_logger.info("Start server listening on {}:{}".format(
        args.host, args.port))
    web.run_app(app, host=args.host, port=args.port, access_log=server_logger)
예제 #3
0
    async def test_aiohttp_output_body__error__incorrect_output_body(
            self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class OuputBodySchema(marshmallow.Schema):
            i = marshmallow.fields.Integer(required=True)

        @hapic.output_body(OuputBodySchema())
        async def hello(request):
            return {"i": "bob"}  # NOTE: should be integer

        app = web.Application(debug=True)
        app.router.add_get("/", hello)
        hapic.set_context(
            AiohttpContext(
                app, default_error_builder=MarshmallowDefaultErrorBuilder()))
        client = await aiohttp_client(app)

        resp = await client.get("/")
        assert resp.status == 500

        data = await resp.text()
        data = await resp.json()
        assert "Validation error of output data" == data.get("message")
        assert {
            "i": ["Missing data for required field."]
        } == data.get("details")
예제 #4
0
    async def test_aiohttp_output_stream__error__interrupt_py37(
            self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class OuputStreamItemSchema(marshmallow.Schema):
            name = marshmallow.fields.String(required=True)

        from .py37.stream import get_func_with_output_stream_and_error

        hello = get_func_with_output_stream_and_error(hapic,
                                                      OuputStreamItemSchema,
                                                      ignore_on_error=False)

        app = web.Application(debug=True)
        app.router.add_get("/", hello)
        hapic.set_context(
            AiohttpContext(
                app, default_error_builder=MarshmallowDefaultErrorBuilder()))
        client = await aiohttp_client(app)

        resp = await client.get("/")
        assert resp.status == 200

        line = await resp.content.readline()
        assert b'{"name": "Hello, bob"}\n' == line

        line = await resp.content.readline()
        assert b"" == line
예제 #5
0
    def test_unit__generate_output_stream_doc__ok__nominal_case(
            self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class OuputStreamItemSchema(marshmallow.Schema):
            name = marshmallow.fields.String(required=True)

        @hapic.with_api_doc()
        @hapic.output_stream(OuputStreamItemSchema())
        async def get_users(request, hapic_data):
            pass

        app = web.Application(debug=True)
        app.router.add_get("/", get_users)
        hapic.set_context(
            AiohttpContext(
                app, default_error_builder=MarshmallowDefaultErrorBuilder()))

        doc = hapic.generate_doc("aiohttp", "testing")
        # INFO BS 2019-04-15: Prevent keep of OrderedDict
        doc = json.loads(json.dumps(doc))

        assert "/" in doc.get("paths")
        assert "get" in doc["paths"]["/"]
        assert "200" in doc["paths"]["/"]["get"].get("responses", {})
        assert {
            "items": {
                "$ref": "#/definitions/OuputStreamItemSchema"
            },
            "type": "array"
        } == doc["paths"]["/"]["get"]["responses"]["200"]["schema"]
예제 #6
0
    async def test_unit__global_exception__ok__nominal_case(self, aiohttp_client):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        @hapic.with_api_doc()
        async def divide_by_zero(request):
            raise ZeroDivisionError()

        app = web.Application(debug=True)
        context = AiohttpContext(app)
        hapic.set_context(context)
        context.handle_exception(ZeroDivisionError, http_code=HTTPStatus.BAD_REQUEST)
        app.router.add_get("/", divide_by_zero)
        client = await aiohttp_client(app)
        response = await client.get("/")

        assert 400 == response.status
예제 #7
0
    async def test_aiohttp_output_stream__ok__nominal_case(self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class AsyncGenerator:
            def __init__(self):
                self._iterator = iter([{"name": "Hello, bob"}, {"name": "Hello, franck"}])

            async def __aiter__(self):
                return self

            async def __anext__(self):
                return next(self._iterator)

        class OuputStreamItemSchema(marshmallow.Schema):
            name = marshmallow.fields.String()

        @hapic.output_stream(OuputStreamItemSchema())
        async def hello(request):
            return AsyncGenerator()

        app = web.Application(debug=True)
        app.router.add_get("/", hello)
        hapic.set_context(
            AiohttpContext(app, default_error_builder=MarshmallowDefaultErrorBuilder())
        )
        client = await aiohttp_client(app)

        resp = await client.get("/")
        assert resp.status == 200

        line = await resp.content.readline()
        assert b'{"name": "Hello, bob"}\n' == line

        line = await resp.content.readline()
        assert b'{"name": "Hello, franck"}\n' == line
예제 #8
0
    async def test_aiohttp_input_path__error_wrong_input_parameter(
            self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class InputPathSchema(marshmallow.Schema):
            i = marshmallow.fields.Integer()

        @hapic.input_path(InputPathSchema())
        async def hello(request, hapic_data: HapicData):
            i = hapic_data.path.get("i")
            return web.Response(text="integer: {}".format(str(i)))

        app = web.Application(debug=True)
        app.router.add_get("/{i}", hello)
        hapic.set_context(
            AiohttpContext(
                app, default_error_builder=MarshmallowDefaultErrorBuilder()))
        client = await aiohttp_client(app)

        resp = await client.get("/bob")  # NOTE: should be integer here
        assert resp.status == 400

        error = await resp.json()
        assert "Validation error of input data" in error.get("message")
        assert {"i": ["Not a valid integer."]} == error.get("details")
예제 #9
0
    async def test_unit__post_file__ok__put_success(self, aiohttp_client,
                                                    loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class InputFilesSchema(marshmallow.Schema):
            avatar = marshmallow.fields.Raw()

        @hapic.with_api_doc()
        @hapic.input_files(InputFilesSchema())
        async def update_avatar(request: Request, hapic_data: HapicData):
            avatar = hapic_data.files["avatar"]
            assert isinstance(avatar, FileField)
            assert b"text content of file" == avatar.file.read()
            return Response(body="ok")

        app = web.Application(debug=True)
        app.router.add_put("/avatar", update_avatar)
        hapic.set_context(
            AiohttpContext(
                app, default_error_builder=MarshmallowDefaultErrorBuilder()))
        client = await aiohttp_client(app)

        resp = await client.put(
            "/avatar", data={"avatar": io.StringIO("text content of file")})
        assert resp.status == 200
예제 #10
0
    async def test_aiohttp_input_body__error__incorrect_input_body(
            self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class InputBodySchema(marshmallow.Schema):
            i = marshmallow.fields.Integer()

        @hapic.input_body(InputBodySchema())
        async def hello(request, hapic_data: HapicData):
            i = hapic_data.body.get("i")
            return web.Response(text="integer, {}".format(i))

        app = web.Application(debug=True)
        app.router.add_post("/", hello)
        hapic.set_context(
            AiohttpContext(
                app, default_error_builder=MarshmallowDefaultErrorBuilder()))
        client = await aiohttp_client(app)

        resp = await client.post("/", data={"i": "bob"})  # NOTE: should be int
        assert resp.status == 400

        error = await resp.json()
        assert "Validation error of input data" in error.get("message")
        assert {"i": ["Not a valid integer."]} == error.get("details")
예제 #11
0
    async def test_unit__post_file__ok__missing_file(self, aiohttp_client,
                                                     loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class InputFilesSchema(marshmallow.Schema):
            avatar = marshmallow.fields.Raw(required=True)

        @hapic.with_api_doc()
        @hapic.input_files(InputFilesSchema())
        async def update_avatar(request: Request, hapic_data: HapicData):
            raise AssertionError("Test should no pass here")

        app = web.Application(debug=True)
        app.router.add_put("/avatar", update_avatar)
        hapic.set_context(
            AiohttpContext(
                app, default_error_builder=MarshmallowDefaultErrorBuilder()))
        client = await aiohttp_client(app)

        resp = await client.put("/avatar")
        assert resp.status == 400
        json_ = await resp.json()
        assert {
            "details": {
                "avatar": ["Missing data for required field"]
            },
            "message": "Validation error of input data",
            "code": None,
        } == json_
def get_aiohttp_serpyco_app_hapic(app):
    from example.fake_api.aiohttp_serpyco import hapic

    hapic.reset_context()
    hapic.set_context(
        AiohttpContext(app,
                       default_error_builder=SerpycoDefaultErrorBuilder()))
    return hapic
예제 #13
0
    def test_unit__generate_doc__ok__nominal_case(self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class InputPathSchema(marshmallow.Schema):
            username = marshmallow.fields.String(required=True)

        class InputQuerySchema(marshmallow.Schema):
            show_deleted = marshmallow.fields.Boolean(required=False)

        class UserSchema(marshmallow.Schema):
            name = marshmallow.fields.String(required=True)

        @hapic.with_api_doc()
        @hapic.input_path(InputPathSchema())
        @hapic.input_query(InputQuerySchema())
        @hapic.output_body(UserSchema())
        async def get_user(request, hapic_data):
            pass

        @hapic.with_api_doc()
        @hapic.input_path(InputPathSchema())
        @hapic.output_body(UserSchema())
        async def post_user(request, hapic_data):
            pass

        app = web.Application(debug=True)
        app.router.add_get("/{username}", get_user)
        app.router.add_post("/{username}", post_user)
        hapic.set_context(
            AiohttpContext(app, default_error_builder=MarshmallowDefaultErrorBuilder())
        )

        doc = hapic.generate_doc("aiohttp", "testing")
        # INFO BS 2019-04-15: Prevent keep of OrderedDict
        doc = json.loads(json.dumps(doc))

        assert "UserSchema" in doc.get("definitions")
        assert {"name": {"type": "string"}} == doc["definitions"]["UserSchema"].get("properties")
        assert "/{username}" in doc.get("paths")
        assert "get" in doc["paths"]["/{username}"]
        assert "post" in doc["paths"]["/{username}"]

        assert [
            {"name": "username", "in": "path", "required": True, "type": "string"},
            {"name": "show_deleted", "in": "query", "required": False, "type": "boolean"},
        ] == doc["paths"]["/{username}"]["get"]["parameters"]
        assert {
            "200": {"schema": {"$ref": "#/definitions/UserSchema"}, "description": "200"}
        } == doc["paths"]["/{username}"]["get"]["responses"]

        assert [{"name": "username", "in": "path", "required": True, "type": "string"}] == doc[
            "paths"
        ]["/{username}"]["post"]["parameters"]
        assert {
            "200": {"schema": {"$ref": "#/definitions/UserSchema"}, "description": "200"}
        } == doc["paths"]["/{username}"]["get"]["responses"]
예제 #14
0
def worldmapc_web_app(worldmapc_kernel: Kernel, loop, aiohttp_client) -> TestClient:
    app = get_application(worldmapc_kernel)
    context = AiohttpContext(app, debug=True, default_error_builder=ErrorBuilder())
    context.handle_exception(HTTPNotFound, http_code=404)
    context.handle_exception(Exception, http_code=500)
    hapic.reset_context()
    hapic.set_processor_class(RollingSerpycoProcessor)
    hapic.set_context(context)
    return loop.run_until_complete(aiohttp_client(app))
    async def test_func__catch_one_exception__ok__aiohttp_case(
            self, test_client):
        from aiohttp import web

        app = web.Application()
        hapic = Hapic(processor_class=MarshmallowProcessor)
        context = AiohttpContext(app=app)
        hapic.set_context(context)

        async def my_view(request):
            raise ZeroDivisionError("An exception message")

        app.add_routes([web.get("/my-view", my_view)])
        # FIXME - G.M - 17-05-2018 - Verify if:
        # - other view that work/raise an other exception do not go
        # into this code for handle this exceptions.
        # - response come clearly from there, not from web framework:
        #  Check not only http code, but also body.
        # see  issue #158 (https://github.com/algoo/hapic/issues/158)
        context.handle_exception(ZeroDivisionError, http_code=400)
        test_app = await test_client(app)
        response = await test_app.get("/my-view")

        assert 400 == response.status
예제 #16
0
    async def test_aiohttp_handle_excpetion__ok__nominal_case(self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        @hapic.handle_exception(ZeroDivisionError, http_code=400)
        async def hello(request):
            1 / 0

        app = web.Application(debug=True)
        app.router.add_get("/", hello)
        hapic.set_context(
            AiohttpContext(app, default_error_builder=MarshmallowDefaultErrorBuilder())
        )
        client = await aiohttp_client(app)

        resp = await client.get("/")
        assert resp.status == 400

        data = await resp.json()
        assert "division by zero" == data.get("message")
예제 #17
0
    async def test_request_header__ok__lowercase_key(self, aiohttp_client):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class HeadersSchema(marshmallow.Schema):
            foo = marshmallow.fields.String(required=True)

        @hapic.with_api_doc()
        @hapic.input_headers(HeadersSchema())
        async def hello(request, hapic_data: HapicData):
            return web.json_response(hapic_data.headers)

        app = web.Application(debug=True)
        hapic.set_context(AiohttpContext(app))
        app.router.add_get("/", hello)
        client = await aiohttp_client(app)
        response = await client.get("/", headers={"FOO": "bar"})
        assert 200 == response.status
        json_ = await response.json()
        assert {"foo": "bar"} == json_
예제 #18
0
파일: test_aiohttp.py 프로젝트: RoPP/hapic
    def test_unit__generate_doc_with_wildcard__ok__fixed_methods(self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        @hapic.with_api_doc()
        async def a_proxy(request):
            pass

        app = web.Application(debug=True)
        app.router.add_route(hdrs.METH_ANY, path="/", handler=a_proxy)
        hapic.set_context(
            AiohttpContext(app, default_error_builder=MarshmallowDefaultErrorBuilder())
        )

        doc = hapic.generate_doc("aiohttp", "testing", wildcard_method_replacement=["head"])
        # INFO BS 2019-04-15: Prevent keep of OrderedDict
        doc = json.loads(json.dumps(doc))

        assert 1 == len(doc["paths"]["/"])
        assert "head" in doc["paths"]["/"]
예제 #19
0
def get_aiohttp_context():
    h = Hapic(async_=True, processor_class=MarshmallowProcessor)
    aiohttp_app = web.Application(debug=True)
    h.reset_context()
    h.set_context(
        AiohttpContext(aiohttp_app, default_error_builder=MarshmallowDefaultErrorBuilder())
    )

    class MySchema(marshmallow.Schema):
        name = marshmallow.fields.String(required=True)

    @h.with_api_doc()
    @h.input_body(MySchema())
    def my_controller():
        return {"name": "test"}

    aiohttp_app.router.add_post("/", my_controller)

    return {"hapic": h, "app": aiohttp_app}
예제 #20
0
    async def test_aiohttp_output_body__ok__nominal_case(self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class OuputBodySchema(marshmallow.Schema):
            name = marshmallow.fields.String()

        @hapic.output_body(OuputBodySchema())
        async def hello(request):
            return {"name": "bob"}

        app = web.Application(debug=True)
        app.router.add_get("/", hello)
        hapic.set_context(
            AiohttpContext(app, default_error_builder=MarshmallowDefaultErrorBuilder())
        )
        client = await aiohttp_client(app)

        resp = await client.get("/")
        assert resp.status == 200

        data = await resp.json()
        assert "bob" == data.get("name")
예제 #21
0
    async def test_aiohttp_input_body__ok_nominal_case(self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class InputBodySchema(marshmallow.Schema):
            name = marshmallow.fields.String()

        @hapic.input_body(InputBodySchema())
        async def hello(request, hapic_data: HapicData):
            name = hapic_data.body.get("name")
            return web.Response(text="Hello, {}".format(name))

        app = web.Application(debug=True)
        app.router.add_post("/", hello)
        hapic.set_context(
            AiohttpContext(app, default_error_builder=MarshmallowDefaultErrorBuilder())
        )
        client = await aiohttp_client(app)

        resp = await client.post("/", data={"name": "bob"})
        assert resp.status == 200

        text = await resp.text()
        assert "Hello, bob" in text
@hapic.with_api_doc()
@hapic.input_path(EmptyPath)
@hapic.input_body(PartialSensor)
@hapic.output_body(Sensor)
async def PATCH_sensor(request, hapic_data: HapicData):
    print(hapic_data.body)
    if hapic_data.body.name and sensor.name != hapic_data.body.name:
        sensor.name = hapic_data.body.name

    if hapic_data.body.location:
        if sensor.location != hapic_data.body.location:
            sensor.location = hapic_data.body.location

    return sensor


app = web.Application()
app.add_routes([
    web.get(r"/about", GET_about),
    web.get(r"/sensor", GET_sensor),
    web.patch(r"/sensor", PATCH_sensor),
])

hapic.set_context(
    AiohttpContext(app, default_error_builder=SerpycoDefaultErrorBuilder()))

hapic.add_documentation_view("/api/doc", "DOC", "Generated doc")
print(json.dumps(hapic.generate_doc()))
aiohttp_autoreload.start()
web.run_app(app)
예제 #23
0

async def do_login(request):
    data = await request.json()
    login = data["login"]

    return web.json_response({"login": login})


app = web.Application(debug=True)
app.add_routes([
    web.get("/n/", display_name),
    web.get("/n/{name}", display_name),
    web.post("/n/{name}", display_name),
    web.post("/b/", display_body),
    web.post("/login", do_login),
])

hapic.set_context(
    AiohttpContext(app,
                   default_error_builder=MarshmallowDefaultErrorBuilder()))

# import json
# import yaml
# print(yaml.dump(
#     json.loads(json.dumps(hapic.generate_doc())),
#     default_flow_style=False,
# ))

web.run_app(app)