From 5ac162e38c3e20e7aa82adc574d9f38141f2aede Mon Sep 17 00:00:00 2001 From: Dinis Cruz Date: Sat, 23 Nov 2024 00:53:06 +0000 Subject: [PATCH] refactored imports --- osbot_fast_api/api/Fast_API.py | 50 ++++++++++++------- osbot_fast_api/api/Fast_API_Routes.py | 8 +-- osbot_fast_api/api/Fast_API__Http_Events.py | 32 ++++++++---- .../Middleware__Detect_Disconnect.py | 8 +-- .../middlewares/Middleware__Http_Request.py | 10 ++-- .../utils/http_shell/Http_Shell__Server.py | 1 - 6 files changed, 70 insertions(+), 39 deletions(-) diff --git a/osbot_fast_api/api/Fast_API.py b/osbot_fast_api/api/Fast_API.py index d11e264..175abcb 100644 --- a/osbot_fast_api/api/Fast_API.py +++ b/osbot_fast_api/api/Fast_API.py @@ -1,25 +1,9 @@ -import traceback -import types -from fastapi import FastAPI, Request, HTTPException -from fastapi.exceptions import RequestValidationError -from starlette.middleware.wsgi import WSGIMiddleware # todo replace this with a2wsgi from osbot_fast_api.api.Fast_API__Http_Events import Fast_API__Http_Events -from osbot_fast_api.api.middlewares.Middleware__Detect_Disconnect import Middleware__Detect_Disconnect -from osbot_fast_api.api.middlewares.Middleware__Http_Request import Middleware__Http_Request -from osbot_fast_api.utils.Version import Version from osbot_utils.base_classes.Type_Safe import Type_Safe -from starlette.middleware.cors import CORSMiddleware -from starlette.responses import RedirectResponse, JSONResponse -from starlette.staticfiles import StaticFiles from osbot_utils.helpers.Random_Guid import Random_Guid -from osbot_utils.utils.Lists import list_index_by -from osbot_utils.utils.Misc import list_set from osbot_utils.decorators.lists.index_by import index_by from osbot_utils.decorators.methods.cache_on_self import cache_on_self -from starlette.testclient import TestClient -from osbot_fast_api.api.routes.Routes_Config import Routes_Config -from osbot_fast_api.utils.http_shell.Http_Shell__Server import Model__Shell_Command, Http_Shell__Server -from osbot_fast_api.utils.Fast_API_Utils import Fast_API_Utils + DEFAULT_ROUTES_PATHS = ['/', '/config/status', '/config/version'] DEFAULT__NAME__FAST_API = 'Fast_API' @@ -38,6 +22,11 @@ def __init__(self, **kwargs): self.http_events.fast_api_name = self.name def add_global_exception_handlers(self): # todo: move to Fast_API + import traceback + from fastapi import Request, HTTPException + from fastapi.exceptions import RequestValidationError + from starlette.responses import JSONResponse + app = self.app() @app.exception_handler(Exception) async def global_exception_handler(request: Request, exc: Exception): @@ -57,10 +46,13 @@ async def validation_exception_handler(request: Request, exc: RequestValidationE def add_flask_app(self, path, flask_app): + from starlette.middleware.wsgi import WSGIMiddleware # todo replace this with a2wsgi + self.app().mount(path, WSGIMiddleware(flask_app)) return self def add_shell_server(self): + from osbot_fast_api.utils.http_shell.Http_Shell__Server import Model__Shell_Command, Http_Shell__Server def shell_server(shell_command: Model__Shell_Command): return Http_Shell__Server().invoke(shell_command) self.add_route_post(shell_server) @@ -82,15 +74,19 @@ def add_routes(self, class_routes): @cache_on_self def app(self, **kwargs): + from fastapi import FastAPI return FastAPI(**kwargs) def app_router(self): return self.app().router def client(self): + from starlette.testclient import TestClient # moved here for performance reasons return TestClient(self.app()) def fast_api_utils(self): + from osbot_fast_api.utils.Fast_API_Utils import Fast_API_Utils + return Fast_API_Utils(self.app()) def path_static_folder(self): # override this to add support for serving static files from this directory @@ -120,10 +116,15 @@ def route_remove(self, path): return False def routes_methods(self): + from osbot_utils.utils.Misc import list_set + return list_set(self.routes(index_by='method_name')) def routes_paths(self, include_default=False, expand_mounts=False): + from osbot_utils.utils.Lists import list_index_by + from osbot_utils.utils.Misc import list_set + routes_paths = self.routes(include_default=include_default, expand_mounts=expand_mounts) return list_set(list_index_by(routes_paths, 'http_path')) @@ -140,17 +141,23 @@ def setup_routes (self): return self # overwrite to add rules def setup_default_routes(self): + from osbot_fast_api.api.routes.Routes_Config import Routes_Config + if self.default_routes: self.setup_add_root_route() self.add_routes(Routes_Config) def setup_add_root_route(self): + from starlette.responses import RedirectResponse + def redirect_to_docs(): return RedirectResponse(url="/docs") self.app_router().get("/")(redirect_to_docs) def setup_static_routes(self): + from starlette.staticfiles import StaticFiles + path_static_folder = self.path_static_folder() if path_static_folder: path_static = "/static" @@ -158,6 +165,8 @@ def setup_static_routes(self): self.app().mount(path_static, StaticFiles(directory=path_static_folder), name=path_name) def setup_middleware__cors(self): # todo: double check that this is working see bug test + from starlette.middleware.cors import CORSMiddleware + if self.enable_cors: self.app().add_middleware(CORSMiddleware, allow_origins = ["*"] , @@ -167,14 +176,20 @@ def setup_middleware__cors(self): # todo: double check that this i expose_headers = ["Content-Type", "X-Requested-With", "Origin", "Accept", "Authorization"]) def setup_middleware__detect_disconnect(self): + from osbot_fast_api.api.middlewares.Middleware__Detect_Disconnect import Middleware__Detect_Disconnect + self.app().add_middleware(Middleware__Detect_Disconnect) def setup_middleware__http_events(self): + from osbot_fast_api.api.middlewares.Middleware__Http_Request import Middleware__Http_Request + self.app().add_middleware(Middleware__Http_Request , http_events=self.http_events) return self def user_middlewares(self): + import types + middlewares = [] data = self.app().user_middleware for item in data: @@ -192,6 +207,7 @@ def user_middlewares(self): return middlewares def version__fast_api_server(self): + from osbot_fast_api.utils.Version import Version return Version().value() # def run_in_lambda(self): diff --git a/osbot_fast_api/api/Fast_API_Routes.py b/osbot_fast_api/api/Fast_API_Routes.py index 46c3041..198b03e 100644 --- a/osbot_fast_api/api/Fast_API_Routes.py +++ b/osbot_fast_api/api/Fast_API_Routes.py @@ -1,11 +1,7 @@ from fastapi import APIRouter, FastAPI from osbot_utils.base_classes.Type_Safe import Type_Safe from osbot_utils.decorators.lists.index_by import index_by -from osbot_utils.utils.Misc import lower -from osbot_utils.utils.Str import str_safe -from osbot_fast_api.utils.Fast_API_Utils import Fast_API_Utils -#DEFAULT_ROUTES = ['/docs', '/docs/oauth2-redirect', '/openapi.json', '/redoc'] class Fast_API_Routes(Type_Safe): # refactor to Fast_API__Routes router : APIRouter @@ -14,6 +10,9 @@ class Fast_API_Routes(Type_Safe): # refactor to Fast_API__Routes tag : str def __init__(self, **kwargs): + from osbot_utils.utils.Str import str_safe + from osbot_utils.utils.Misc import lower + super().__init__(**kwargs) self.prefix = f'/{lower(str_safe(self.tag))}' @@ -35,6 +34,7 @@ def add_route_put(self, function): return self.add_route(function=function, methods=['PUT']) def fast_api_utils(self): + from osbot_fast_api.utils.Fast_API_Utils import Fast_API_Utils return Fast_API_Utils(self.app) @index_by diff --git a/osbot_fast_api/api/Fast_API__Http_Events.py b/osbot_fast_api/api/Fast_API__Http_Events.py index 82536f9..d3f9596 100644 --- a/osbot_fast_api/api/Fast_API__Http_Events.py +++ b/osbot_fast_api/api/Fast_API__Http_Events.py @@ -1,16 +1,17 @@ import types from collections import deque -from osbot_fast_api.api.Fast_API__Http_Event import Fast_API__Http_Event -from osbot_fast_api.api.Fast_API__Http_Event__Info import Fast_API__Http_Event__Info from osbot_utils.base_classes.Type_Safe import Type_Safe -from fastapi import Request -from starlette.responses import Response -from osbot_utils.helpers.trace.Trace_Call import Trace_Call from osbot_utils.helpers.trace.Trace_Call__Config import Trace_Call__Config -from osbot_utils.utils.Misc import str_md5 + HTTP_EVENTS__MAX_REQUESTS_LOGGED = 50 +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from fastapi import Request + from starlette.responses import Response + from osbot_fast_api.api.Fast_API__Http_Event import Fast_API__Http_Event + class Fast_API__Http_Events(Type_Safe): #log_requests : bool = False # todo: change this to save on S3 and disk background_tasks : list @@ -29,14 +30,14 @@ def __init__(self,**kwargs): super().__init__(**kwargs) self.trace_call_config.ignore_start_with = ['osbot_fast_api.api.Fast_API__Http_Events'] # so that we don't see traces from this - def on_http_request(self, request: Request): + def on_http_request(self, request: 'Request'): with self.request_data(request) as _: _.on_request(request) self.request_trace_start(request) if self.callback_on_request: self.callback_on_request(_) - def on_http_response(self, request: Request, response:Response): + def on_http_response(self, request: 'Request', response: 'Response'): with self.request_data(request) as _: _.on_response(response) # if StreamingResponse not in base_types(response): # handle the special case when the response is a StreamingResponse @@ -45,12 +46,14 @@ def on_http_response(self, request: Request, response:Response): if self.callback_on_response: self.callback_on_response(response, _) - def clean_request_data(self, request_data: Fast_API__Http_Event): + def clean_request_data(self, request_data: 'Fast_API__Http_Event'): if self.clean_data: self.clean_request_data_field(request_data.http_event_request , 'headers', 'cookie') self.clean_request_data_field(request_data.http_event_response, 'headers', 'cookie') def clean_request_data_field(self, request_data, variable_name, field_name): + from osbot_utils.utils.Misc import str_md5 + with request_data as _: variable_data = getattr(_, variable_name) if type(variable_data) is dict: @@ -68,6 +71,9 @@ def clean_request_data_field(self, request_data, variable_name, field_name): #print(f">>>>> on on_response_stream_end : {state}") def create_request_data(self, request): + from osbot_fast_api.api.Fast_API__Http_Event import Fast_API__Http_Event + from osbot_fast_api.api.Fast_API__Http_Event__Info import Fast_API__Http_Event__Info + kwargs = dict(fast_api_name = self.fast_api_name) http_event_info = Fast_API__Http_Event__Info(**kwargs) http_event = Fast_API__Http_Event(http_event_info=http_event_info) @@ -84,7 +90,7 @@ def create_request_data(self, request): return http_event - def request_data(self, request: Request): # todo: refactor all this request_data into a Request_Data class + def request_data(self, request: 'Request'): # todo: refactor all this request_data into a Request_Data class if not hasattr(request.state, "request_data"): request_data = self.create_request_data(request) else: @@ -100,13 +106,17 @@ def request_messages(self, request): return self.requests_data.get(event_id, {}).get('messages', []) def request_trace_start(self, request): + from osbot_utils.helpers.trace.Trace_Call import Trace_Call + if self.trace_calls: trace_call_config = self.trace_call_config trace_call = Trace_Call(config=trace_call_config) trace_call.start() request.state.trace_call = trace_call - def request_trace_stop(self, request: Request): # pragma: no cover + def request_trace_stop(self, request: 'Request'): + from osbot_utils.helpers.trace.Trace_Call import Trace_Call + # pragma: no cover if self.trace_calls: trace_call: Trace_Call = request.state.trace_call trace_call.stop() diff --git a/osbot_fast_api/api/middlewares/Middleware__Detect_Disconnect.py b/osbot_fast_api/api/middlewares/Middleware__Detect_Disconnect.py index 53cc989..4f220eb 100644 --- a/osbot_fast_api/api/middlewares/Middleware__Detect_Disconnect.py +++ b/osbot_fast_api/api/middlewares/Middleware__Detect_Disconnect.py @@ -1,10 +1,12 @@ -from starlette.types import ASGIApp, Receive, Scope, Send +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from starlette.types import ASGIApp, Receive, Scope, Send class Middleware__Detect_Disconnect: - def __init__(self, app: ASGIApp): + def __init__(self, app: 'ASGIApp'): self.app = app - async def __call__(self, scope: Scope, receive: Receive, send: Send): + async def __call__(self, scope: 'Scope', receive: 'Receive', send: 'Send'): async def disconnect_monitor_receive(): message = await receive() if message["type"] == "http.disconnect": diff --git a/osbot_fast_api/api/middlewares/Middleware__Http_Request.py b/osbot_fast_api/api/middlewares/Middleware__Http_Request.py index 4826945..2df7570 100644 --- a/osbot_fast_api/api/middlewares/Middleware__Http_Request.py +++ b/osbot_fast_api/api/middlewares/Middleware__Http_Request.py @@ -1,8 +1,10 @@ -from fastapi import Request, BackgroundTasks from starlette.middleware.base import BaseHTTPMiddleware -from starlette.responses import Response from osbot_fast_api.api.Fast_API__Http_Events import Fast_API__Http_Events +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from fastapi import Request + from starlette.responses import Response class Middleware__Http_Request(BaseHTTPMiddleware): @@ -10,7 +12,7 @@ def __init__(self, app, http_events: Fast_API__Http_Events): super().__init__(app) self.http_events = http_events - async def dispatch(self, request: Request, call_next) -> Response: + async def dispatch(self, request: 'Request', call_next) -> 'Response': self.http_events.on_http_request(request) response = None @@ -23,6 +25,8 @@ async def dispatch(self, request: Request, call_next) -> Response: # todo: figure if this should be here or on the http_events.on_http_response def add_background_tasks_to_live_response(self, request, response): + from fastapi import BackgroundTasks + background_tasks = BackgroundTasks() for background_task in self.http_events.background_tasks: background_tasks.add_task(background_task, request=request, response=response) diff --git a/osbot_fast_api/utils/http_shell/Http_Shell__Server.py b/osbot_fast_api/utils/http_shell/Http_Shell__Server.py index 32d9dfb..ccbd3b2 100644 --- a/osbot_fast_api/utils/http_shell/Http_Shell__Server.py +++ b/osbot_fast_api/utils/http_shell/Http_Shell__Server.py @@ -1,5 +1,4 @@ import os - from osbot_utils.utils.Env import load_dotenv from osbot_utils.utils.Misc import is_guid from osbot_utils.utils.Process import Process