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.
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/PKG-INFO +1 -1
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/tutorial/index.md +4 -4
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/pyproject.toml +1 -1
- ab_openapi_python_generator-2.2.3/src/ab_openapi_python_generator/language_converters/python/templates/async_client_httpx_pydantic_2.jinja2 +146 -0
- ab_openapi_python_generator-2.2.3/src/ab_openapi_python_generator/language_converters/python/templates/sync_client_httpx_pydantic_2.jinja2 +145 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/models.py +0 -15
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_generated_code.py +3 -3
- ab_openapi_python_generator-2.2.1/src/ab_openapi_python_generator/language_converters/python/templates/async_client_httpx_pydantic_2.jinja2 +0 -80
- ab_openapi_python_generator-2.2.1/src/ab_openapi_python_generator/language_converters/python/templates/sync_client_httpx_pydantic_2.jinja2 +0 -80
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.envrc.example +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.gitattributes +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.github/dependabot.yml +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.github/workflows/ci.yaml +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.github/workflows/publish.yaml +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.gitignore +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.pre-commit-config.yaml +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.vscode/launch.json +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.vscode/tasks.json +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/LICENSE +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/Makefile +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/README.md +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/acknowledgements/index.md +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/css/custom.css +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/css/termynal.css +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/index.md +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/js/custom.js +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/js/termynal.js +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/openapi-definition.md +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/quick_start.md +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/references/index.md +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/references/module_usage.md +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/tutorial/advanced.md +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/tutorial/authentication.md +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/logo.png +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/__init__.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/__main__.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/common.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/generate_data.py +0 -0
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/parsers/__init__.py +0 -0
- {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
- {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
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/py.typed +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/src/ab_openapi_python_generator/version_detector.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/__init__.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/build_test_api/api.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/conftest.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_common_normalize_symbol.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/failing_api.json +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/gitea_issue_11.json +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_117.json +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_120.json +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_17.json +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_30_87.json +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_51.json +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_55.json +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_71.json +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_71_31.json +0 -0
- {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
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/issue_keyword_parameter_name.json +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/openapi_gitea_converted.json +0 -0
- {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
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/swagger_petstore_3_1.yaml +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/test_api.json +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_data/test_api_31.json +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_generate_data.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_generate_data_negative.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_jinja_no_autoescape.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_main.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_model_docstring.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_model_generator.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_model_generator_edges.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_openapi_30.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_openapi_31.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_openapi_31_completeness.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_openapi_31_coverage.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_openapi_31_schema_features.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_service_generator.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_service_generator_edges.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_swagger_petstore_30.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_swagger_petstore_31.py +0 -0
- {ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_version_detector_edges.py +0 -0
- {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.
|
|
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
|
{ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/tutorial/index.md
RENAMED
|
@@ -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
|
-
|
|
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=
|
|
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
|
-
|
|
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=
|
|
827
|
+
with httpx.Client(base_url=base_url) as client:
|
|
828
828
|
response = client.request(
|
|
829
829
|
method="get",
|
|
830
830
|
url=path,
|
|
@@ -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)
|
{ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_generated_code.py
RENAMED
|
@@ -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.
|
|
134
|
+
api_config_instance.base_url = custom_ip
|
|
135
135
|
base_url = custom_ip
|
|
136
136
|
else:
|
|
137
|
-
base_url = api_config_instance.
|
|
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.
|
|
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 %}
|
|
File without changes
|
|
File without changes
|
{ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.github/dependabot.yml
RENAMED
|
File without changes
|
{ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.github/workflows/ci.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/.pre-commit-config.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/css/termynal.css
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/openapi-definition.md
RENAMED
|
File without changes
|
|
File without changes
|
{ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/references/index.md
RENAMED
|
File without changes
|
|
File without changes
|
{ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/docs/tutorial/advanced.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/build_test_api/api.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_generate_data.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_openapi_30.py
RENAMED
|
File without changes
|
{ab_openapi_python_generator-2.2.1 → ab_openapi_python_generator-2.2.3}/tests/test_openapi_31.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|