1- from typing import Union
2- from unittest import TestCase
3- from osbot_fast_api .client .Fast_API__Route__Extractor import Fast_API__Route__Extractor
4- from osbot_utils .type_safe .Type_Safe import Type_Safe
5- from osbot_fast_api .api .Fast_API import Fast_API
1+ from typing import Union
2+ from unittest import TestCase
3+ from osbot_fast_api .client .Fast_API__Route__Extractor import Fast_API__Route__Extractor
4+ from osbot_utils .type_safe .Type_Safe import Type_Safe
5+ from osbot_fast_api .api .Fast_API import Fast_API
6+ from osbot_fast_api .api .routes .Fast_API__Routes import Fast_API__Routes
7+ from osbot_fast_api .api .schemas .Schema__Fast_API__Config import Schema__Fast_API__Config
8+ from osbot_fast_api .api .transformers .Type_Safe__To__BaseModel import Type_Safe__To__BaseModel
9+ from osbot_utils .type_safe .primitives .core .Safe_Str import Safe_Str
610
711
812class test_Fast_API__Routes__regression (TestCase ):
@@ -64,4 +68,67 @@ def concrete_return_type() -> Schema__Response:
6468 client = fast_api .client () # Verify the route works
6569 response = client .get ('/concrete-return-type' )
6670 assert response .status_code == 200
67- assert response .json () == {"message" : "test" }
71+ assert response .json () == {"message" : "test" }
72+
73+ def test__regression__fast_api__response__base_model__not_handing__none_values__in_type_safe_primitives (self ):
74+ from osbot_fast_api .api .Fast_API import Fast_API
75+
76+ class An_Response_Class (Type_Safe ):
77+ an_str : Safe_Str = None
78+
79+ class Routes__ABC (Fast_API__Routes ):
80+ def an_post__fails (self ) -> An_Response_Class :
81+ return An_Response_Class ()
82+
83+ def an_post__ok_1 (self ) -> An_Response_Class :
84+ return An_Response_Class (an_str = '' )
85+
86+ def an_post__ok_2 (self ) -> An_Response_Class :
87+ return An_Response_Class (an_str = 'ok' )
88+
89+ def setup_routes (self ):
90+ self .add_routes_post (self .an_post__fails ,
91+ self .an_post__ok_1 ,
92+ self .an_post__ok_2 )
93+
94+ config = Schema__Fast_API__Config (default_routes = False )
95+ class Fast_API__Abc (Fast_API ):
96+ def setup_routes (self ):
97+ self .add_routes (Routes__ABC )
98+ return self
99+
100+ fast_api_abc = Fast_API__Abc (config = config ).setup ()
101+ assert fast_api_abc .routes_paths () == ['/an-post/fails' ,
102+ '/an-post/ok-1' ,
103+ '/an-post/ok-2' ]
104+
105+ with fast_api_abc .client () as _ :
106+ # error_message = "1 validation error for An_Response_Class__BaseModel\nan_str\n Input should be a valid string [type=string_type, input_value=None, input_type=NoneType]\n For further information visit https://errors.pydantic.dev/2.12/v/string_type"
107+ # with pytest.raises(ValueError, match=re.escape(error_message)):
108+ # _.post(url='/an-post/fails') # BUG: should have worked
109+
110+ assert _ .post (url = '/an-post/fails' ).json () == {'an_str' : None }
111+
112+ assert _ .post (url = '/an-post/ok-1' ).json () == {'an_str' : '' }
113+ assert _ .post (url = '/an-post/ok-2' ).json () == {'an_str' : 'ok' }
114+
115+ def test__regression__type_safe_to_basemodel__converter__handle__none_return_values__no_optional (self ):
116+
117+ class An_Class (Type_Safe ):
118+ #an_str : Safe_Str = None
119+ an_str : str = None # when we make this optional , it fails
120+
121+
122+ # error_message = ("1 validation error for An_Class__BaseModel\nan_str\n "
123+ # "Input should be a valid string [type=string_type, input_value=None, input_type=NoneType]\n "
124+ # "For further information visit https://errors.pydantic.dev/2.12/v/string_type")
125+ # with pytest.raises(ValueError, match=re.escape(error_message)):
126+ # result = Type_Safe__To__BaseModel().convert_instance(An_Class()) # BUG
127+
128+ result = Type_Safe__To__BaseModel ().convert_instance (An_Class ()) # FIXED
129+ assert result .model_json_schema () == {'properties' : {'an_str' : {'anyOf' : [{'type' : 'string' },
130+ {'type' : 'null' }],
131+ 'default' : None ,
132+ 'title' : 'An Str' }},
133+ 'title' : 'An_Class__BaseModel' ,
134+ 'type' : 'object' }
0 commit comments