openapi-httpx-client 0.4.2__tar.gz → 0.4.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.
- openapi_httpx_client-0.4.3/LICENSE +21 -0
- {openapi-httpx-client-0.4.2 → openapi_httpx_client-0.4.3}/PKG-INFO +15 -6
- {openapi-httpx-client-0.4.2 → openapi_httpx_client-0.4.3}/openapi_httpx_client.egg-info/PKG-INFO +15 -6
- {openapi-httpx-client-0.4.2 → openapi_httpx_client-0.4.3}/openapi_httpx_client.egg-info/SOURCES.txt +1 -0
- {openapi-httpx-client-0.4.2 → openapi_httpx_client-0.4.3}/openapiclient/client.py +67 -15
- {openapi-httpx-client-0.4.2 → openapi_httpx_client-0.4.3}/setup.py +1 -1
- {openapi-httpx-client-0.4.2 → openapi_httpx_client-0.4.3}/README.md +0 -0
- {openapi-httpx-client-0.4.2 → openapi_httpx_client-0.4.3}/openapi_httpx_client.egg-info/dependency_links.txt +0 -0
- {openapi-httpx-client-0.4.2 → openapi_httpx_client-0.4.3}/openapi_httpx_client.egg-info/requires.txt +0 -0
- {openapi-httpx-client-0.4.2 → openapi_httpx_client-0.4.3}/openapi_httpx_client.egg-info/top_level.txt +0 -0
- {openapi-httpx-client-0.4.2 → openapi_httpx_client-0.4.3}/openapiclient/__init__.py +0 -0
- {openapi-httpx-client-0.4.2 → openapi_httpx_client-0.4.3}/setup.cfg +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Lloyd Zhou
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,17 +1,28 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: openapi-httpx-client
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: A Python client for OpenAPI specifications using httpx
|
|
5
5
|
Home-page: https://github.com/lloydzhou/openapiclient
|
|
6
6
|
Author: lloydzhou
|
|
7
7
|
Author-email: lloydzhou@qq.com
|
|
8
|
-
License: UNKNOWN
|
|
9
|
-
Platform: UNKNOWN
|
|
10
8
|
Classifier: Programming Language :: Python :: 3
|
|
11
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
12
10
|
Classifier: Operating System :: OS Independent
|
|
13
11
|
Requires-Python: >=3.7
|
|
14
12
|
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: httpx>=0.23.0
|
|
15
|
+
Requires-Dist: pyyaml>=6.0
|
|
16
|
+
Dynamic: author
|
|
17
|
+
Dynamic: author-email
|
|
18
|
+
Dynamic: classifier
|
|
19
|
+
Dynamic: description
|
|
20
|
+
Dynamic: description-content-type
|
|
21
|
+
Dynamic: home-page
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
Dynamic: requires-dist
|
|
24
|
+
Dynamic: requires-python
|
|
25
|
+
Dynamic: summary
|
|
15
26
|
|
|
16
27
|
# OpenAPI Client for Python
|
|
17
28
|
|
|
@@ -132,5 +143,3 @@ All API responses are returned in a dictionary format with the following keys:
|
|
|
132
143
|
lloydzhou
|
|
133
144
|
|
|
134
145
|
|
|
135
|
-
|
|
136
|
-
|
{openapi-httpx-client-0.4.2 → openapi_httpx_client-0.4.3}/openapi_httpx_client.egg-info/PKG-INFO
RENAMED
|
@@ -1,17 +1,28 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: openapi-httpx-client
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: A Python client for OpenAPI specifications using httpx
|
|
5
5
|
Home-page: https://github.com/lloydzhou/openapiclient
|
|
6
6
|
Author: lloydzhou
|
|
7
7
|
Author-email: lloydzhou@qq.com
|
|
8
|
-
License: UNKNOWN
|
|
9
|
-
Platform: UNKNOWN
|
|
10
8
|
Classifier: Programming Language :: Python :: 3
|
|
11
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
12
10
|
Classifier: Operating System :: OS Independent
|
|
13
11
|
Requires-Python: >=3.7
|
|
14
12
|
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: httpx>=0.23.0
|
|
15
|
+
Requires-Dist: pyyaml>=6.0
|
|
16
|
+
Dynamic: author
|
|
17
|
+
Dynamic: author-email
|
|
18
|
+
Dynamic: classifier
|
|
19
|
+
Dynamic: description
|
|
20
|
+
Dynamic: description-content-type
|
|
21
|
+
Dynamic: home-page
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
Dynamic: requires-dist
|
|
24
|
+
Dynamic: requires-python
|
|
25
|
+
Dynamic: summary
|
|
15
26
|
|
|
16
27
|
# OpenAPI Client for Python
|
|
17
28
|
|
|
@@ -132,5 +143,3 @@ All API responses are returned in a dictionary format with the following keys:
|
|
|
132
143
|
lloydzhou
|
|
133
144
|
|
|
134
145
|
|
|
135
|
-
|
|
136
|
-
|
|
@@ -3,6 +3,8 @@ import json
|
|
|
3
3
|
import os.path
|
|
4
4
|
from urllib.parse import urljoin, urlparse
|
|
5
5
|
import yaml
|
|
6
|
+
import re
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
# 合并DynamicClientBase和BaseClient为一个基类
|
|
8
10
|
class BaseClient:
|
|
@@ -67,13 +69,13 @@ class Client(BaseClient):
|
|
|
67
69
|
def __init__(self, api, **kwargs):
|
|
68
70
|
"""Initialize the sync client"""
|
|
69
71
|
super().__init__(api)
|
|
70
|
-
self.session = httpx.Client(**kwargs)
|
|
72
|
+
self.session = api.httpx_client or httpx.Client(**kwargs)
|
|
71
73
|
|
|
72
74
|
def __enter__(self):
|
|
73
75
|
"""Enter context manager and initialize the client"""
|
|
74
76
|
if not self.api.definition:
|
|
75
77
|
self.api._load_definition_sync()
|
|
76
|
-
|
|
78
|
+
|
|
77
79
|
self.setup_base_url()
|
|
78
80
|
# Generate methods directly on this instance
|
|
79
81
|
self.api._generate_client_methods(self, is_async=False)
|
|
@@ -94,7 +96,7 @@ class AsyncClient(BaseClient):
|
|
|
94
96
|
def __init__(self, api, **kwargs):
|
|
95
97
|
"""Initialize the async client"""
|
|
96
98
|
super().__init__(api)
|
|
97
|
-
self.session = httpx.AsyncClient(**kwargs)
|
|
99
|
+
self.session = api.httpx_async_client or httpx.AsyncClient(**kwargs)
|
|
98
100
|
|
|
99
101
|
async def __aenter__(self):
|
|
100
102
|
"""Enter async context manager and initialize the client"""
|
|
@@ -112,6 +114,50 @@ class AsyncClient(BaseClient):
|
|
|
112
114
|
await self.session.aclose()
|
|
113
115
|
|
|
114
116
|
|
|
117
|
+
def sanitize_openapi_path(path: str) -> str:
|
|
118
|
+
"""
|
|
119
|
+
Convert OpenAPI path (e.g. "/v3/symbols/{symbol}/session") into a valid Python identifier.
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
# replace path parameters {param} with sanitized param name prefixed with "by_"
|
|
123
|
+
def repl_param(m):
|
|
124
|
+
name = m.group(1) or ""
|
|
125
|
+
# sanitize param name: replace non-alnum/_ with underscore and collapse
|
|
126
|
+
name = re.sub(r"[^0-9A-Za-z_]", "_", name)
|
|
127
|
+
name = re.sub(r"_+", "_", name).strip("_")
|
|
128
|
+
return "by_" + name
|
|
129
|
+
|
|
130
|
+
s = re.sub(r"\{([^}]*)\}", repl_param, path)
|
|
131
|
+
# replace slashes/backslashes with underscore
|
|
132
|
+
s = re.sub(r"[\\/]+", "_", s)
|
|
133
|
+
# replace any remaining non-alnum/_ with underscore
|
|
134
|
+
s = re.sub(r"[^0-9A-Za-z_]", "_", s)
|
|
135
|
+
# collapse underscores and strip edges
|
|
136
|
+
s = re.sub(r"_+", "_", s).strip("_")
|
|
137
|
+
|
|
138
|
+
return s
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def resolve_open_api_reference(dct, definition):
|
|
142
|
+
if "$ref" not in dct:
|
|
143
|
+
return dct
|
|
144
|
+
else:
|
|
145
|
+
ref_path = dct["$ref"]
|
|
146
|
+
# Only handling local references for simplicity
|
|
147
|
+
if not ref_path.startswith("#/"):
|
|
148
|
+
raise NotImplementedError(
|
|
149
|
+
"Only local references are supported in this implementation."
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
parts = ref_path.lstrip("#/").split("/")
|
|
153
|
+
ref = definition
|
|
154
|
+
for part in parts:
|
|
155
|
+
ref = ref.get(part)
|
|
156
|
+
if ref is None:
|
|
157
|
+
raise ValueError(f"Reference {ref_path} could not be resolved.")
|
|
158
|
+
return ref
|
|
159
|
+
|
|
160
|
+
|
|
115
161
|
# Create the main OpenAPIClient class as a factory
|
|
116
162
|
class OpenAPIClient:
|
|
117
163
|
"""
|
|
@@ -130,7 +176,7 @@ class OpenAPIClient:
|
|
|
130
176
|
result = await client.operation_name(param1=value)
|
|
131
177
|
"""
|
|
132
178
|
|
|
133
|
-
def __init__(self, definition=None):
|
|
179
|
+
def __init__(self, definition=None, httpx_client=None, httpx_async_client=None):
|
|
134
180
|
"""
|
|
135
181
|
Initialize the OpenAPI client.
|
|
136
182
|
|
|
@@ -139,8 +185,10 @@ class OpenAPIClient:
|
|
|
139
185
|
"""
|
|
140
186
|
self.definition_source = definition
|
|
141
187
|
self.definition = {}
|
|
142
|
-
self.base_url =
|
|
188
|
+
self.base_url = ""
|
|
143
189
|
self.source_url = None # Store the source URL if loaded from a URL
|
|
190
|
+
self.httpx_client = httpx_client
|
|
191
|
+
self.httpx_async_client = httpx_async_client
|
|
144
192
|
|
|
145
193
|
def Client(self, **kwargs):
|
|
146
194
|
"""
|
|
@@ -153,7 +201,7 @@ class OpenAPIClient:
|
|
|
153
201
|
Client: A synchronous client
|
|
154
202
|
"""
|
|
155
203
|
return Client(self, **kwargs)
|
|
156
|
-
|
|
204
|
+
|
|
157
205
|
def AsyncClient(self, **kwargs):
|
|
158
206
|
"""
|
|
159
207
|
Create an asynchronous client instance that can be used as a context manager.
|
|
@@ -353,7 +401,9 @@ class OpenAPIClient:
|
|
|
353
401
|
for operation in self.get_operations():
|
|
354
402
|
operation_id = operation.get('operationId')
|
|
355
403
|
if not operation_id:
|
|
356
|
-
|
|
404
|
+
operation_id = (
|
|
405
|
+
operation["method"] + "_" + sanitize_openapi_path(operation["path"])
|
|
406
|
+
)
|
|
357
407
|
|
|
358
408
|
path = operation.get('path')
|
|
359
409
|
paths.append(path)
|
|
@@ -399,6 +449,7 @@ class OpenAPIClient:
|
|
|
399
449
|
# Extract parameters from operation definition
|
|
400
450
|
parameters = operation.get('parameters', [])
|
|
401
451
|
for param in parameters:
|
|
452
|
+
param = resolve_open_api_reference(param, self.definition)
|
|
402
453
|
if param.get('in') == 'path':
|
|
403
454
|
name = param.get('name')
|
|
404
455
|
if name in kwargs:
|
|
@@ -416,6 +467,7 @@ class OpenAPIClient:
|
|
|
416
467
|
# Handle query parameters
|
|
417
468
|
query_params = {}
|
|
418
469
|
for param in parameters:
|
|
470
|
+
param = resolve_open_api_reference(param, self.definition)
|
|
419
471
|
if param.get('in') == 'query':
|
|
420
472
|
name = param.get('name')
|
|
421
473
|
if name in kwargs:
|
|
@@ -483,10 +535,10 @@ class OpenAPIClient:
|
|
|
483
535
|
response = await client_instance.session.request(
|
|
484
536
|
method,
|
|
485
537
|
full_url,
|
|
486
|
-
params=query_params,
|
|
487
|
-
json=body,
|
|
488
|
-
headers=headers,
|
|
489
|
-
**remaining_kwargs
|
|
538
|
+
params=query_params,
|
|
539
|
+
json=body,
|
|
540
|
+
headers=dict(client_instance.session.headers) | headers,
|
|
541
|
+
**remaining_kwargs,
|
|
490
542
|
)
|
|
491
543
|
|
|
492
544
|
# Process the response
|
|
@@ -502,10 +554,10 @@ class OpenAPIClient:
|
|
|
502
554
|
response = client_instance.session.request(
|
|
503
555
|
method,
|
|
504
556
|
full_url,
|
|
505
|
-
params=query_params,
|
|
506
|
-
json=body,
|
|
507
|
-
headers=headers,
|
|
508
|
-
**remaining_kwargs
|
|
557
|
+
params=query_params,
|
|
558
|
+
json=body,
|
|
559
|
+
headers=dict(client_instance.session.headers) | headers,
|
|
560
|
+
**remaining_kwargs,
|
|
509
561
|
)
|
|
510
562
|
|
|
511
563
|
# Process the response
|
|
File without changes
|
|
File without changes
|
{openapi-httpx-client-0.4.2 → openapi_httpx_client-0.4.3}/openapi_httpx_client.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|