Skip to content

Commit 8430744

Browse files
committed
fixed nasty bug in the Fast_API openapi.json creation, which was not including the return Type_Safe class in it's definition (the fix was to add the method create_passthrough_wrapper to the Type_Safe__Route__Wrapper class
added large number of tests to the test_Type_Safe__Route__Wrapper that check for the new behaviour and check for any possible FastAPI and Pydantic side effects updated to latest version of OSBot_Utils, which had a new location of the __ class
1 parent af50c1c commit 8430744

12 files changed

+597
-45
lines changed

_to_refactor_to_separate_project/code/cli/Fast_API__CLI.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from osbot_fast_api.api.Fast_API import Fast_API
88
from osbot_fast_api.utils.Fast_API_Server import Fast_API_Server
99
from osbot_utils.type_safe.Type_Safe import Type_Safe
10-
from osbot_utils.utils.Objects import obj_data
1110

1211

1312
class Fast_API__CLI(Type_Safe):

osbot_fast_api/api/routes/type_safe/Type_Safe__Route__Wrapper.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import functools
22
import inspect
3-
from typing import Callable
3+
from typing import Callable, get_type_hints
44
from fastapi import HTTPException
55
from fastapi.exceptions import RequestValidationError
66
from osbot_utils.type_safe.Type_Safe import Type_Safe
@@ -18,7 +18,9 @@ def create_wrapper(self, function : Callable , # Origin
1818
) -> Callable: # Returns wrapper function
1919

2020
if not signature.primitive_conversions and not signature.type_safe_conversions and not signature.return_needs_conversion:
21-
return function # No conversion needed - return original
21+
if signature.return_type is not None: # Even if no conversions needed, preserve return type for OpenAPI
22+
return self.create_passthrough_wrapper(function, signature) # Create minimal wrapper that preserves return type annotation
23+
return function # No return type - return original
2224

2325
if signature.has_body_params: # Different wrappers for different scenarios
2426
wrapper_function = self.create_body_wrapper(function, signature)
@@ -39,6 +41,33 @@ def create_wrapper(self, function : Callable , # Origin
3941

4042
return wrapper_function
4143

44+
@type_safe
45+
def create_passthrough_wrapper(self, function : Callable , # Function to wrap
46+
signature : Schema__Route__Signature # Signature info
47+
) -> Callable: # Returns minimal wrapper that preserves annotations
48+
49+
@functools.wraps(function)
50+
def wrapper(*args, **kwargs):
51+
return function(*args, **kwargs) # Simply pass through to the original function
52+
53+
wrapper.__signature__ = inspect.signature(function) # Preserve the original signature
54+
55+
try: # Build annotations dict including the return type
56+
type_hints = get_type_hints(function)
57+
wrapper.__annotations__ = type_hints.copy()
58+
except:
59+
wrapper.__annotations__ = getattr(function, '__annotations__', {}).copy() # Fallback to __annotations__ if get_type_hints fails
60+
61+
if signature.return_type is not None and 'return' not in wrapper.__annotations__: # Ensure return type is set
62+
wrapper.__annotations__['return'] = signature.return_type
63+
64+
wrapper.__original_return_type__ = signature.return_type # Preserve original return type metadata
65+
66+
if hasattr(function, '__route_path__'): # Preserve route_path decorator if it exists
67+
wrapper.__route_path__ = function.__route_path__
68+
69+
return wrapper
70+
4271
@type_safe
4372
def create_body_wrapper(self, function : Callable , # Function to wrap
4473
signature : Schema__Route__Signature # Signature info

osbot_fast_api/utils/Fast_API_Server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
from urllib.parse import urljoin
44
from threading import Thread
55
from fastapi import FastAPI
6+
from osbot_utils.utils.Objects import base_types
67
from osbot_utils.type_safe.Type_Safe import Type_Safe
78
from osbot_utils.testing.Stderr import Stderr
89
from osbot_utils.testing.Stdout import Stdout
910
from osbot_utils.utils.Http import wait_for_port, wait_for_port_closed, is_port_open, url_join_safe
10-
from osbot_utils.utils.Objects import base_types
1111
from uvicorn import Config, Server
1212
from osbot_utils.utils.Misc import random_port
1313

tests/unit/api/routes/test_Fast_API__Routes.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from unittest import TestCase
22
from fastapi import FastAPI, APIRouter
3-
from osbot_utils.utils.Objects import __
3+
from osbot_utils.testing.__ import __
4+
#from osbot_utils.testing.__ import __
45
from osbot_fast_api.api.routes.Fast_API__Routes import Fast_API__Routes
56
from osbot_fast_api.api.routes.type_safe.Type_Safe__Route__Registration import Type_Safe__Route__Registration
67
from osbot_fast_api.api.schemas.safe_str.Safe_Str__Fast_API__Route__Prefix import Safe_Str__Fast_API__Route__Prefix

tests/unit/api/routes/test_Fast_API__Routes__with_Type_Safe.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
from unittest import TestCase
2-
from dataclasses import dataclass
3-
from typing import Optional, List
4-
5-
from osbot_fast_api.api.schemas.Schema__Fast_API__Config import Schema__Fast_API__Config
6-
from osbot_utils.type_safe.Type_Safe import Type_Safe
7-
from osbot_utils.type_safe.primitives.domains.files.safe_str.Safe_Str__File__Path import Safe_Str__File__Path
8-
from osbot_utils.utils.Objects import __
9-
from pydantic import BaseModel
10-
from osbot_fast_api.api.routes.Fast_API__Routes import Fast_API__Routes
11-
from osbot_fast_api.api.Fast_API import Fast_API
1+
from unittest import TestCase
2+
from dataclasses import dataclass
3+
from typing import Optional, List
4+
from osbot_fast_api.api.schemas.Schema__Fast_API__Config import Schema__Fast_API__Config
5+
from osbot_utils.type_safe.Type_Safe import Type_Safe
6+
from osbot_utils.type_safe.primitives.domains.files.safe_str.Safe_Str__File__Path import Safe_Str__File__Path
7+
from osbot_utils.testing.__ import __
8+
from pydantic import BaseModel
9+
from osbot_fast_api.api.routes.Fast_API__Routes import Fast_API__Routes
10+
from osbot_fast_api.api.Fast_API import Fast_API
1211

1312

1413
class test_Fast_API__Routes__with_Type_Safe(TestCase):

tests/unit/api/routes/type_safe/test_Type_Safe__Route__Converter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from osbot_fast_api.api.schemas.routes.Schema__Route__Signature import Schema__Route__Signature
33
from osbot_utils.type_safe.primitives.domains.web.safe_str.Safe_Str__Email import Safe_Str__Email
44
from osbot_utils.type_safe.primitives.domains.identifiers.safe_str.Safe_Str__Display_Name import Safe_Str__Display_Name
5-
from osbot_utils.utils.Objects import __
5+
from osbot_utils.testing.__ import __
66
from osbot_utils.type_safe.Type_Safe import Type_Safe
77
from osbot_utils.type_safe.primitives.core.Safe_Str import Safe_Str
88
from osbot_utils.type_safe.primitives.core.Safe_Int import Safe_Int

0 commit comments

Comments
 (0)