Пример #1
0
    def __init__(
        self,
        debug: bool = False,
        routes: typing.Sequence[BaseRoute] = None,
        middleware: typing.Sequence[Middleware] = None,
        exception_handlers: typing.Dict[typing.Union[int,
                                                     typing.Type[Exception]],
                                        typing.Callable] = None,
        on_startup: typing.Sequence[typing.Callable] = None,
        on_shutdown: typing.Sequence[typing.Callable] = None,
        lifespan: typing.Callable[["Starlette"], typing.AsyncGenerator] = None,
    ) -> None:
        # The lifespan context function is a newer style that replaces
        # on_startup / on_shutdown handlers. Use one or the other, not both.
        assert lifespan is None or (
            on_startup is None and on_shutdown is None
        ), "Use either 'lifespan' or 'on_startup'/'on_shutdown', not both."

        self._debug = debug
        self.state = State()
        self.router = Router(routes,
                             on_startup=on_startup,
                             on_shutdown=on_shutdown,
                             lifespan=lifespan)
        self.exception_handlers = ({} if exception_handlers is None else
                                   dict(exception_handlers))
        self.user_middleware = [] if middleware is None else list(middleware)
        self.middleware_stack = self.build_middleware_stack()
Пример #2
0
    def __init__(
        self,
        *,
        engine: Engine = None,
        sdl: str = None,
        graphiql: typing.Union[None, bool, GraphiQL] = True,
        path: str = "/",
        subscriptions: typing.Union[bool, Subscriptions] = None,
        context: dict = None,
        schema_name: str = "default",
    ) -> None:
        if engine is None:
            assert sdl, "`sdl` expected if `engine` not given"
            engine = Engine(sdl=sdl, schema_name=schema_name)

        assert engine, "`engine` expected if `sdl` not given"

        self.engine = engine

        if context is None:
            context = {}

        if graphiql is True:
            graphiql = GraphiQL()
        elif not graphiql:
            graphiql = None

        assert graphiql is None or isinstance(graphiql, GraphiQL)

        if subscriptions is True:
            subscriptions = Subscriptions(path="/subscriptions")
        elif not subscriptions:
            subscriptions = None

        assert subscriptions is None or isinstance(subscriptions,
                                                   Subscriptions)

        self.router = Router(on_startup=[self.startup])

        if graphiql and graphiql.path is not None:
            self.router.add_route(path=graphiql.path,
                                  endpoint=GraphiQLEndpoint)

        self.router.add_route(path=path, endpoint=GraphQLEndpoint)

        if subscriptions is not None:
            self.router.add_websocket_route(path=subscriptions.path,
                                            endpoint=SubscriptionEndpoint)

        config = GraphQLConfig(
            engine=self.engine,
            context=context,
            graphiql=graphiql,
            path=path,
            subscriptions=subscriptions,
        )

        self.app = GraphQLMiddleware(self.router, config=config)

        self._started_up = False
Пример #3
0
    def __init__(
        self,
        debug: bool = False,
        exception_handlers: Dict[Union[int, Type[Exception]], Callable] = None,
        middleware: Sequence[Union[Middleware, Callable]] = None,
        response_class: Optional[Type[Response]] = None,
        modules: Optional[List[ModuleType]] = None,
        auto_bind: bool = False,
    ):
        self._debug = debug
        self.injector = Injector(auto_bind=auto_bind)
        self.router = Router()
        self.exception_handlers = {
            exc_type: self._inject_exception_handler(handler)
            for exc_type, handler in (
                {} if exception_handlers is None else dict(exception_handlers)
            ).items()
        }
        self.user_middleware = (
            []
            if middleware is None
            else [self.prepare_middleware(m) for m in middleware]
        )
        self.user_middleware.insert(0, Middleware(RequestScopeMiddleware))
        self.middleware_stack = self.build_middleware_stack()
        self.cli = click.Group()
        self.response_class = response_class or JSONResponse

        self.injector.binder.bind(AppUnit, to=self, scope=SingletonScope)
        self.injector.binder.bind(Injector, to=self.injector, scope=SingletonScope)
        self.injector.binder.bind(Request, to=context.get_current_request)

        modules = modules or []
        for module in modules:
            self.add_module(module)
Пример #4
0
async def init_app(app: Application):
    swagger = Router()
    swagger.add_route('/schema/{chain}/{network}',
                      custom_schema,
                      include_in_schema=False)

    create_swagger(apispec, router=swagger)
    app.mount('/', swagger)
Пример #5
0
 def __init__(self,
              debug: bool = False,
              routes: typing.List[BaseRoute] = None) -> None:
     self._debug = debug
     self.router = Router(routes)
     self.exception_middleware = ExceptionMiddleware(self.router,
                                                     debug=debug)
     self.error_middleware = ServerErrorMiddleware(
         self.exception_middleware, debug=debug)
Пример #6
0
def create_swagger(apispec: APISpec, *, router: Router = None):
    handler = create_schema_handler(apispec)
    router.add_route('/schema', handler, include_in_schema=False)

    router.mount(
        path='/',
        app=StaticFiles(packages=[__package__], html=True),
        name='statics',
    )

    return router
Пример #7
0
 def __init__(self,
              debug: bool = False,
              template_directory: str = None) -> None:
     self._debug = debug
     self.router = Router()
     self.exception_middleware = ExceptionMiddleware(self.router,
                                                     debug=debug)
     self.error_middleware = ServerErrorMiddleware(
         self.exception_middleware, debug=debug)
     self.lifespan_middleware = LifespanMiddleware(self.error_middleware)
     self.schema_generator = None  # type: typing.Optional[BaseSchemaGenerator]
     self.template_env = self.load_template_env(template_directory)
Пример #8
0
    def test_limit(self):
        """
        Make sure a request is rejected if the client has exceeded the limit.
        """
        app = RateLimitingMiddleware(
            Router([Route("/", Endpoint)]),
            InMemoryLimitProvider(limit=5, timespan=1, block_duration=1),
        )

        client = TestClient(app)

        successful = 0
        for i in range(20):
            response = client.get("/")
            if response.status_code == 429:
                break
            else:
                successful += 1

        self.assertTrue(successful == 5)

        # After the 'block_duration' has expired, requests should be allowed
        # again.
        sleep(1.1)
        response = client.get("/")
        self.assertTrue(response.status_code == 200)
Пример #9
0
def test_lifespan_sync():
    startup_complete = False
    shutdown_complete = False

    def hello_world(request):
        return PlainTextResponse("hello, world")

    def run_startup():
        nonlocal startup_complete
        startup_complete = True

    def run_shutdown():
        nonlocal shutdown_complete
        shutdown_complete = True

    app = Router(
        on_startup=[run_startup],
        on_shutdown=[run_shutdown],
        routes=[Route("/", hello_world)],
    )

    assert not startup_complete
    assert not shutdown_complete
    with TestClient(app) as client:
        assert startup_complete
        assert not shutdown_complete
        client.get("/")
    assert startup_complete
    assert shutdown_complete
Пример #10
0
 def routes(cls):
     mount = cls.mount_name()
     return Router([
         Route("/",
               endpoint=cls.list_view,
               methods=["GET"],
               name=f"{mount}_list"),
         Route(
             "/create",
             endpoint=cls.create_view,
             methods=["GET", "POST"],
             name=f"{mount}_create",
         ),
         Route(
             f"/{cls.routing_id_part}/edit",
             endpoint=cls.update_view,
             methods=["GET", "POST"],
             name=f"{mount}_edit",
         ),
         Route(
             f"/{cls.routing_id_part}/delete",
             endpoint=cls.delete_view,
             methods=["GET", "POST"],
             name=f"{mount}_delete",
         ),
     ])
Пример #11
0
 def __init__(self, debug: bool = False) -> None:
     self.router = Router(routes=[])
     self.lifespan_handler = LifespanHandler()
     self.app = self.router
     self.exception_middleware = ExceptionMiddleware(self.router,
                                                     debug=debug)
     self.executor = ThreadPoolExecutor()
Пример #12
0
class BackendStarlette(ABCBackend):
    def __init__(self, api):
        self.api = api
        self.router = Router()

    def bind(self, app):
        """Bind the current API to given Starlette app."""
        app.router.routes.append(Mount(self.api.prefix, self.router))

    def register(self, endpoint, *paths, methods=None):
        """Register the given Endpoint in routing."""

        for path in paths:
            self.router.add_route(path,
                                  endpoint.as_view(self.api),
                                  methods=methods)

        return endpoint

    def to_response(self, response, status_code=200, **options):
        """Prepare a response."""
        if isinstance(response, Response):
            return response

        return JSONResponse(response, status_code=status_code, **options)

    def get_params(self, request):
        """Get Path params from the given request."""
        return dict(request.path_params)

    def get_query(self, request):
        """Get Query params from the given request."""
        return dict(request.query_params)

    async def get_data(self, request):
        """Get data from the given request."""
        content_type = request.headers.get('content-type')
        if content_type in {
                'application/x-www-form-urlencoded', 'multipart/form-data'
        }:
            return await request.form()

        if content_type == 'application/json':
            return await request.json()

        data = await request.body()
        return data.decode('utf-8')
Пример #13
0
def test_mount_urls():
    mounted = Router([Mount("/users", ok, name="users")])
    client = TestClient(mounted)
    assert client.get("/users").status_code == 200
    assert client.get("/users").url == "http://testserver/users/"
    assert client.get("/users/").status_code == 200
    assert client.get("/users/a").status_code == 200
    assert client.get("/usersa").status_code == 404
Пример #14
0
def test_reverse_mount_urls():
    mounted = Router([Mount("/users", ok, name="users")])
    assert mounted.url_path_for("users", path="/a") == "/users/a"

    users = Router([Route("/{username}", ok, name="user")])
    mounted = Router([Mount("/{subpath}/users", users, name="users")])
    assert (mounted.url_path_for("users:user", subpath="test",
                                 username="******") == "/test/users/tom")
    assert (mounted.url_path_for("users", subpath="test",
                                 path="/tom") == "/test/users/tom")
Пример #15
0
def test_datetime_convertor(test_client_factory, app: Router):
    client = test_client_factory(app)
    response = client.get("/datetime/2020-01-01T00:00:00")
    assert response.json() == {"datetime": "2020-01-01T00:00:00"}

    assert (app.url_path_for("datetime-convertor",
                             param=datetime(
                                 1996, 1, 22, 23, 0,
                                 0)) == "/datetime/1996-01-22T23:00:00")
Пример #16
0
def launch_emergency_app():
    """Launches a minimal application to inform the user about the incorrect configuration"""
    emergency_app = Starlette(debug=True)
    emergency_app = Router([
        Route('/{whatever:path}',
              endpoint=emergency_response,
              methods=['GET', 'POST']),
    ])
    uvicorn.run(emergency_app, host=WEBGUI_HOST, port=WEBGUI_PORT)
Пример #17
0
def serverStart():
    from starlette.applications import Starlette
    from starlette.routing import Router
    from starlette.routing import Route
    import uvicorn
    
    app = Router([Route('/', endpoint=graphQL, methods=['GET', 'POST'])])
    uvicorn.run(app, host='0.0.0.0', port=8000)
    return None
Пример #18
0
def test_raise_on_startup():
    def run_startup():
        raise RuntimeError()

    app = Router(routes=[Lifespan(on_startup=run_startup)])

    with pytest.raises(RuntimeError):
        with TestClient(app):
            pass  # pragma: nocover
Пример #19
0
def test_raise_on_shutdown():
    def run_shutdown():
        raise RuntimeError()

    app = Router(on_shutdown=[run_shutdown])

    with pytest.raises(RuntimeError):
        with TestClient(app):
            pass  # pragma: nocover
Пример #20
0
def test_routes():
    assert app.routes == [
        Route("/func", endpoint=func_homepage, methods=["GET"]),
        Route("/async", endpoint=async_homepage, methods=["GET"]),
        Route("/class", endpoint=Homepage),
        Mount(
            "/users",
            app=Router(routes=[
                Route("/", endpoint=all_users_page),
                Route("/{username}", endpoint=user_page),
            ]),
        ),
        Host(
            "{subdomain}.example.org",
            app=Router(routes=[Route("/", endpoint=custom_subdomain)]),
        ),
        Route("/500", endpoint=runtime_error, methods=["GET"]),
        WebSocketRoute("/ws", endpoint=websocket_endpoint),
    ]
Пример #21
0
 def __init__(
     self,
     debug: bool = False,
     routes: typing.List[BaseRoute] = None,
     middleware: typing.List[typing.Optional[Middleware]] = None,
     exception_handlers: typing.Dict[
         typing.Union[int, typing.Type[Exception]], typing.Callable
     ] = None,
     on_startup: typing.List[typing.Callable] = None,
     on_shutdown: typing.List[typing.Callable] = None,
 ) -> None:
     self._debug = debug
     self.state = State()
     self.router = Router(routes, on_startup=on_startup, on_shutdown=on_shutdown)
     self.exception_handlers = (
         {} if exception_handlers is None else dict(exception_handlers)
     )
     self.user_middleware = [item for item in middleware or [] if item is not None]
     self.middleware_stack = self.build_middleware_stack()
Пример #22
0
 def __init__(
     self,
     debug: bool = False,
     routes: typing.Sequence[BaseRoute] = None,
     middleware: typing.Sequence[Middleware] = None,
     exception_handlers: typing.Dict[
         typing.Union[int, typing.Type[Exception]], typing.Callable
     ] = None,
     on_startup: typing.Sequence[typing.Callable] = None,
     on_shutdown: typing.Sequence[typing.Callable] = None,
 ) -> None:
     self._debug = debug
     self.state = State()
     self.router = Router(routes, on_startup=on_startup, on_shutdown=on_shutdown)
     self.exception_handlers = (
         {} if exception_handlers is None else dict(exception_handlers)
     )
     self.user_middleware = [] if middleware is None else list(middleware)
     self.middleware_stack = self.build_middleware_stack()
Пример #23
0
    def __init__(
        self,
        *,
        engine: Engine = None,
        sdl: str = None,
        graphiql: typing.Union[bool, GraphiQL] = True,
        path: str = "/",
        subscriptions: typing.Union[bool, Subscriptions] = None,
        context: dict = None,
        schema_name: str = "default",
    ):
        if engine is None:
            assert sdl, "`sdl` expected if `engine` not given"
            engine = Engine(sdl=sdl, schema_name=schema_name)

        assert engine, "`engine` expected if `sdl` not given"

        self.engine = engine

        if context is None:
            context = {}

        if graphiql is True:
            graphiql = GraphiQL()

        if subscriptions is True:
            subscriptions = Subscriptions(path="/subscriptions")

        routes = []

        if graphiql and graphiql.path is not None:
            routes.append(Route(path=graphiql.path, endpoint=GraphiQLEndpoint))

        graphql_route = Route(path=path, endpoint=GraphQLEndpoint)
        routes.append(graphql_route)

        if subscriptions is not None:
            subscription_route = WebSocketRoute(path=subscriptions.path,
                                                endpoint=SubscriptionEndpoint)
            routes.append(subscription_route)

        config = GraphQLConfig(
            engine=self.engine,
            context=context,
            graphiql=graphiql,
            path=graphql_route.path,
            subscriptions=subscriptions,
        )

        router = Router(routes=routes)
        self.app = GraphQLMiddleware(router, config=config)
        self.lifespan = Lifespan(on_startup=self.startup)

        self._started_up = False
Пример #24
0
def setup_routes(app: Starlette):
    app.mount(
        '/',
        Router([
            Route('/',
                  endpoint=word_form,
                  methods=['GET', 'POST'],
                  name='index'),
            Route('/', endpoint=learn_word, methods=['GET'], name='learn'),
            Mount('/learn',
                  name='learn',
                  app=Router([
                      Route('/',
                            endpoint=learn_word,
                            methods=['GET'],
                            name='index'),
                      Route('/{word_id:int}/{answer:int}',
                            endpoint=learned_word,
                            methods=['GET'],
                            name='learned'),
                  ])),
            Mount('/w',
                  name='word',
                  app=Router([
                      Route('/create',
                            endpoint=word_create,
                            methods=['GET', 'POST'],
                            name='create'),
                      Route('/{word_id:int}/detail',
                            endpoint=word_detail,
                            methods=['GET'],
                            name='detail'),
                      Route('/{word_id:int}/delete',
                            endpoint=word_delete,
                            methods=['POST'],
                            name='delete'),
                  ])),

            # Auth
            Mount('/auth', name='auth', app=Router([*auth_routes])),

            # API
            Mount('/api',
                  app=Router([
                      Mount('/v1',
                            app=Router([
                                Mount('/status',
                                      app=Router([
                                          Route('/',
                                                endpoint=status,
                                                methods=['GET']),
                                      ])),
                            ])),
                  ])),
            Mount('/static', static_files, name='static'),
        ]))
Пример #25
0
 def __init__(self, visible=True):
     # self.app can be any ASGI app, but it must exist
     self.visible = visible
     self.app = Router()
     self.url = ""  # will be replaced during webserver init
     self.cache = {"skip": {}, "deps": {}}
     self.listeners = {
         "startup": set(),
         "shutdown": set(),
         "pipeline_update": set()
     }
     self.lastPipeline = None
Пример #26
0
def swagger_ui(
    schema_url: str = "/openapi.json",
    swagger_ui_title: str = "Piccolo Swagger UI",
    csrf_cookie_name: t.Optional[str] = DEFAULT_COOKIE_NAME,
    csrf_header_name: t.Optional[str] = DEFAULT_HEADER_NAME,
):
    """
    Even though ASGI frameworks such as FastAPI and BlackSheep have endpoints
    for viewing OpenAPI / Swagger docs, out of the box they don't work well
    with some Piccolo middleware (namely CSRF middleware, which requires
    Swagger UI to add the CSRF token to the header of each API call).

    By using this endpoint instead, it will work correctly with CSRF.

    **FastAPI example**

    .. code-block:: python

        from fastapi import FastAPI
        from piccolo_api.openapi.endpoints import swagger_ui

        # By setting these values to None, we disable the builtin endpoints.
        app = FastAPI(docs_url=None, redoc_url=None)

        app.mount('/docs', swagger_ui())

    :param schema_url:
        The URL to the OpenAPI schema.
    :param csrf_cookie_name:
        The name of the CSRF cookie.
    :param csrf_header_name:
        The HTTP header name which the CSRF cookie value will be added to.

    """

    # We return a router, because it's effectively a mini ASGI
    # app, which can be mounted in any ASGI app which supports mounting.
    router = Router()

    class DocsEndpoint(HTTPEndpoint):
        def get(self, request: Request):
            template = ENVIRONMENT.get_template("swagger_ui.html.jinja")
            html = template.render(
                schema_url=schema_url,
                swagger_ui_title=swagger_ui_title,
                csrf_cookie_name=csrf_cookie_name,
                csrf_header_name=csrf_header_name,
            )
            return HTMLResponse(content=html)

    class OAuthRedirectEndpoint(HTTPEndpoint):
        def get(self, request: Request):
            return get_swagger_ui_oauth2_redirect_html()

    router.add_route("/", endpoint=DocsEndpoint)
    router.add_route("/oauth2-redirect/", endpoint=OAuthRedirectEndpoint)

    return router
Пример #27
0
    def setup_server(self):
        # This could maybe be added to the API...
        log.info("Setting up server")
        self.add_exception_handler(WebargsHTTPException, http_exception)

        if self.api_loaded:
            return
        self.setup_database()
        route_table = []
        self.run_hook("add-routes", route_table)
        self.mount("/", Router(route_table))
        self.run_hook("finalize-routes")
        self.run_hook("asgi-setup", self)
        self.api_loaded = True
        log.info("Finished setting up server")
Пример #28
0
def app() -> Router:
    register_url_convertor("datetime", DateTimeConvertor())

    def datetime_convertor(request):
        param = request.path_params["param"]
        assert isinstance(param, datetime)
        return JSONResponse({"datetime": param.strftime("%Y-%m-%dT%H:%M:%S")})

    return Router(routes=[
        Route(
            "/datetime/{param:datetime}",
            endpoint=datetime_convertor,
            name="datetime-convertor",
        )
    ])
Пример #29
0
    def test_hooks(self):
        # TODO Replace these with mocks ...
        def pre_login_test(username):
            assert isinstance(username, str)

        async def pre_login_test_async(username):
            assert isinstance(username, str)

        def login_success_test(username, user_id):
            assert isinstance(username, str)
            assert isinstance(user_id, int)

        async def login_success_test_async(username, user_id):
            assert isinstance(username, str)
            assert isinstance(user_id, int)

        def login_failure_test(username):
            assert isinstance(username, str)

        def login_failure_test_async(username):
            assert isinstance(username, str)

        router = Router(
            routes=[
                Route(
                    "/login/",
                    session_login(
                        hooks=LoginHooks(
                            pre_login=[pre_login_test, pre_login_test_async],
                            login_success=[
                                login_success_test,
                                login_success_test_async,
                            ],
                            login_failure=[
                                login_failure_test,
                                login_failure_test_async,
                            ],
                        )
                    ),
                ),
            ]
        )
        app = ExceptionMiddleware(router)

        BaseUser(**self.credentials, active=True).save().run_sync()

        client = TestClient(app)
        client.post("/login/", json=self.credentials)
Пример #30
0
    def __init__(self, visible=True):
        self.visible = visible
        self.app = Router()
        if NT_AVAIL:
            self.netdict = NetworkDict("/CameraPublisher")
        self.funcs = {}  # {name: route}
        self.index_route = [
            Route("/", LiteralTemplate(self.TEMPLATE, funcs=self.funcs.keys()))
        ]
        self.listeners = {
            "startup": set(),
            "shutdown": set(),
            "pipeline_update": set()
        }

        self._update()