vantage-python 0.3.0__tar.gz → 0.3.1__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.
- {vantage_python-0.3.0 → vantage_python-0.3.1}/.github/workflows/pypi-publish.yml +2 -0
- {vantage_python-0.3.0 → vantage_python-0.3.1}/.github/workflows/test.yml +0 -2
- {vantage_python-0.3.0 → vantage_python-0.3.1}/PKG-INFO +1 -1
- {vantage_python-0.3.0 → vantage_python-0.3.1}/autogen.py +72 -4
- {vantage_python-0.3.0 → vantage_python-0.3.1}/pyproject.toml +1 -1
- {vantage_python-0.3.0 → vantage_python-0.3.1}/src/vantage/_async/client.py +732 -183
- {vantage_python-0.3.0 → vantage_python-0.3.1}/src/vantage/_sync/client.py +732 -183
- {vantage_python-0.3.0 → vantage_python-0.3.1}/tests/test_e2e.py +8 -8
- {vantage_python-0.3.0 → vantage_python-0.3.1}/.gitignore +0 -0
- {vantage_python-0.3.0 → vantage_python-0.3.1}/LICENSE +0 -0
- {vantage_python-0.3.0 → vantage_python-0.3.1}/Makefile +0 -0
- {vantage_python-0.3.0 → vantage_python-0.3.1}/README.md +0 -0
- {vantage_python-0.3.0 → vantage_python-0.3.1}/src/vantage/__init__.py +0 -0
- {vantage_python-0.3.0 → vantage_python-0.3.1}/src/vantage/_async/__init__.py +0 -0
- {vantage_python-0.3.0 → vantage_python-0.3.1}/src/vantage/_base.py +0 -0
- {vantage_python-0.3.0 → vantage_python-0.3.1}/src/vantage/_sync/__init__.py +0 -0
- {vantage_python-0.3.0 → vantage_python-0.3.1}/src/vantage/_types.py +0 -0
- {vantage_python-0.3.0 → vantage_python-0.3.1}/src/vantage/py.typed +0 -0
|
@@ -14,7 +14,6 @@ jobs:
|
|
|
14
14
|
with:
|
|
15
15
|
python-version: ${{ matrix.python-version }}
|
|
16
16
|
- run: pip install -e ".[dev]"
|
|
17
|
-
- run: python autogen.py
|
|
18
17
|
- run: pytest tests/test_e2e.py
|
|
19
18
|
env:
|
|
20
19
|
VANTAGE_API_TOKEN: ${{ secrets.VANTAGE_API_TOKEN }}
|
|
@@ -32,7 +31,6 @@ jobs:
|
|
|
32
31
|
with:
|
|
33
32
|
python-version: ${{ matrix.python-version }}
|
|
34
33
|
- run: pip install -e ".[dev]"
|
|
35
|
-
- run: python autogen.py
|
|
36
34
|
- run: python -c "from vantage import Client, AsyncClient"
|
|
37
35
|
|
|
38
36
|
compare-to-api:
|
|
@@ -373,6 +373,70 @@ def generate_method_name(endpoint: Endpoint, resource_name: str) -> str:
|
|
|
373
373
|
return to_snake_case(op_id)
|
|
374
374
|
|
|
375
375
|
|
|
376
|
+
def _extract_inner_type(type_hint: str, generic_prefix: str) -> str | None:
|
|
377
|
+
"""Extract inner type from simple generic forms like Prefix[Inner]."""
|
|
378
|
+
if not type_hint.startswith(generic_prefix) or not type_hint.endswith("]"):
|
|
379
|
+
return None
|
|
380
|
+
return type_hint[len(generic_prefix):-1].strip()
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def _extract_dict_value_type(type_hint: str) -> str | None:
|
|
384
|
+
"""Extract value type from Dict[str, ValueType]."""
|
|
385
|
+
if not type_hint.startswith("Dict[") or not type_hint.endswith("]"):
|
|
386
|
+
return None
|
|
387
|
+
inner = type_hint[len("Dict["):-1].strip()
|
|
388
|
+
key_and_value = inner.split(",", 1)
|
|
389
|
+
if len(key_and_value) != 2:
|
|
390
|
+
return None
|
|
391
|
+
key_type = key_and_value[0].strip()
|
|
392
|
+
value_type = key_and_value[1].strip()
|
|
393
|
+
if key_type not in {"str", "Optional[str]"}:
|
|
394
|
+
return None
|
|
395
|
+
return value_type
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def _is_model_type(type_hint: str) -> bool:
|
|
399
|
+
"""Return True for generated Pydantic model type names."""
|
|
400
|
+
return bool(re.match(r"^[A-Z][A-Za-z0-9_]*$", type_hint))
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def _append_response_mapping(lines: list[str], return_type: str, data_var: str) -> None:
|
|
404
|
+
"""Append generated code that coerces dict payloads into typed models."""
|
|
405
|
+
type_hint = return_type.strip()
|
|
406
|
+
|
|
407
|
+
optional_inner = _extract_inner_type(type_hint, "Optional[")
|
|
408
|
+
if optional_inner:
|
|
409
|
+
type_hint = optional_inner
|
|
410
|
+
|
|
411
|
+
list_inner = _extract_inner_type(type_hint, "List[")
|
|
412
|
+
if list_inner and _is_model_type(list_inner):
|
|
413
|
+
lines.extend(
|
|
414
|
+
[
|
|
415
|
+
f" if isinstance({data_var}, list):",
|
|
416
|
+
f" return [{list_inner}.model_validate(item) if isinstance(item, dict) else item for item in {data_var}]",
|
|
417
|
+
]
|
|
418
|
+
)
|
|
419
|
+
return
|
|
420
|
+
|
|
421
|
+
dict_inner = _extract_dict_value_type(type_hint)
|
|
422
|
+
if dict_inner and _is_model_type(dict_inner):
|
|
423
|
+
lines.extend(
|
|
424
|
+
[
|
|
425
|
+
f" if isinstance({data_var}, dict):",
|
|
426
|
+
f" return {{k: {dict_inner}.model_validate(v) if isinstance(v, dict) else v for k, v in {data_var}.items()}}",
|
|
427
|
+
]
|
|
428
|
+
)
|
|
429
|
+
return
|
|
430
|
+
|
|
431
|
+
if _is_model_type(type_hint):
|
|
432
|
+
lines.extend(
|
|
433
|
+
[
|
|
434
|
+
f" if isinstance({data_var}, dict):",
|
|
435
|
+
f" return {type_hint}.model_validate({data_var})",
|
|
436
|
+
]
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
|
|
376
440
|
def generate_pydantic_models(schema: dict[str, Any]) -> str:
|
|
377
441
|
"""Generate Pydantic models from OpenAPI schemas."""
|
|
378
442
|
schemas = schema.get("components", {}).get("schemas", {})
|
|
@@ -675,10 +739,12 @@ def generate_sync_method(endpoint: Endpoint, method_name: str) -> list[str]:
|
|
|
675
739
|
else:
|
|
676
740
|
lines.append(" body_data = None")
|
|
677
741
|
|
|
678
|
-
# Make request
|
|
742
|
+
# Make request and coerce response payload into typed models where possible
|
|
679
743
|
lines.append(
|
|
680
|
-
f'
|
|
744
|
+
f' data = self._client.request("{endpoint.method}", path, params=params, body=body_data)'
|
|
681
745
|
)
|
|
746
|
+
_append_response_mapping(lines, return_type, "data")
|
|
747
|
+
lines.append(" return data")
|
|
682
748
|
|
|
683
749
|
return lines
|
|
684
750
|
|
|
@@ -899,10 +965,12 @@ def generate_async_method(endpoint: Endpoint, method_name: str) -> list[str]:
|
|
|
899
965
|
else:
|
|
900
966
|
lines.append(" body_data = None")
|
|
901
967
|
|
|
902
|
-
# Make request
|
|
968
|
+
# Make request and coerce response payload into typed models where possible
|
|
903
969
|
lines.append(
|
|
904
|
-
f'
|
|
970
|
+
f' data = await self._client.request("{endpoint.method}", path, params=params, body=body_data)'
|
|
905
971
|
)
|
|
972
|
+
_append_response_mapping(lines, return_type, "data")
|
|
973
|
+
lines.append(" return data")
|
|
906
974
|
|
|
907
975
|
return lines
|
|
908
976
|
|