ab-openapi-python-generator 2.2.1__tar.gz → 2.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/PKG-INFO +1 -1
  2. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/tutorial/index.md +4 -4
  3. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/pyproject.toml +1 -1
  4. ab_openapi_python_generator-2.2.3/src/ab_openapi_python_generator/language_converters/python/templates/async_client_httpx_pydantic_2.jinja2 +146 -0
  5. ab_openapi_python_generator-2.2.3/src/ab_openapi_python_generator/language_converters/python/templates/sync_client_httpx_pydantic_2.jinja2 +145 -0
  6. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/models.py +0 -15
  7. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_generated_code.py +3 -3
  8. ab_openapi_python_generator-2.2.1/src/ab_openapi_python_generator/language_converters/python/templates/async_client_httpx_pydantic_2.jinja2 +0 -80
  9. ab_openapi_python_generator-2.2.1/src/ab_openapi_python_generator/language_converters/python/templates/sync_client_httpx_pydantic_2.jinja2 +0 -80
  10. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.envrc.example +0 -0
  11. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.gitattributes +0 -0
  12. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.github/dependabot.yml +0 -0
  13. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.github/workflows/ci.yaml +0 -0
  14. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.github/workflows/publish.yaml +0 -0
  15. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.gitignore +0 -0
  16. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.pre-commit-config.yaml +0 -0
  17. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.vscode/launch.json +0 -0
  18. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.vscode/tasks.json +0 -0
  19. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/LICENSE +0 -0
  20. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/Makefile +0 -0
  21. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/README.md +0 -0
  22. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/acknowledgements/index.md +0 -0
  23. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/css/custom.css +0 -0
  24. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/css/termynal.css +0 -0
  25. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/index.md +0 -0
  26. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/js/custom.js +0 -0
  27. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/js/termynal.js +0 -0
  28. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/openapi-definition.md +0 -0
  29. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/quick_start.md +0 -0
  30. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/references/index.md +0 -0
  31. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/references/module_usage.md +0 -0
  32. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/tutorial/advanced.md +0 -0
  33. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/tutorial/authentication.md +0 -0
  34. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/logo.png +0 -0
  35. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/__init__.py +0 -0
  36. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/__main__.py +0 -0
  37. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/common.py +0 -0
  38. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/generate_data.py +0 -0
  39. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/language_converters/__init__.py +0 -0
  40. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/language_converters/python/__init__.py +0 -0
  41. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/language_converters/python/client_generator.py +0 -0
  42. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/language_converters/python/common.py +0 -0
  43. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/language_converters/python/exception_generator.py +0 -0
  44. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/language_converters/python/generator.py +0 -0
  45. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/language_converters/python/jinja_config.py +0 -0
  46. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/language_converters/python/model_generator.py +0 -0
  47. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/language_converters/python/templates/alias_union.jinja2 +0 -0
  48. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/language_converters/python/templates/discriminator_enum.jinja2 +0 -0
  49. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/language_converters/python/templates/enum.jinja2 +0 -0
  50. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/language_converters/python/templates/http_exception.jinja2 +0 -0
  51. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/language_converters/python/templates/models.jinja2 +0 -0
  52. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/language_converters/python/templates/models_pydantic_2.jinja2 +0 -0
  53. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/parsers/__init__.py +0 -0
  54. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/parsers/openapi_30.py +0 -0
  55. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/parsers/openapi_31.py +0 -0
  56. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/py.typed +0 -0
  57. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/version_detector.py +0 -0
  58. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/__init__.py +0 -0
  59. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/build_test_api/api.py +0 -0
  60. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/conftest.py +0 -0
  61. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_common_normalize_symbol.py +0 -0
  62. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/failing_api.json +0 -0
  63. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/gitea_issue_11.json +0 -0
  64. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_117.json +0 -0
  65. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_120.json +0 -0
  66. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_17.json +0 -0
  67. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_30_87.json +0 -0
  68. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_51.json +0 -0
  69. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_55.json +0 -0
  70. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_71.json +0 -0
  71. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_71_31.json +0 -0
  72. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_illegal_character_in_operation_id.json +0 -0
  73. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_keyword_parameter_name.json +0 -0
  74. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/openapi_gitea_converted.json +0 -0
  75. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/swagger_petstore_3_0_4.yaml +0 -0
  76. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/swagger_petstore_3_1.yaml +0 -0
  77. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/test_api.json +0 -0
  78. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/test_api_31.json +0 -0
  79. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_generate_data.py +0 -0
  80. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_generate_data_negative.py +0 -0
  81. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_jinja_no_autoescape.py +0 -0
  82. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_main.py +0 -0
  83. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_model_docstring.py +0 -0
  84. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_model_generator.py +0 -0
  85. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_model_generator_edges.py +0 -0
  86. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_openapi_30.py +0 -0
  87. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_openapi_31.py +0 -0
  88. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_openapi_31_completeness.py +0 -0
  89. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_openapi_31_coverage.py +0 -0
  90. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_openapi_31_schema_features.py +0 -0
  91. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_service_generator.py +0 -0
  92. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_service_generator_edges.py +0 -0
  93. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_swagger_petstore_30.py +0 -0
  94. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_swagger_petstore_31.py +0 -0
  95. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_version_detector_edges.py +0 -0
  96. {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ab-openapi-python-generator
3
- Version: 2.2.1
3
+ Version: 2.2.3
4
4
  Summary: Openapi Python Generator
5
5
  Project-URL: Homepage, https://github.com/auth-broker/openapi-python-generator
6
6
  Project-URL: Repository, https://github.com/auth-broker/openapi-python-generator
@@ -788,7 +788,7 @@ only sync (for __requests__) or only async (for __aiohttp__) services.
788
788
  ``` py
789
789
  ...
790
790
  async def async_root__get() -> RootResponse:
791
- base_path = APIConfig().base_path
791
+ base_url = APIConfig().base_url
792
792
  path = f"/"
793
793
  headers = {
794
794
  "Content-Type": "application/json",
@@ -797,7 +797,7 @@ only sync (for __requests__) or only async (for __aiohttp__) services.
797
797
  }
798
798
  query_params = {}
799
799
 
800
- with httpx.AsyncClient(base_url=base_path) as client:
800
+ with httpx.AsyncClient(base_url=base_url) as client:
801
801
  response = await client.request(
802
802
  method="get",
803
803
  url=path,
@@ -815,7 +815,7 @@ only sync (for __requests__) or only async (for __aiohttp__) services.
815
815
  ``` py
816
816
  ...
817
817
  def root__get() -> RootResponse:
818
- base_path = APIConfig().base_path
818
+ base_url = APIConfig().base_url
819
819
  path = f"/"
820
820
  headers = {
821
821
  "Content-Type": "application/json",
@@ -824,7 +824,7 @@ only sync (for __requests__) or only async (for __aiohttp__) services.
824
824
  }
825
825
  query_params = {}
826
826
 
827
- with httpx.Client(base_url=base_path) as client:
827
+ with httpx.Client(base_url=base_url) as client:
828
828
  response = client.request(
829
829
  method="get",
830
830
  url=path,
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ab-openapi-python-generator"
3
- version = "2.2.1"
3
+ version = "2.2.3"
4
4
  description = "Openapi Python Generator"
5
5
  authors = [
6
6
  { name = "Marco Müllner", email = "muellnermarco@gmail.com" },
@@ -0,0 +1,146 @@
1
+ {% if env_token_name is not none %}import os{% endif %}
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import AsyncGenerator
6
+ from typing import Any, Dict, Optional, Union
7
+ import json
8
+
9
+ import httpx
10
+ from pydantic import BaseModel
11
+
12
+ from ..models import *
13
+ from ..exceptions import HTTPException
14
+
15
+ {% set _base_url = servers[0].url if servers|length > 0 else "/" %}
16
+
17
+
18
+ class AsyncClient(BaseModel):
19
+ model_config = {"validate_assignment": True}
20
+
21
+ base_url: str = "{{ _base_url }}"
22
+ verify: Union[bool, str] = True
23
+ {% if env_token_name is none %}
24
+ access_token: Optional[str] = None
25
+ {% endif %}
26
+
27
+ def get_access_token(self) -> Optional[str]:
28
+ {% if env_token_name is not none %}
29
+ try:
30
+ return os.environ["{{ env_token_name }}"]
31
+ except KeyError:
32
+ return None
33
+ {% else %}
34
+ return self.access_token
35
+ {% endif %}
36
+
37
+ def set_access_token(self, value: str) -> None:
38
+ {% if env_token_name is not none %}
39
+ raise Exception(
40
+ "This client was generated with an environment variable for the access token. "
41
+ "Please set '{{ env_token_name }}'."
42
+ )
43
+ {% else %}
44
+ self.access_token = value
45
+ {% endif %}
46
+
47
+ {% for op in operations %}
48
+ async def {{ op.operation_id }}(self{% if op.params %}, {{ op.params }}{% endif %}) -> {%- if op.is_sse -%}
49
+ AsyncGenerator[str | dict[str, Any], None]
50
+ {%- else -%}
51
+ {%- if op.return_type.type is none or op.return_type.type.converted_type is none -%}None
52
+ {%- elif op.return_type.list_type is not none -%}list[{{ op.return_type.list_type }}]
53
+ {%- else -%}{{ op.return_type.type.converted_type }}
54
+ {%- endif -%}
55
+ {%- endif -%}:
56
+ base_url = self.base_url
57
+ path = f"{{ op.path_name }}"
58
+
59
+ headers = {
60
+ "Content-Type": "application/json",
61
+ {% if op.is_sse %}
62
+ "Accept": "text/event-stream",
63
+ {% else %}
64
+ "Accept": "application/json",
65
+ {% endif %}
66
+ "Authorization": f"Bearer { self.get_access_token() }",
67
+ }
68
+
69
+ query_params: Dict[str, Any] = {
70
+ {% for qp in op.query_params %}
71
+ {{ qp }},
72
+ {% endfor %}
73
+ }
74
+ query_params = {k: v for (k, v) in query_params.items() if v is not None}
75
+
76
+ {% if op.is_sse %}
77
+ async with httpx.AsyncClient(base_url=base_url, verify=self.verify) as client:
78
+ async with client.stream(
79
+ "{{ op.method }}",
80
+ httpx.URL(path),
81
+ headers=headers,
82
+ params=query_params,
83
+ {% if op.body_param %}
84
+ json={{ op.body_param }},
85
+ {% endif %}
86
+ ) as response:
87
+ if response.status_code != {{ op.return_type.status_code }}:
88
+ raise HTTPException(
89
+ response.status_code,
90
+ f"{{ op.operation_id }} failed with status code: {response.status_code}",
91
+ )
92
+
93
+ async for line in response.aiter_lines():
94
+ if not line:
95
+ continue
96
+ if line.startswith("data:"):
97
+ payload = line[len("data:"):].strip()
98
+ if not payload:
99
+ continue
100
+ if payload == "[DONE]":
101
+ break
102
+ try:
103
+ obj = json.loads(payload)
104
+ if isinstance(obj, dict):
105
+ yield obj
106
+ else:
107
+ yield payload
108
+ except Exception:
109
+ yield payload
110
+ else:
111
+ # Non-data lines: yield as raw text for debugging/visibility
112
+ yield line
113
+ {% else %}
114
+ async with httpx.AsyncClient(base_url=base_url, verify=self.verify) as client:
115
+ response = await client.request(
116
+ "{{ op.method }}",
117
+ httpx.URL(path),
118
+ headers=headers,
119
+ params=query_params,
120
+ {% if op.body_param %}
121
+ json={{ op.body_param }},
122
+ {% endif %}
123
+ )
124
+
125
+ if response.status_code != {{ op.return_type.status_code }}:
126
+ raise HTTPException(
127
+ response.status_code,
128
+ f"{{ op.operation_id }} failed with status code: {response.status_code}",
129
+ )
130
+
131
+ body = None if {{ op.return_type.status_code }} == 204 else response.json()
132
+
133
+ {% if op.return_type.type is none or op.return_type.type.converted_type is none %}
134
+ return None
135
+ {% elif op.return_type.complex_type %}
136
+ {% if op.return_type.list_type is none %}
137
+ return {{ op.return_type.type.converted_type }}.model_validate(body) if body is not None else {{ op.return_type.type.converted_type }}()
138
+ {% else %}
139
+ return [{{ op.return_type.list_type }}.model_validate(item) for item in (body or [])]
140
+ {% endif %}
141
+ {% else %}
142
+ return body
143
+ {% endif %}
144
+ {% endif %}
145
+
146
+ {% endfor %}
@@ -0,0 +1,145 @@
1
+ {% if env_token_name is not none %}import os{% endif %}
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Generator
6
+ from typing import Any, Dict, Optional, Union
7
+ import json
8
+
9
+ import httpx
10
+ from pydantic import BaseModel
11
+
12
+ from ..models import *
13
+ from ..exceptions import HTTPException
14
+
15
+ {% set _base_url = servers[0].url if servers|length > 0 else "/" %}
16
+
17
+
18
+ class SyncClient(BaseModel):
19
+ model_config = {"validate_assignment": True}
20
+
21
+ base_url: str = "{{ _base_url }}"
22
+ verify: Union[bool, str] = True
23
+ {% if env_token_name is none %}
24
+ access_token: Optional[str] = None
25
+ {% endif %}
26
+
27
+ def get_access_token(self) -> Optional[str]:
28
+ {% if env_token_name is not none %}
29
+ try:
30
+ return os.environ["{{ env_token_name }}"]
31
+ except KeyError:
32
+ return None
33
+ {% else %}
34
+ return self.access_token
35
+ {% endif %}
36
+
37
+ def set_access_token(self, value: str) -> None:
38
+ {% if env_token_name is not none %}
39
+ raise Exception(
40
+ "This client was generated with an environment variable for the access token. "
41
+ "Please set '{{ env_token_name }}'."
42
+ )
43
+ {% else %}
44
+ self.access_token = value
45
+ {% endif %}
46
+
47
+ {% for op in operations %}
48
+ def {{ op.operation_id }}(self{% if op.params %}, {{ op.params }}{% endif %}) -> {%- if op.is_sse -%}
49
+ Generator[str | dict[str, Any], None, None]
50
+ {%- else -%}
51
+ {%- if op.return_type.type is none or op.return_type.type.converted_type is none -%}None
52
+ {%- elif op.return_type.list_type is not none -%}list[{{ op.return_type.list_type }}]
53
+ {%- else -%}{{ op.return_type.type.converted_type }}
54
+ {%- endif -%}
55
+ {%- endif -%}:
56
+ base_url = self.base_url
57
+ path = f"{{ op.path_name }}"
58
+
59
+ headers = {
60
+ "Content-Type": "application/json",
61
+ {% if op.is_sse %}
62
+ "Accept": "text/event-stream",
63
+ {% else %}
64
+ "Accept": "application/json",
65
+ {% endif %}
66
+ "Authorization": f"Bearer { self.get_access_token() }",
67
+ }
68
+
69
+ query_params: Dict[str, Any] = {
70
+ {% for qp in op.query_params %}
71
+ {{ qp }},
72
+ {% endfor %}
73
+ }
74
+ query_params = {k: v for (k, v) in query_params.items() if v is not None}
75
+
76
+ {% if op.is_sse %}
77
+ with httpx.Client(base_url=base_url, verify=self.verify) as client:
78
+ with client.stream(
79
+ "{{ op.method }}",
80
+ httpx.URL(path),
81
+ headers=headers,
82
+ params=query_params,
83
+ {% if op.body_param %}
84
+ json={{ op.body_param }},
85
+ {% endif %}
86
+ ) as response:
87
+ if response.status_code != {{ op.return_type.status_code }}:
88
+ raise HTTPException(
89
+ response.status_code,
90
+ f"{{ op.operation_id }} failed with status code: {response.status_code}",
91
+ )
92
+
93
+ for line in response.iter_lines():
94
+ if not line:
95
+ continue
96
+ if line.startswith("data:"):
97
+ payload = line[len("data:"):].strip()
98
+ if not payload:
99
+ continue
100
+ if payload == "[DONE]":
101
+ break
102
+ try:
103
+ obj = json.loads(payload)
104
+ if isinstance(obj, dict):
105
+ yield obj
106
+ else:
107
+ yield payload
108
+ except Exception:
109
+ yield payload
110
+ else:
111
+ yield line
112
+ {% else %}
113
+ with httpx.Client(base_url=base_url, verify=self.verify) as client:
114
+ response = client.request(
115
+ "{{ op.method }}",
116
+ httpx.URL(path),
117
+ headers=headers,
118
+ params=query_params,
119
+ {% if op.body_param %}
120
+ json={{ op.body_param }},
121
+ {% endif %}
122
+ )
123
+
124
+ if response.status_code != {{ op.return_type.status_code }}:
125
+ raise HTTPException(
126
+ response.status_code,
127
+ f"{{ op.operation_id }} failed with status code: {response.status_code}",
128
+ )
129
+
130
+ body = None if {{ op.return_type.status_code }} == 204 else response.json()
131
+
132
+ {% if op.return_type.type is none or op.return_type.type.converted_type is none %}
133
+ return None
134
+ {% elif op.return_type.complex_type %}
135
+ {% if op.return_type.list_type is none %}
136
+ return {{ op.return_type.type.converted_type }}.model_validate(body) if body is not None else {{ op.return_type.type.converted_type }}()
137
+ {% else %}
138
+ return [{{ op.return_type.list_type }}.model_validate(item) for item in (body or [])]
139
+ {% endif %}
140
+ {% else %}
141
+ return body
142
+ {% endif %}
143
+ {% endif %}
144
+
145
+ {% endfor %}
@@ -80,21 +80,6 @@ class Model(BaseModel):
80
80
  properties: List[Property] = []
81
81
 
82
82
 
83
- class Service(BaseModel):
84
- file_name: str
85
- operations: List[ServiceOperation]
86
- content: str
87
- async_client: Optional[bool] = False
88
- library_import: str
89
- use_orjson: bool = False
90
-
91
-
92
- class APIConfig(BaseModel):
93
- file_name: str
94
- base_url: str
95
- content: str
96
-
97
-
98
83
  class ConversionResult(BaseModel):
99
84
  models: List[Model] = Field(default_factory=list)
100
85
  clients: List[Model] = Field(default_factory=list)
@@ -131,10 +131,10 @@ def test_generate_code(
131
131
 
132
132
  # Get the base URL from the API config
133
133
  if custom_ip is not None:
134
- api_config_instance.base_path = custom_ip
134
+ api_config_instance.base_url = custom_ip
135
135
  base_url = custom_ip
136
136
  else:
137
- base_url = api_config_instance.base_path
137
+ base_url = api_config_instance.base_url
138
138
 
139
139
  # Ensure base_url doesn't have trailing slash for consistent URL construction
140
140
  base_url = base_url.rstrip("/")
@@ -431,7 +431,7 @@ async def _run_service_tests_aiohttp(
431
431
  port = sockets[0].getsockname()[1]
432
432
 
433
433
  base_url = f"{scheme}://{host}:{port}"
434
- api_config_instance.base_path = base_url
434
+ api_config_instance.base_url = base_url
435
435
 
436
436
  try:
437
437
  # Call async generated functions
@@ -1,80 +0,0 @@
1
- {% if env_token_name is not none %}import os{% endif %}
2
-
3
- from typing import Any, Dict, Optional, Union
4
-
5
- import httpx
6
- from pydantic import BaseModel
7
-
8
- from ..models import *
9
- {% set _base_path = servers[0].url if servers|length > 0 else "/" %}
10
- from ..exceptions import HTTPException
11
-
12
-
13
- class AsyncClient(BaseModel):
14
- model_config = {"validate_assignment": True}
15
-
16
- base_path: str = "{{ _base_path }}"
17
- verify: Union[bool, str] = True
18
- {% if env_token_name is none %}
19
- access_token: Optional[str] = None
20
- {% endif %}
21
-
22
- def get_access_token(self) -> Optional[str]:
23
- {% if env_token_name is not none %}
24
- try:
25
- return os.environ["{{ env_token_name }}"]
26
- except KeyError:
27
- return None
28
- {% else %}
29
- return self.access_token
30
- {% endif %}
31
-
32
- def set_access_token(self, value: str) -> None:
33
- {% if env_token_name is not none %}
34
- raise Exception(
35
- "This client was generated with an environment variable for the access token. "
36
- "Please set '{{ env_token_name }}'."
37
- )
38
- {% else %}
39
- self.access_token = value
40
- {% endif %}
41
-
42
- {% for op in operations %}
43
- async def {{ op.operation_id }}(self{% if op.params %}, {{ op.params }}{% endif %}) -> Any:
44
- base_path = self.base_path
45
- path = f"{{ op.path_name }}"
46
-
47
- headers = {
48
- "Content-Type": "application/json",
49
- "Accept": "application/json",
50
- "Authorization": f"Bearer { self.get_access_token() }",
51
- }
52
-
53
- query_params: Dict[str, Any] = {
54
- {% for qp in op.query_params %}
55
- {{ qp }},
56
- {% endfor %}
57
- }
58
- query_params = {k: v for (k, v) in query_params.items() if v is not None}
59
-
60
- async with httpx.AsyncClient(base_url=base_path, verify=self.verify) as client:
61
- response = await client.request(
62
- "{{ op.method }}",
63
- httpx.URL(path),
64
- headers=headers,
65
- params=query_params,
66
- {% if op.body_param %}
67
- json={{ op.body_param }},
68
- {% endif %}
69
- )
70
-
71
- if response.status_code != {{ op.return_type.status_code }}:
72
- raise HTTPException(
73
- response.status_code,
74
- f"{{ op.operation_id }} failed with status code: {response.status_code}",
75
- )
76
-
77
- body = None if {{ op.return_type.status_code }} == 204 else response.json()
78
- return body
79
-
80
- {% endfor %}
@@ -1,80 +0,0 @@
1
- {% if env_token_name is not none %}import os{% endif %}
2
-
3
- from typing import Any, Dict, Optional, Union
4
-
5
- import httpx
6
- from pydantic import BaseModel
7
-
8
- from ..models import *
9
- {% set _base_path = servers[0].url if servers|length > 0 else "/" %}
10
- from ..exceptions import HTTPException
11
-
12
-
13
- class SyncClient(BaseModel):
14
- model_config = {"validate_assignment": True}
15
-
16
- base_path: str = "{{ _base_path }}"
17
- verify: Union[bool, str] = True
18
- {% if env_token_name is none %}
19
- access_token: Optional[str] = None
20
- {% endif %}
21
-
22
- def get_access_token(self) -> Optional[str]:
23
- {% if env_token_name is not none %}
24
- try:
25
- return os.environ["{{ env_token_name }}"]
26
- except KeyError:
27
- return None
28
- {% else %}
29
- return self.access_token
30
- {% endif %}
31
-
32
- def set_access_token(self, value: str) -> None:
33
- {% if env_token_name is not none %}
34
- raise Exception(
35
- "This client was generated with an environment variable for the access token. "
36
- "Please set '{{ env_token_name }}'."
37
- )
38
- {% else %}
39
- self.access_token = value
40
- {% endif %}
41
-
42
- {% for op in operations %}
43
- def {{ op.operation_id }}(self{% if op.params %}, {{ op.params }}{% endif %}) -> Any:
44
- base_path = self.base_path
45
- path = f"{{ op.path_name }}"
46
-
47
- headers = {
48
- "Content-Type": "application/json",
49
- "Accept": "application/json",
50
- "Authorization": f"Bearer { self.get_access_token() }",
51
- }
52
-
53
- query_params: Dict[str, Any] = {
54
- {% for qp in op.query_params %}
55
- {{ qp }},
56
- {% endfor %}
57
- }
58
- query_params = {k: v for (k, v) in query_params.items() if v is not None}
59
-
60
- with httpx.Client(base_url=base_path, verify=self.verify) as client:
61
- response = client.request(
62
- "{{ op.method }}",
63
- httpx.URL(path),
64
- headers=headers,
65
- params=query_params,
66
- {% if op.body_param %}
67
- json={{ op.body_param }},
68
- {% endif %}
69
- )
70
-
71
- if response.status_code != {{ op.return_type.status_code }}:
72
- raise HTTPException(
73
- response.status_code,
74
- f"{{ op.operation_id }} failed with status code: {response.status_code}",
75
- )
76
-
77
- body = None if {{ op.return_type.status_code }} == 204 else response.json()
78
- return body
79
-
80
- {% endfor %}