Skip to content

Commit 6c99161

Browse files
Merge pull request #23 from MarcoMuellner/14-no-way-to-set-the-base-url
:feat: Added possibility to pass custom APIConfig object to the clients
2 parents dc8e1ae + 911fe3f commit 6c99161

File tree

7 files changed

+87
-59
lines changed

7 files changed

+87
-59
lines changed

docs/tutorial/index.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -788,12 +788,12 @@ only sync (for __requests__) or only async (for __aiohttp__) services.
788788
``` py
789789
...
790790
async def async_root__get() -> RootResponse:
791-
base_path = APIConfig.base_path
791+
base_path = APIConfig().base_path
792792
path = f"/"
793793
headers = {
794794
"Content-Type": "application/json",
795795
"Accept": "application/json",
796-
"Authorization": f"Bearer { APIConfig.get_access_token() }",
796+
"Authorization": f"Bearer { APIConfig().get_access_token() }",
797797
}
798798
query_params = {}
799799

@@ -815,12 +815,12 @@ only sync (for __requests__) or only async (for __aiohttp__) services.
815815
``` py
816816
...
817817
def root__get() -> RootResponse:
818-
base_path = APIConfig.base_path
818+
base_path = APIConfig().base_path
819819
path = f"/"
820820
headers = {
821821
"Content-Type": "application/json",
822822
"Accept": "application/json",
823-
"Authorization": f"Bearer { APIConfig.get_access_token() }",
823+
"Authorization": f"Bearer { APIConfig().get_access_token() }",
824824
}
825825
query_params = {}
826826

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "openapi-python-generator"
3-
version = "0.4.1"
3+
version = "0.4.2"
44
description = "Openapi Python Generator"
55
authors = ["Marco Müllner <[email protected]>"]
66
license = "MIT"

src/openapi_python_generator/language_converters/python/templates/aiohttp.jinja2

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
async def {{ operation_id }}({{ params }}) -> {% if return_type.type is none or return_type.type.converted_type is none %}None{% else %}{{ return_type.type.converted_type}}{% endif %}:
2-
base_path = APIConfig.base_path
1+
async def {{ operation_id }}({{ params }} api_config_override : Optional[APIConfig] = None) -> {% if return_type.type is none or return_type.type.converted_type is none %}None{% else %}{{ return_type.type.converted_type}}{% endif %}:
2+
api_config = api_config_override if api_config_override else APIConfig()
3+
4+
base_path = api_config.base_path
35
path = f'{{ path_name }}'
46
headers = {
57
'Content-Type': 'application/json',
68
'Accept': 'application/json',
7-
'Authorization': f'Bearer { APIConfig.get_access_token() }',
9+
'Authorization': f'Bearer { api_config.get_access_token() }',
810
{{ header_params | join(',\n') | safe }}
911
}
1012

src/openapi_python_generator/language_converters/python/templates/apiconfig.jinja2

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,31 @@
11
{% if env_token_name is not none %}import os{% endif %}
22

3+
from pydantic import BaseModel, Field
34
from typing import Optional, Union
45

5-
class APIConfig():
6+
class APIConfig(BaseModel):
67
base_path: str = {% if servers|length > 0 %} '{{ servers[0].url }}' {% else %} 'NO SERVER' {% endif %}
78

89
verify: Union[bool, str] = True
910
{% if env_token_name is none %}
10-
_access_token : Optional[str] = None
11+
access_token : Optional[str] = None
1112
{% endif %}
1213

13-
@staticmethod
14-
def get_access_token() -> Optional[str]:
14+
def get_access_token(self) -> Optional[str]:
1515
{% if env_token_name is not none %}
1616
try:
1717
return os.environ['{{ env_token_name }}']
1818
except KeyError:
1919
return None
2020
{% else %}
21-
return APIConfig._access_token
21+
return self.access_token
2222
{% endif %}
2323

24-
@staticmethod
25-
def set_access_token(value : str):
24+
def set_access_token(self, value : str):
2625
{% if env_token_name is not none %}
2726
raise Exception("This client was generated with an environment variable for the access token. Please set the environment variable '{{ env_token_name }}' to the access token.")
2827
{% else %}
29-
APIConfig._access_token = value
28+
self.access_token = value
3029
{% endif %}
3130

3231
class HTTPException(Exception):

src/openapi_python_generator/language_converters/python/templates/httpx.jinja2

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
{% if async_client %}async {% endif %}def {{ operation_id }}({{ params }}) -> {% if return_type.type is none or return_type.type.converted_type is none %}None{% else %}{{ return_type.type.converted_type}}{% endif %}:
2-
base_path = APIConfig.base_path
1+
{% if async_client %}async {% endif %}def {{ operation_id }}({{ params }} api_config_override : Optional[APIConfig] = None) -> {% if return_type.type is none or return_type.type.converted_type is none %}None{% else %}{{ return_type.type.converted_type}}{% endif %}:
2+
api_config = api_config_override if api_config_override else APIConfig()
3+
4+
base_path = api_config.base_path
35
path = f'{{ path_name }}'
46
headers = {
57
'Content-Type': 'application/json',
68
'Accept': 'application/json',
7-
'Authorization': f'Bearer { APIConfig.get_access_token() }',
9+
'Authorization': f'Bearer { api_config.get_access_token() }',
810
{{ header_params | join(',\n') | safe }}
911
}
1012
query_params : Dict[str,Any] = {
@@ -19,7 +21,7 @@
1921
async with httpx.AsyncClient(base_url=base_path, verify=APIConfig.verify) as client:
2022
response = await client.request(
2123
{% else %}
22-
with httpx.Client(base_url=base_path, verify=APIConfig.verify) as client:
24+
with httpx.Client(base_url=base_path, verify=api_config.verify) as client:
2325
response = client.request(
2426
{% endif %}
2527
'{{ method }}',

src/openapi_python_generator/language_converters/python/templates/requests.jinja2

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
def {{ operation_id }}({{ params }}) -> {% if return_type.type is none or return_type.type.converted_type is none %}None{% else %}{{ return_type.type.converted_type}}{% endif %}:
2-
base_path = APIConfig.base_path
1+
def {{ operation_id }}({{ params }} api_config_override : Optional[APIConfig] = None) -> {% if return_type.type is none or return_type.type.converted_type is none %}None{% else %}{{ return_type.type.converted_type}}{% endif %}:
2+
api_config = api_config_override if api_config_override else APIConfig()
3+
4+
base_path = api_config.base_path
35
path = f'{{ path_name }}'
46
headers = {
57
'Content-Type': 'application/json',
68
'Accept': 'application/json',
7-
'Authorization': f'Bearer { APIConfig.get_access_token() }',
9+
'Authorization': f'Bearer { api_config.get_access_token() }',
810
{{ header_params | join(',\n') | safe }}
911
}
1012
query_params : Dict[str,Any] = {
@@ -20,7 +22,7 @@ def {{ operation_id }}({{ params }}) -> {% if return_type.type is none or return
2022
f'{base_path}{path}',
2123
headers=headers,
2224
params=query_params,
23-
verify=APIConfig.verify,
25+
verify=api_config.verify,
2426
{% if body_param %}
2527
{% if use_orjson %}
2628
content=orjson.dumps({{ body_param }})

tests/test_generated_code.py

+58-35
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def test_get_auth_token_without_env(model_data_with_cleanup):
2323
_locals = locals()
2424

2525
exec(
26-
"from .test_result import *\nassert APIConfig.get_access_token() is None",
26+
"from .test_result import *\nassert APIConfig().get_access_token() is None",
2727
globals(),
2828
_locals,
2929
)
@@ -34,9 +34,10 @@ def test_set_auth_token():
3434

3535
_locals = locals()
3636
program = """from .test_result import APIConfig
37-
assert APIConfig.get_access_token() is None
38-
APIConfig.set_access_token('foo_bar')
39-
assert APIConfig.get_access_token() == 'foo_bar'
37+
api_config = APIConfig()
38+
assert api_config.get_access_token() is None
39+
api_config.set_access_token('foo_bar')
40+
assert api_config.get_access_token() == 'foo_bar'
4041
"""
4142
exec(
4243
program,
@@ -46,29 +47,40 @@ def test_set_auth_token():
4647

4748

4849
@pytest.mark.parametrize(
49-
"library, use_orjson",
50+
"library, use_orjson, custom_ip",
5051
[
51-
(HTTPLibrary.httpx, False),
52-
(HTTPLibrary.requests, False),
53-
(HTTPLibrary.httpx, True),
54-
(HTTPLibrary.requests, True),
55-
(HTTPLibrary.aiohttp, True),
56-
(HTTPLibrary.aiohttp, False),
52+
(HTTPLibrary.httpx, False, None),
53+
(HTTPLibrary.requests, False, None),
54+
(HTTPLibrary.httpx, True, None),
55+
(HTTPLibrary.requests, True, None),
56+
(HTTPLibrary.aiohttp, True, None),
57+
(HTTPLibrary.aiohttp, False, None),
58+
(HTTPLibrary.httpx, False, "http://localhost:5000"),
59+
(HTTPLibrary.requests, False, "http://localhost:5000"),
60+
(HTTPLibrary.httpx, True, "http://localhost:5000"),
61+
(HTTPLibrary.requests, True, "http://localhost:5000"),
62+
(HTTPLibrary.aiohttp, True, "http://localhost:5000"),
63+
(HTTPLibrary.aiohttp, False, "http://localhost:5000"),
5764
],
5865
)
5966
@respx.mock
60-
def test_generate_code(model_data_with_cleanup, library, use_orjson):
67+
def test_generate_code(model_data_with_cleanup, library, use_orjson, custom_ip):
6168
generate_data(test_data_path, test_result_path, library, use_orjson=use_orjson)
6269
result = generator(model_data_with_cleanup, library_config_dict[library])
6370

71+
if custom_ip is not None:
72+
api_config_custom = result.api_config
73+
api_config_custom.base_url = custom_ip
74+
else:
75+
api_config_custom = result.api_config
76+
6477
# Testing root access
65-
_locals = locals()
66-
root_route = respx.get(f"{result.api_config.base_url}/").mock(
78+
root_route = respx.get(f"{api_config_custom.base_url}/").mock(
6779
return_value=Response(
6880
status_code=200, content=json.dumps({"message": "Hello World"})
6981
)
7082
)
71-
get_users_route = respx.get(f"{result.api_config.base_url}/users").mock(
83+
get_users_route = respx.get(f"{api_config_custom.base_url}/users").mock(
7284
return_value=Response(
7385
status_code=200,
7486
content=json.dumps(
@@ -93,7 +105,7 @@ def test_generate_code(model_data_with_cleanup, library, use_orjson):
93105
),
94106
)
95107
)
96-
get_user_route = respx.get(f"{result.api_config.base_url}/users/{1}").mock(
108+
get_user_route = respx.get(f"{api_config_custom.base_url}/users/{1}").mock(
97109
return_value=Response(
98110
status_code=200,
99111
content=json.dumps(
@@ -108,7 +120,7 @@ def test_generate_code(model_data_with_cleanup, library, use_orjson):
108120
),
109121
)
110122
)
111-
post_user_route = respx.post(f"{result.api_config.base_url}/users").mock(
123+
post_user_route = respx.post(f"{api_config_custom.base_url}/users").mock(
112124
return_value=Response(
113125
status_code=201,
114126
content=json.dumps(
@@ -123,7 +135,7 @@ def test_generate_code(model_data_with_cleanup, library, use_orjson):
123135
),
124136
)
125137
)
126-
update_user_route = respx.patch(f"{result.api_config.base_url}/users/{1}").mock(
138+
update_user_route = respx.patch(f"{api_config_custom.base_url}/users/{1}").mock(
127139
return_value=Response(
128140
status_code=200,
129141
content=json.dumps(
@@ -137,11 +149,11 @@ def test_generate_code(model_data_with_cleanup, library, use_orjson):
137149
),
138150
)
139151
)
140-
delete_user_route = respx.delete(f"{result.api_config.base_url}/users/{1}").mock(
152+
delete_user_route = respx.delete(f"{api_config_custom.base_url}/users/{1}").mock(
141153
return_value=Response(status_code=204, content=json.dumps(None))
142154
)
143155

144-
get_teams_route = respx.get(f"{result.api_config.base_url}/teams").mock(
156+
get_teams_route = respx.get(f"{api_config_custom.base_url}/teams").mock(
145157
return_value=Response(
146158
status_code=200,
147159
content=orjson.dumps(
@@ -167,7 +179,7 @@ def test_generate_code(model_data_with_cleanup, library, use_orjson):
167179
)
168180
)
169181

170-
get_team_route = respx.get(f"{result.api_config.base_url}/teams/{1}").mock(
182+
get_team_route = respx.get(f"{api_config_custom.base_url}/teams/{1}").mock(
171183
return_value=Response(
172184
status_code=200,
173185
content=orjson.dumps(
@@ -182,7 +194,7 @@ def test_generate_code(model_data_with_cleanup, library, use_orjson):
182194
),
183195
)
184196
)
185-
post_team_route = respx.post(f"{result.api_config.base_url}/teams").mock(
197+
post_team_route = respx.post(f"{api_config_custom.base_url}/teams").mock(
186198
return_value=Response(
187199
status_code=201,
188200
content=orjson.dumps(
@@ -198,7 +210,7 @@ def test_generate_code(model_data_with_cleanup, library, use_orjson):
198210
)
199211
)
200212

201-
update_team_route = respx.patch(f"{result.api_config.base_url}/teams/{1}").mock(
213+
update_team_route = respx.patch(f"{api_config_custom.base_url}/teams/{1}").mock(
202214
return_value=Response(
203215
status_code=200,
204216
content=orjson.dumps(
@@ -214,15 +226,26 @@ def test_generate_code(model_data_with_cleanup, library, use_orjson):
214226
)
215227
)
216228

217-
delete_team_route = respx.delete(f"{result.api_config.base_url}/teams/{1}").mock(
229+
delete_team_route = respx.delete(f"{api_config_custom.base_url}/teams/{1}").mock(
218230
return_value=Response(status_code=204, content=json.dumps(None))
219231
)
220232

221-
exec_code_base = f"""from .test_result.services.general_service import *\nresp_result = root__get()\nassert isinstance(resp_result, RootResponse)"""
233+
passed_api_config = None
234+
235+
236+
237+
if custom_ip:
238+
from .test_result.api_config import APIConfig
239+
passed_api_config = APIConfig()
240+
passed_api_config.base_path = custom_ip
241+
242+
_locals = locals()
243+
244+
exec_code_base = f"""from .test_result.services.general_service import *\nresp_result = root__get(passed_api_config)\nassert isinstance(resp_result, RootResponse)"""
222245
exec(exec_code_base, globals(), _locals)
223246
assert root_route.called
224247

225-
exec_code_base = f"try:\n\tfrom .test_result import *\n\tresp_result = get_users_users_get()\nexcept Exception as e:\n\tprint(e)\n\traise e"
248+
exec_code_base = f"try:\n\tfrom .test_result import *\n\tresp_result = get_users_users_get(passed_api_config)\nexcept Exception as e:\n\tprint(e)\n\traise e"
226249

227250
try:
228251
exec(exec_code_base, globals(), _locals)
@@ -250,7 +273,7 @@ def test_generate_code(model_data_with_cleanup, library, use_orjson):
250273
exec(exec_code_base, globals(), _locals)
251274
assert get_users_route.called
252275

253-
exec_code_base = f"from .test_result.services.general_service import *\nresp_result = get_user_users__user_id__get(1,'test')"
276+
exec_code_base = f"from .test_result.services.general_service import *\nresp_result = get_user_users__user_id__get(1,'test',passed_api_config)"
254277

255278
exec(exec_code_base, globals(), _locals)
256279

@@ -266,7 +289,7 @@ def test_generate_code(model_data_with_cleanup, library, use_orjson):
266289
id=1, username="user1", email="[email protected]", password="123456", is_active=True
267290
)
268291

269-
exec_code_base = f"from .test_result.services.general_service import *\nresp_result = create_user_users_post(User(**{data}))"
292+
exec_code_base = f"from .test_result.services.general_service import *\nresp_result = create_user_users_post(User(**{data}),passed_api_config)"
270293

271294
exec(exec_code_base, globals(), _locals)
272295

@@ -277,7 +300,7 @@ def test_generate_code(model_data_with_cleanup, library, use_orjson):
277300
)
278301
assert post_user_route.called
279302

280-
exec_code_base = f"from .test_result.services.general_service import *\nresp_result = update_user_users__user_id__patch(1, User(**{data}))"
303+
exec_code_base = f"from .test_result.services.general_service import *\nresp_result = update_user_users__user_id__patch(1, User(**{data}), passed_api_config)"
281304

282305
exec(exec_code_base, globals(), _locals)
283306

@@ -288,13 +311,13 @@ def test_generate_code(model_data_with_cleanup, library, use_orjson):
288311
)
289312
assert update_user_route.called
290313

291-
exec_code_base = f"from .test_result.services.general_service import *\nresp_result = delete_user_users__user_id__delete(1)"
314+
exec_code_base = f"from .test_result.services.general_service import *\nresp_result = delete_user_users__user_id__delete(1, passed_api_config)"
292315

293316
exec(exec_code_base, globals(), _locals)
294317

295318
assert delete_user_route.called
296319

297-
exec_code_base = f"from .test_result.services.general_service import *\nresp_result = get_teams_teams_get()"
320+
exec_code_base = f"from .test_result.services.general_service import *\nresp_result = get_teams_teams_get(passed_api_config)"
298321

299322
exec(exec_code_base, globals(), _locals)
300323

@@ -315,7 +338,7 @@ def test_generate_code(model_data_with_cleanup, library, use_orjson):
315338
)
316339
assert get_teams_route.called
317340

318-
exec_code_base = f"from .test_result.services.general_service import *\nresp_result = get_team_teams__team_id__get(1)"
341+
exec_code_base = f"from .test_result.services.general_service import *\nresp_result = get_team_teams__team_id__get(1, passed_api_config)"
319342

320343
exec(exec_code_base, globals(), _locals)
321344
assert get_team_route.called
@@ -329,16 +352,16 @@ def test_generate_code(model_data_with_cleanup, library, use_orjson):
329352
updated_at="",
330353
)
331354

332-
exec_code_base = f"from .test_result.services.general_service import *\nfrom datetime import datetime\nresp_result = create_team_teams_post(Team(**{data}))"
355+
exec_code_base = f"from .test_result.services.general_service import *\nfrom datetime import datetime\nresp_result = create_team_teams_post(Team(**{data}), passed_api_config)"
333356

334357
exec(exec_code_base, globals(), _locals)
335358
assert post_team_route.called
336359

337-
exec_code_base = f"from .test_result.services.general_service import *\nfrom datetime import datetime\nresp_result = update_team_teams__team_id__patch(1, Team(**{data}))"
360+
exec_code_base = f"from .test_result.services.general_service import *\nfrom datetime import datetime\nresp_result = update_team_teams__team_id__patch(1, Team(**{data}), passed_api_config)"
338361

339362
exec(exec_code_base, globals(), _locals)
340363
assert update_team_route.called
341364

342-
exec_code_base = f"from .test_result.services.general_service import *\nresp_result = delete_team_teams__team_id__delete(1)"
365+
exec_code_base = f"from .test_result.services.general_service import *\nresp_result = delete_team_teams__team_id__delete(1, passed_api_config)"
343366

344367
exec(exec_code_base, globals(), _locals)

0 commit comments

Comments
 (0)