diff --git a/Pipfile.lock b/Pipfile.lock index 883415b..6a3e346 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -23,10 +23,10 @@ }, "aniso8601": { "hashes": [ - "sha256:b8a6a9b24611fc50cf2d9b45d371bfdc4fd0581d1cc52254f5502130a776d4af", - "sha256:bb167645c79f7a438f9dfab6161af9bed75508c645b1f07d1158240841d22673" + "sha256:513d2b6637b7853806ae79ffaca6f3e8754bdd547048f5ccc1420aec4b714f1e", + "sha256:d10a4bf949f619f719b227ef5386e31f49a2b6d453004b21f02661ccc8670c7b" ], - "version": "==6.0.0" + "version": "==7.0.0" }, "apispec": { "hashes": [ @@ -70,10 +70,10 @@ }, "graphene": { "hashes": [ - "sha256:77d61618132ccd084c343e64c22d806cee18dce73cc86e0f427378dbdeeac287", - "sha256:acf808d50d053b94f7958414d511489a9e490a7f9563b9be80f6875fc5723d2a" + "sha256:09165f03e1591b76bf57b133482db9be6dac72c74b0a628d3c93182af9c5a896", + "sha256:2cbe6d4ef15cfc7b7805e0760a0e5b80747161ce1b0f990dfdc0d2cf497c12f9" ], - "version": "==2.1.7" + "version": "==2.1.8" }, "graphql-core": { "hashes": [ @@ -158,10 +158,10 @@ }, "marshmallow": { "hashes": [ - "sha256:7ea8540fc7e35be3b0af8b017313944b984d5acdb118b4ba3c270ac9611765c7", - "sha256:bc91e3f90e86133241ac62ea0dd35217d631a207e8628430bc66c347dbe12f7d" + "sha256:23f684b54b1955ebd5bdfbdda4062e438ef86218f14f1a356f570cdf0c016ab3", + "sha256:fcfc9ffd75a883da06f30f604a4e81dd0b56eb9438f4d0a8de6bbaa163ce9ec3" ], - "version": "==3.0.0rc9" + "version": "==3.0.1" }, "promise": { "hashes": [ @@ -513,10 +513,10 @@ }, "marshmallow": { "hashes": [ - "sha256:7ea8540fc7e35be3b0af8b017313944b984d5acdb118b4ba3c270ac9611765c7", - "sha256:bc91e3f90e86133241ac62ea0dd35217d631a207e8628430bc66c347dbe12f7d" + "sha256:23f684b54b1955ebd5bdfbdda4062e438ef86218f14f1a356f570cdf0c016ab3", + "sha256:fcfc9ffd75a883da06f30f604a4e81dd0b56eb9438f4d0a8de6bbaa163ce9ec3" ], - "version": "==3.0.0rc9" + "version": "==3.0.1" }, "mccabe": { "hashes": [ @@ -590,11 +590,11 @@ }, "pytest": { "hashes": [ - "sha256:3805d095f1ea279b9870c3eeae5dddf8a81b10952c8835cd628cf1875b0ef031", - "sha256:abc562321c2d190dd63c2faadf70b86b7af21a553b61f0df5f5e1270717dc5a3" + "sha256:95d13143cc14174ca1a01ec68e84d76ba5d9d493ac02716fd9706c949a505210", + "sha256:b78fe2881323bd44fd9bd76e5317173d4316577e7b1cddebae9136a4495ec865" ], "index": "pypi", - "version": "==5.1.0" + "version": "==5.1.2" }, "pytest-cov": { "hashes": [ @@ -647,11 +647,11 @@ }, "sphinx": { "hashes": [ - "sha256:22538e1bbe62b407cf5a8aabe1bb15848aa66bb79559f42f5202bbce6b757a69", - "sha256:f9a79e746b87921cabc3baa375199c6076d1270cee53915dbd24fdbeaaacc427" + "sha256:0d586b0f8c2fc3cc6559c5e8fd6124628110514fda0e5d7c82e682d749d2e845", + "sha256:839a3ed6f6b092bb60f492024489cc9e6991360fb9f52ed6361acd510d261069" ], "index": "pypi", - "version": "==2.1.2" + "version": "==2.2.0" }, "sphinxcontrib-applehelp": { "hashes": [ @@ -704,10 +704,10 @@ }, "tqdm": { "hashes": [ - "sha256:1dc82f87a8726602fa7177a091b5e8691d6523138a8f7acd08e58088f51e389f", - "sha256:47220a4f2aeebbc74b0ab317584264ea44c745e1fd5ff316b675cd0aff8afad8" + "sha256:1be3e4e3198f2d0e47b928e9d9a8ec1b63525db29095cec1467f4c5a4ea8ebf9", + "sha256:7e39a30e3d34a7a6539378e39d7490326253b7ee354878a92255656dc4284457" ], - "version": "==4.33.0" + "version": "==4.35.0" }, "twine": { "hashes": [ @@ -747,10 +747,10 @@ }, "zipp": { "hashes": [ - "sha256:4970c3758f4e89a7857a973b1e2a5d75bcdc47794442f2e2dd4fe8e0466e809a", - "sha256:8a5712cfd3bb4248015eb3b0b3c54a5f6ee3f2425963ef2a0125b8bc40aafaec" + "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", + "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" ], - "version": "==0.5.2" + "version": "==0.6.0" } } } diff --git a/responder/api.py b/responder/api.py index ffca14c..56b85ea 100644 --- a/responder/api.py +++ b/responder/api.py @@ -68,21 +68,6 @@ class API: self.router = Router() - if openapi or docs_route: - self.openapi = OpenAPISchema( - app=self, - title="Web Service", - version="1.0", - openapi="3.0.2", - docs_route=docs_route, - description=description, - terms_of_service=terms_of_service, - contact=contact, - license=license, - openapi_route=openapi_route, - static_route=static_route, - ) - if static_dir is not None: if static_route is None: static_route = static_dir @@ -119,7 +104,7 @@ class API: os.makedirs(_dir, exist_ok=True) if self.static_dir is not None: - self.mount(self.static_route, StaticFiles(directory=self.static_dir)) + self.mount(self.static_route, self.static_app) self.formats = get_formats() @@ -140,12 +125,34 @@ class API: self.add_middleware(ServerErrorMiddleware, debug=debug) self.add_middleware(SessionMiddleware, secret_key=self.secret_key) + if openapi or docs_route: + self.openapi = OpenAPISchema( + app=self, + title="Web Service", + version="1.0", + openapi="3.0.2", + docs_route=docs_route, + description=description, + terms_of_service=terms_of_service, + contact=contact, + license=license, + openapi_route=openapi_route, + static_route=static_route, + ) + # TODO: Update docs for templates self.templates = Templates(directory=templates_dir) self.requests = ( self.session() ) #: A Requests session that is connected to the ASGI app. + @property + def static_app(self): + if not hasattr(self, "_static_app"): + assert self.static_dir is not None + self._static_app = StaticFiles(directory=self.static_dir) + return self._static_app + @staticmethod def _notfound_wsgi_app(environ, start_response): start_response("404 NOT FOUND", [("Content-Type", "text/plain")]) @@ -200,6 +207,7 @@ class API: endpoint=None, *, default=False, + static=True, check_existing=True, websocket=False, before_request=False, @@ -211,6 +219,14 @@ class API: :param default: If ``True``, all unknown requests will route to this view. :param static: If ``True``, and no endpoint was passed, render "static/index.html", and it will become a default route. """ + + # Path + if static: + assert self.static_dir is not None + if not endpoint: + endpoint = self._static_response + default = True + self.router.add_route( route, endpoint, @@ -220,6 +236,17 @@ class API: check_existing=check_existing, ) + async def _static_response(self, req, resp): + assert self.static_dir is not None + + index = (self.static_dir / "index.html").resolve() + if os.path.exists(index): + with open(index, "r") as f: + resp.html = "Hello world !" + else: + resp.status_code = status_codes.HTTP_404 + resp.text = "Not found." + def redirect( self, resp, location, *, set_text=True, status_code=status_codes.HTTP_301 ): diff --git a/responder/ext/schema/__init__.py b/responder/ext/schema/__init__.py index 9c717c0..be18b14 100644 --- a/responder/ext/schema/__init__.py +++ b/responder/ext/schema/__init__.py @@ -57,7 +57,7 @@ class Schema: self.static_route = static_route - self.app.mount(self.static_route, StaticFiles(directory=theme_path)) + self.app.static_app.add_directory(theme_path) @property def _apispec(self): diff --git a/responder/routes.py b/responder/routes.py index c53def1..6ff6535 100644 --- a/responder/routes.py +++ b/responder/routes.py @@ -208,7 +208,7 @@ class WebSocketRoute(BaseRoute): class Router: def __init__(self, routes=None, default_response=None, before_requests=None): self.routes = [] if routes is None else list(routes) - # [TODO] Make it's own router + # [TODO] Make its own router self.apps = {} self.default_endpoint = ( self.default_response if default_response is None else default_response diff --git a/responder/staticfiles.py b/responder/staticfiles.py index 93f26d7..66a57c1 100644 --- a/responder/staticfiles.py +++ b/responder/staticfiles.py @@ -1,18 +1,18 @@ -from whitenoise import WhiteNoise - - -def _notfound_wsgi_app(environ, start_response): - start_response("404 NOT FOUND", [("Content-Type", "text/plain")]) - return [b"Not Found."] - - -class StaticFiles: - def __init__(self, directory=None, mkdir=True): - self.directory = directory - self.app = WhiteNoise(_notfound_wsgi_app, root=self.directory) - - def __call__(self, environ, start_response): - return self.app(environ, start_response) - +import typing from starlette.staticfiles import StaticFiles + + +class StaticFiles(StaticFiles): + """I've created an issue to disccuss allowing multiple directories in starletter's `StaticFiles`. + + https://github.com/encode/starlette/issues/625 + + I've also made a PR to add this method to starlette StaticFiles + Once accepted we will remove this. + + https://github.com/encode/starlette/pull/626 + """ + + def add_directory(self, directory: str) -> None: + self.all_directories = [*self.all_directories, *self.get_directories(directory)] diff --git a/setup.py b/setup.py index 63a350e..1d5dcd3 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ required = [ "aiofiles", "pyyaml", "requests", - "graphene", + "graphene<3.0", "graphql-server-core>=1.1", "jinja2", "uvloop; sys_platform != 'win32' and sys_platform != 'cygwin' and sys_platform != 'cli'",