openapi-httpx-client 0.4.0__tar.gz → 0.4.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openapi-httpx-client
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: A Python client for OpenAPI specifications using httpx
5
5
  Home-page: https://github.com/lloydzhou/openapiclient
6
6
  Author: lloydzhou
@@ -47,6 +47,11 @@ async def main():
47
47
  pet = await client.getPetById(petId=1)
48
48
  print(f"Status: {pet['status']}")
49
49
  print(f"Pet data: {pet['data']}")
50
+
51
+ # Call operations directly as methods, using positional arguments, can using in path and query
52
+ pet = await client.getPetById(1)
53
+ print(f"Status: {pet['status']}")
54
+ print(f"Pet data: {pet['data']}")
50
55
 
51
56
  # Alternative way to call methods
52
57
  pet = await client("getPetById", petId=2)
@@ -32,6 +32,11 @@ async def main():
32
32
  pet = await client.getPetById(petId=1)
33
33
  print(f"Status: {pet['status']}")
34
34
  print(f"Pet data: {pet['data']}")
35
+
36
+ # Call operations directly as methods, using positional arguments, can using in path and query
37
+ pet = await client.getPetById(1)
38
+ print(f"Status: {pet['status']}")
39
+ print(f"Pet data: {pet['data']}")
35
40
 
36
41
  # Alternative way to call methods
37
42
  pet = await client("getPetById", petId=2)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openapi-httpx-client
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: A Python client for OpenAPI specifications using httpx
5
5
  Home-page: https://github.com/lloydzhou/openapiclient
6
6
  Author: lloydzhou
@@ -47,6 +47,11 @@ async def main():
47
47
  pet = await client.getPetById(petId=1)
48
48
  print(f"Status: {pet['status']}")
49
49
  print(f"Pet data: {pet['data']}")
50
+
51
+ # Call operations directly as methods, using positional arguments, can using in path and query
52
+ pet = await client.getPetById(1)
53
+ print(f"Status: {pet['status']}")
54
+ print(f"Pet data: {pet['data']}")
50
55
 
51
56
  # Alternative way to call methods
52
57
  pet = await client("getPetById", petId=2)
@@ -1,3 +1,2 @@
1
1
  httpx>=0.23.0
2
2
  pyyaml>=6.0
3
- nanoid>=0.2.1
@@ -1,10 +1,8 @@
1
1
  import httpx
2
2
  import json
3
3
  import os.path
4
- from typing import Dict, List, Any, Optional, Union, Callable, Type
5
4
  from urllib.parse import urljoin, urlparse
6
5
  import yaml
7
- from nanoid import generate as nanoid_generate
8
6
 
9
7
  # 合并DynamicClientBase和BaseClient为一个基类
10
8
  class BaseClient:
@@ -189,6 +187,10 @@ class OpenAPIClient:
189
187
 
190
188
  async def _load_definition_async(self):
191
189
  """Load the OpenAPI definition asynchronously"""
190
+ # Check if definition is already loaded
191
+ if self.definition:
192
+ return
193
+
192
194
  if isinstance(self.definition_source, dict):
193
195
  self.definition = self.definition_source
194
196
  return
@@ -209,6 +211,10 @@ class OpenAPIClient:
209
211
 
210
212
  def _load_definition_sync(self):
211
213
  """Load the OpenAPI definition synchronously"""
214
+ # Check if definition is already loaded
215
+ if self.definition:
216
+ return
217
+
212
218
  if isinstance(self.definition_source, dict):
213
219
  self.definition = self.definition_source
214
220
  return
@@ -283,38 +289,43 @@ class OpenAPIClient:
283
289
 
284
290
  def create_tool(self, operation_id, operation, all_references):
285
291
  """Create an AI tool description from operation data"""
286
- # Get parameters from the request body schema only for json content
292
+ # Get parameters from the request body schema
287
293
  body = operation.get('requestBody', {})
288
- schema = body.get('content', {}).get('application/json', {}).get('schema', {})
289
- parameters = {
290
- "type": "object",
291
- "required": ['body'] if body.get("required", False) else [],
292
- "description": body.get('description', ''),
293
- "properties": {
294
- "body": self.resolve_schema_ref(schema, all_references) if schema else {},
295
- }
296
- }
294
+ content = body.get('content', {})
295
+ schema = content.get('application/json', {}).get('schema', {}) or content.get('application/xml', {}).get('schema', {}) or content.get('application/x-www-form-urlencoded', {}).get('schema', {})
296
+ json_schema = self.resolve_schema_ref(schema, all_references) if schema else { "type": "object", "properties": {} }
297
+
298
+ if not json_schema.get('description'):
299
+ json_schema['description'] = body.get('description', '')
300
+
297
301
  # add parameters from path and query
298
- for parameter in operation.get('parameters', []):
299
- name = parameter.get('name')
300
- if parameter.get('required', False):
301
- parameters["required"].append(name)
302
- item = {
303
- "type": parameter.get('schema', {}).get('type', 'string'),
304
- "description": parameter.get('description', ''),
305
- }
306
- # Add format, enum, and example if available
307
- for key in ['format', 'enum', 'example']:
308
- if parameter.get('schema', {}).get(key):
309
- item[key] = parameter.get('schema', {}).get(key)
310
- parameters["properties"][name] = item
302
+ parameters = operation.get('parameters', [])
303
+ if len(parameters) > 0:
304
+ if not json_schema.get('required'):
305
+ json_schema['required'] = []
306
+ if not json_schema.get('properties'):
307
+ json_schema['properties'] = {}
308
+ for parameter in parameters:
309
+ name = parameter.get('name')
310
+ if parameter.get('required', False):
311
+ json_schema["required"].append(name)
312
+
313
+ parameter_schema = {
314
+ "type": parameter.get('schema', {}).get('type', 'string'),
315
+ "description": parameter.get('description', ''),
316
+ }
317
+ # Add format, enum, and example if available
318
+ for key in ['format', 'enum', 'example']:
319
+ if parameter.get('schema', {}).get(key):
320
+ parameter_schema[key] = parameter.get('schema', {}).get(key)
321
+ json_schema["properties"][name] = parameter_schema
311
322
 
312
323
  return {
313
324
  "type": "function",
314
325
  "function": {
315
326
  "name": operation_id,
316
327
  "description": operation.get('summary', '') or operation.get('description', ''),
317
- "parameters": parameters,
328
+ "parameters": json_schema,
318
329
  }
319
330
  }
320
331
 
@@ -368,13 +379,14 @@ class OpenAPIClient:
368
379
  client_instance.paths = paths
369
380
  client_instance.tools = tools
370
381
 
371
- def _prepare_request_params(self, path, operation, kwargs):
382
+ def _prepare_request_params(self, path, operation, args, kwargs):
372
383
  """
373
384
  Prepare request parameters for an API operation.
374
385
 
375
386
  Args:
376
387
  path: The path template
377
388
  operation: Operation object
389
+ args: Positional arguments passed to the operation
378
390
  kwargs: Keyword arguments passed to the operation
379
391
 
380
392
  Returns:
@@ -391,6 +403,8 @@ class OpenAPIClient:
391
403
  name = param.get('name')
392
404
  if name in kwargs:
393
405
  path_params[name] = kwargs.pop(name)
406
+ elif len(args) > 0:
407
+ path_params[name] = args.pop(0) # Pop the first positional argument
394
408
 
395
409
  # Replace path parameters in the URL
396
410
  for name, value in path_params.items():
@@ -406,6 +420,8 @@ class OpenAPIClient:
406
420
  name = param.get('name')
407
421
  if name in kwargs:
408
422
  query_params[name] = kwargs.pop(name)
423
+ elif len(args) > 0:
424
+ query_params[name] = args.pop(0) # Pop the first positional argument
409
425
 
410
426
  # Handle headers
411
427
  headers = kwargs.pop('headers', {})
@@ -413,7 +429,7 @@ class OpenAPIClient:
413
429
  # Handle request body
414
430
  body = kwargs.pop('data', None) or kwargs.pop('body', None)
415
431
  # json body
416
- if not body and len(kwargs) > 0 and operation.get('requestBody', {}).get('content', {}).get('application/json'):
432
+ if not body and len(kwargs) > 0 and operation.get('requestBody', {}).get('content', {}):
417
433
  body = kwargs.copy()
418
434
  kwargs.clear() # Clear the kwargs after using them as body
419
435
 
@@ -460,7 +476,7 @@ class OpenAPIClient:
460
476
  async def operation_method(*args, **kwargs):
461
477
  # Prepare request parameters
462
478
  full_url, query_params, body, headers, remaining_kwargs = self._prepare_request_params(
463
- path, operation, kwargs.copy()
479
+ path, operation, list(args), kwargs.copy()
464
480
  )
465
481
 
466
482
  # Make the async request
@@ -479,7 +495,7 @@ class OpenAPIClient:
479
495
  def operation_method(*args, **kwargs):
480
496
  # Prepare request parameters
481
497
  full_url, query_params, body, headers, remaining_kwargs = self._prepare_request_params(
482
- path, operation, kwargs.copy()
498
+ path, operation, list(args), kwargs.copy()
483
499
  )
484
500
 
485
501
  # Make the sync request
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setup(
7
7
  name="openapi-httpx-client",
8
- version="0.4.0",
8
+ version="0.4.2",
9
9
  author="lloydzhou",
10
10
  author_email="lloydzhou@qq.com",
11
11
  description="A Python client for OpenAPI specifications using httpx",
@@ -16,7 +16,6 @@ setup(
16
16
  install_requires=[
17
17
  "httpx>=0.23.0",
18
18
  "pyyaml>=6.0",
19
- "nanoid>=0.2.1",
20
19
  ],
21
20
  classifiers=[
22
21
  "Programming Language :: Python :: 3",