def test_decorator_required_method(): from indexpy import Index app = Index() @app.router.http.get("/get") async def need_get(): ... @app.router.http.post("/post") async def need_post(): ... @app.router.http.put("/put") async def need_put(): ... @app.router.http.patch("/patch") async def need_patch(): ... @app.router.http.delete("/delete") async def need_delete(): ... assert app.router.search("http", "/get")[1].__name__ == "need_get" assert app.router.search("http", "/post")[1].__name__ == "need_post" assert app.router.search("http", "/put")[1].__name__ == "need_put" assert app.router.search("http", "/patch")[1].__name__ == "need_patch" assert app.router.search("http", "/delete")[1].__name__ == "need_delete"
def test_wsgi_websocket(self): from starlette.websockets import WebSocketDisconnect client = TestClient(Index()) try: resp = client.websocket_connect("/django/") except WebSocketDisconnect as e: assert e.code == 1001 else: assert False, "Must be raise WebSocketDisconnect"
def test_openapi_single_function_tags(): app = Index() openapi = OpenAPI("Title", "description", "1.0") app.router << "/docs" // openapi.routes @app.router.http.get("/", name=None, tags=["tag0"]) async def homepage(): return "" assert openapi._generate_path(app.router.search("http", "/")[1], "/", {}) == { "get": {"tags": ["tag0"]} }
def test_url_for(): from indexpy import Index app = Index() @app.router.http("/hello", name="hello") @app.router.http("/hello/{name}", name="hello-with-name") async def hello(request): return f"hello {request.path_params.get('name')}" assert app.router.url_for("hello") == "/hello" assert app.router.url_for("hello-with-name", {"name": "Aber"}) == "/hello/Aber"
def test_openapi_routes_tags(): app = Index() openapi = OpenAPI("Title", "description", "1.0") app.router << "/docs" // openapi.routes async def homepage(): return "" app.router << Routes( HttpRoute("/", homepage) @ required_method("GET"), tags=["tag0"] ) assert openapi._generate_path(app.router.search("http", "/")[1], "/", {}) == { "get": {"tags": ["tag0"]} }
async def test_cors(): cors_middleware = CORSMiddleware() from indexpy import HttpRoute, Index app = Index() async def homepage(): return "homepage" app.router << (HttpRoute("/", homepage) @ cors_middleware) async with TestClient(app, headers={"origin": "testserver"}) as client: resp = await client.get("/") assert resp.headers["access-control-allow-origin"] == "testserver"
def test_decorator(): from indexpy import Index app = Index() @app.router.http("/hello", name="hello") async def hello(): ... @app.router.websocket("/hello", name="hello_ws") async def hello_ws(): ... assert app.router.search("http", "/hello")[0] == {} assert app.router.search("websocket", "/hello")[0] == {} assert app.router.search("http", "/hello") != (app.router.search( "websocket", "/hello"))
def test_lshift(): from indexpy import Index from indexpy.routing import HttpRoute, SocketRoute app = Index() async def hello(): return "hello world" async def hello_ws(): ... (app.router << HttpRoute("/hello", hello, name="hello") << SocketRoute( "/hello", hello_ws, name="hello_ws")) assert app.router.search("http", "/hello")[0] == {} assert app.router.search("websocket", "/hello")[0] == {} assert app.router.search("http", "/hello") != (app.router.search( "websocket", "/hello"))
def app(): app = Index() class Path(BaseModel): name: str = None @app.router.http("/cat", name=None) @app.router.http("/cat/{name}") class Cat(HTTPView): async def get(self): if not self.request.path_params: return self.request.method return self.request.method + " " + self.request.path_params["name"] async def post(self, path: Path): if not self.request.path_params: return self.request.method return self.request.method + " " + path.name return app
def test_openapi_single_function_summary_and_description(): app = Index() openapi = OpenAPI("Title", "description", "1.0") app.router << "/docs" // openapi.routes @app.router.http.get("/0", name=None, summary="Summary", description="Description") async def _(): return "" @app.router.http.get("/1", name=None, summary="Summary") async def _(): return "" @app.router.http.get("/2", name=None, summary="Summary") async def _(): """ Description """ return "" @app.router.http.get("/3", name=None) async def _(): """ Summary Description """ return "" assert openapi._generate_path(app.router.search("http", "/0")[1], "/", {}) == { "get": {"summary": "Summary", "description": "Description"} } assert openapi._generate_path(app.router.search("http", "/1")[1], "/", {}) == { "get": {"summary": "Summary"} } assert openapi._generate_path(app.router.search("http", "/2")[1], "/", {}) == { "get": {"summary": "Summary", "description": "Description"} } assert openapi._generate_path(app.router.search("http", "/3")[1], "/", {}) == { "get": {"summary": "Summary", "description": "Description"} }
def app(): app = Index() @app.router.http("/", method="get") def homepage(request): return "" class Name(BaseModel): name: str = None @app.router.http("/cat", name=None) @app.router.http("/cat/{name}") class Cat(HTTPView): async def get(self, name: str = Path(None)): if not self.request.path_params: return self.request.method return self.request.method + " " + name async def post(self, path: Name = Exclusive("path", title="Cat Name")): if not self.request.path_params: return self.request.method return self.request.method + " " + path.name return app
# @File: main.py # @Software: PyCharm from indexpy import Index # 路由 from indexpy.http import Request from indexpy.http.responses import Response, JSONResponse from indexpy.openapi import OpenAPI from jwt import ExpiredSignatureError import redis from routes.index import index_routes from routes.user import user_routes from utils.logger import AppLog from utils.db import database app = Index(templates=["templates"]) log = AppLog("test") # openAPI 文档自动生成,不需要的可以注释掉 # app.mount_asgi( # "/v1", # OpenAPI("xxxx后端接口", "作者:dimples_yj", "0.1.0", tags={ # "user": { # "description": "用户登录、注册接口", # "paths": ["/login", "/register"] # } # }) # ) app.router.extend(index_routes) app.router.extend(user_routes)
def app(router): from indexpy import Index app = Index() app.router = router return app
def test_openapi_page(): app = Index() app.router.extend( SubRoutes("/openapi", OpenAPI("Title", "description", "1.0").routes)) @app.router.http("/hello", method="get") async def hello(request): """ hello 接口描述 """ pass class Path(BaseModel): name: str @app.router.http("/path/{name}", method="get") async def path(request, path: Path): pass @app.router.http("/http-view") class HTTPClass(HTTPView): @describe_response( HTTPStatus.OK, content={"text/html": { "schema": { "type": "string" }, }}, ) async def get(self): """ ... ...... """ @describe_response(HTTPStatus.CREATED, content=Path) async def post(self): """ ... ...... """ @describe_response(HTTPStatus.NO_CONTENT) async def delete(self): """ ... ...... """ def just_middleware(endpoint): describe_extra_docs( endpoint, { "parameters": [{ "name": "Authorization", "in": "header", "description": "JWT Token", "required": True, "schema": { "type": "string" }, }] }, ) return endpoint middleware_routes = SubRoutes( "/middleware", [ HttpRoute("/path/{name}", path, "middleware-path", method="get"), HttpRoute("/http-view", HTTPClass, "middleware-HTTPClass"), ], http_middlewares=[just_middleware], ) app.router.extend(middleware_routes) client = TestClient(app) assert client.get("/openapi/docs").status_code == 200 openapi_docs_text = client.get("/openapi/docs").text _ = """definitions: {} info: description: description title: Title version: '1.0' openapi: 3.0.0 paths: /hello: get: description: 接口描述 summary: hello /http-view: delete: description: '......' parameters: &id001 - description: JWT Token in: header name: Authorization required: true schema: type: string responses: 204: description: Request fulfilled, nothing follows summary: '...' get: description: '......' parameters: *id001 responses: 200: content: &id002 text/html: schema: type: string description: Request fulfilled, document follows summary: '...' post: description: '......' parameters: *id001 responses: 201: content: application/json: schema: properties: name: title: Name type: string required: - name title: Path type: object description: Document created, URL follows summary: '...' /middleware/http-view: delete: description: '......' parameters: *id001 responses: 204: description: Request fulfilled, nothing follows summary: '...' get: description: '......' parameters: *id001 responses: 200: content: *id002 description: Request fulfilled, document follows summary: '...' post: description: '......' parameters: *id001 responses: 201: content: application/json: schema: properties: name: title: Name type: string required: - name title: Path type: object description: Document created, URL follows summary: '...' /middleware/path/{name}: get: parameters: - description: '' in: path name: name required: true schema: title: Name type: string - &id003 description: JWT Token in: header name: Authorization required: true schema: type: string /path/{name}: get: parameters: - description: '' in: path name: name required: true schema: title: Name type: string - *id003 servers: - description: Current server url: http://testserver tags: [] """ assert openapi_docs_text == _
Return source files """ realpath = FilePath(".") / filepath.lstrip("./") if realpath.exists() and realpath.is_file(): return realpath else: raise HTTPException(404) async def ws(): await websocket.accept() while not await websocket.is_disconnected(): await websocket.send_json({"data": "(^_^)"}) await asyncio.sleep(app.state.wait_time) await websocket.close() app = Index( debug=True, routes=[ HttpRoute("/", homepage), HttpRoute("/exc", exc), HttpRoute("/message", message), HttpRoute("/sources/{filepath:path}", sources) @ required_method("GET"), SocketRoute("/", ws), ], ) app.router << "/docs" // OpenAPI("", "", "").routes app.state.wait_time = 1
async def test_openapi_page(): app = Index() openapi = OpenAPI("Title", "description", "1.0") app.router << Routes("/docs" // openapi.routes, namespace="docs") assert app.router.url_for("docs:json_docs") == "/docs/json" @app.router.http("/hello") @describe_response(200, content=List[str]) async def hello(): """ hello """ pass class Username(BaseModel): name: str @app.router.http("/path/{name}") async def path(name: str = Path(...)): pass @app.router.http("/http-view") class HTTPClass(HttpView): @describe_response( HTTPStatus.OK, content={ "text/html": { "schema": {"type": "string"}, } }, ) async def get(self): """ ... ...... """ @describe_response(HTTPStatus.CREATED, content=Username) async def post(self): """ ... ...... """ @describe_response(HTTPStatus.NO_CONTENT) async def delete(self): """ ... ...... """ def just_middleware(endpoint): describe_extra_docs( endpoint, { "parameters": [ { "name": "Authorization", "in": "header", "description": "JWT Token", "required": True, "schema": {"type": "string"}, } ] }, ) return endpoint middleware_routes = "/middleware" // Routes( HttpRoute("/path/{name}", path, "middleware-path"), HttpRoute("/http-view", HTTPClass, "middleware-HTTPClass"), http_middlewares=[just_middleware], ) app.router << middleware_routes client = TestClient(app) response = await client.get("/docs", allow_redirects=False) assert response.status_code == 307 assert response.headers["location"] == "http://localhost/docs/" response = await client.get("/docs/") assert response.status_code == 200 response = await client.get("/docs/json") assert response.status_code == 200 assert len(response.headers["hash"]) == 32 openapi_docs_text = response.text assert ( openapi_docs_text == '{"openapi":"3.0.0","info":{"title":"Title","description":"description","version":"1.0"},"paths":{"/http-view":{"get":{"summary":"...","description":"......","responses":{"200":{"description":"Request fulfilled, document follows","content":{"text/html":{"schema":{"type":"string"}}}}},"parameters":[{"name":"Authorization","in":"header","description":"JWT Token","required":true,"schema":{"type":"string"}}]},"post":{"summary":"...","description":"......","responses":{"201":{"description":"Document created, URL follows","content":{"application/json":{"schema":{"title":"Username","type":"object","properties":{"name":{"title":"Name","type":"string"}},"required":["name"]}}}}},"parameters":[{"name":"Authorization","in":"header","description":"JWT Token","required":true,"schema":{"type":"string"}}]},"delete":{"summary":"...","description":"......","responses":{"204":{"description":"Request fulfilled, nothing follows"}},"parameters":[{"name":"Authorization","in":"header","description":"JWT Token","required":true,"schema":{"type":"string"}}]}},"/middleware/http-view":{"get":{"summary":"...","description":"......","responses":{"200":{"description":"Request fulfilled, document follows","content":{"text/html":{"schema":{"type":"string"}}}}},"parameters":[{"name":"Authorization","in":"header","description":"JWT Token","required":true,"schema":{"type":"string"}}]},"post":{"summary":"...","description":"......","responses":{"201":{"description":"Document created, URL follows","content":{"application/json":{"schema":{"title":"Username","type":"object","properties":{"name":{"title":"Name","type":"string"}},"required":["name"]}}}}},"parameters":[{"name":"Authorization","in":"header","description":"JWT Token","required":true,"schema":{"type":"string"}}]},"delete":{"summary":"...","description":"......","responses":{"204":{"description":"Request fulfilled, nothing follows"}},"parameters":[{"name":"Authorization","in":"header","description":"JWT Token","required":true,"schema":{"type":"string"}}]}}},"tags":[],"servers":[{"url":"http://localhost","description":"Current server"}],"components":{}}' )
from indexpy import Index app = Index(try_html=False) @app.router.http("/", method="get") async def homepage(request): return "" @app.router.http("/user/{user_id}", method="get") async def user(request): return request.path_params["user_id"] @app.router.http("/user", method="post") async def userinfo(request): return ""
def test_openapi_page(): app = Index() openapi = OpenAPI("Title", "description", "1.0") app.router.extend(SubRoutes("/openapi", openapi.routes)) @app.router.http("/hello", method="get") @describe_response(200, content=List[str]) async def hello(request): """ hello """ pass class Username(BaseModel): name: str @app.router.http("/path/{name}", method="get") async def path(request, name: str = Path(...)): pass @app.router.http("/http-view") class HTTPClass(HTTPView): @describe_response( HTTPStatus.OK, content={"text/html": { "schema": { "type": "string" }, }}, ) async def get(self): """ ... ...... """ @describe_response(HTTPStatus.CREATED, content=Username) async def post(self): """ ... ...... """ @describe_response(HTTPStatus.NO_CONTENT) async def delete(self): """ ... ...... """ def just_middleware(endpoint): describe_extra_docs( endpoint, { "parameters": [{ "name": "Authorization", "in": "header", "description": "JWT Token", "required": True, "schema": { "type": "string" }, }] }, ) return endpoint middleware_routes = SubRoutes( "/middleware", [ HttpRoute("/path/{name}", path, "middleware-path", method="get"), HttpRoute("/http-view", HTTPClass, "middleware-HTTPClass"), ], http_middlewares=[just_middleware], ) app.router.extend(middleware_routes) client = TestClient(app) assert client.get("/openapi/docs").status_code == 200 openapi_docs_text = client.get("/openapi/docs").text assert ( openapi_docs_text == '{"openapi":"3.0.0","info":{"title":"Title","description":"description","version":"1.0"},"paths":{"/hello":{"get":{"summary":"hello","responses":{"200":{"description":"Request fulfilled, document follows","content":{"application/json":{"schema":{"title":"ParsingModel[List[str]]","type":"array","items":{"type":"string"}}}}}}}},"/http-view":{"get":{"summary":"...","description":"......","responses":{"200":{"description":"Request fulfilled, document follows","content":{"text/html":{"schema":{"type":"string"}}}}},"parameters":[{"name":"Authorization","in":"header","description":"JWT Token","required":true,"schema":{"type":"string"}}]},"post":{"summary":"...","description":"......","responses":{"201":{"description":"Document created, URL follows","content":{"application/json":{"schema":{"title":"Username","type":"object","properties":{"name":{"title":"Name","type":"string"}},"required":["name"]}}}}},"parameters":[{"name":"Authorization","in":"header","description":"JWT Token","required":true,"schema":{"type":"string"}}]},"delete":{"summary":"...","description":"......","responses":{"204":{"description":"Request fulfilled, nothing follows"}},"parameters":[{"name":"Authorization","in":"header","description":"JWT Token","required":true,"schema":{"type":"string"}}]}},"/path/{name}":{"get":{"parameters":[{"in":"path","name":"name","description":"","required":true,"schema":{"title":"Name","type":"string"}},{"name":"Authorization","in":"header","description":"JWT Token","required":true,"schema":{"type":"string"}}],"responses":{"422":{"content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"loc":{"title":"Loc","description":"error field","type":"array","items":{"type":"string"}},"type":{"title":"Type","description":"error type","type":"string"},"msg":{"title":"Msg","description":"error message","type":"string"}},"required":["loc","type","msg"]}}}},"description":"Failed to verify request parameters"}}}},"/middleware/path/{name}":{"get":{"parameters":[{"in":"path","name":"name","description":"","required":true,"schema":{"title":"Name","type":"string"}},{"name":"Authorization","in":"header","description":"JWT Token","required":true,"schema":{"type":"string"}}],"responses":{"422":{"content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"loc":{"title":"Loc","description":"error field","type":"array","items":{"type":"string"}},"type":{"title":"Type","description":"error type","type":"string"},"msg":{"title":"Msg","description":"error message","type":"string"}},"required":["loc","type","msg"]}}}},"description":"Failed to verify request parameters"}}}},"/middleware/http-view":{"get":{"summary":"...","description":"......","responses":{"200":{"description":"Request fulfilled, document follows","content":{"text/html":{"schema":{"type":"string"}}}}},"parameters":[{"name":"Authorization","in":"header","description":"JWT Token","required":true,"schema":{"type":"string"}}]},"post":{"summary":"...","description":"......","responses":{"201":{"description":"Document created, URL follows","content":{"application/json":{"schema":{"title":"Username","type":"object","properties":{"name":{"title":"Name","type":"string"}},"required":["name"]}}}}},"parameters":[{"name":"Authorization","in":"header","description":"JWT Token","required":true,"schema":{"type":"string"}}]},"delete":{"summary":"...","description":"......","responses":{"204":{"description":"Request fulfilled, nothing follows"}},"parameters":[{"name":"Authorization","in":"header","description":"JWT Token","required":true,"schema":{"type":"string"}}]}}},"tags":[],"servers":[{"url":"http://testserver","description":"Current server"}],"definitions":{}}' )
import asyncio from indexpy import Index from indexpy.__version__ import __version__ from indexpy.http.responses import ServerSendEventResponse from indexpy.openapi import OpenAPI, describe_response from indexpy.routing import Routes, SubRoutes app = Index( debug=True, routes=Routes( SubRoutes( "/openapi", OpenAPI( "Index.py Example", "Just a simple example, and for display debug page.", __version__, ).routes, namespace="openapi", )), ) @app.router.http("/", method="get") @describe_response( 200, content={"text/plain": { "schema": { "type": "string" } }},
from indexpy import Index from indexpy.routing import FileRoutes, ASGIRoute from indexpy.http.responses import RedirectResponse app = Index() app.router.extend(FileRoutes("views", suffix=".php")) app.router.append( ASGIRoute("/", RedirectResponse("/home.php"), name=None, type=("http", )))
def test_django_admin(self): client = TestClient(Index()) resp = client.get("/django/admin/") assert resp.status_code == 200, resp.status_code
""" async def message_gen(): for i in range(5): await asyncio.sleep(1) yield {"id": i, "data": "hello"} return message_gen() @required_method("GET") async def sources(filepath: str = Path()): """ Return source files """ realpath = FilePath(".") / filepath.lstrip("./") try: return FileResponse(realpath) except FileNotFoundError: raise HTTPException(404) app = Index( debug=True, routes=[ HttpRoute("/", homepage), HttpRoute("/exc", exc), HttpRoute("/message", message), HttpRoute("/sources/{filepath:path}", sources), ], )