openapi-python-client 0.19.1__tar.gz → 0.20.0__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 (109) hide show
  1. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/PKG-INFO +4 -4
  2. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/__init__.py +5 -3
  3. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/config.py +3 -2
  4. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/const.py +3 -2
  5. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/model_property.py +22 -8
  6. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/protocol.py +2 -0
  7. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/endpoint_macros.py.jinja +2 -2
  8. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/model.py.jinja +10 -16
  9. openapi_python_client-0.20.0/openapi_python_client/templates/property_templates/any_property.py.jinja +7 -0
  10. openapi_python_client-0.20.0/openapi_python_client/templates/property_templates/boolean_property.py.jinja +11 -0
  11. openapi_python_client-0.20.0/openapi_python_client/templates/property_templates/const_property.py.jinja +5 -0
  12. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/property_templates/date_property.py.jinja +13 -5
  13. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/property_templates/datetime_property.py.jinja +13 -5
  14. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/property_templates/enum_property.py.jinja +12 -4
  15. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/property_templates/file_property.py.jinja +11 -1
  16. openapi_python_client-0.20.0/openapi_python_client/templates/property_templates/float_property.py.jinja +11 -0
  17. openapi_python_client-0.20.0/openapi_python_client/templates/property_templates/int_property.py.jinja +11 -0
  18. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/property_templates/list_property.py.jinja +25 -11
  19. openapi_python_client-0.20.0/openapi_python_client/templates/property_templates/model_property.py.jinja +47 -0
  20. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/property_templates/union_property.py.jinja +27 -3
  21. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/pyproject.toml +5 -4
  22. openapi_python_client-0.19.1/openapi_python_client/templates/property_templates/any_property.py.jinja +0 -0
  23. openapi_python_client-0.19.1/openapi_python_client/templates/property_templates/boolean_property.py.jinja +0 -3
  24. openapi_python_client-0.19.1/openapi_python_client/templates/property_templates/float_property.py.jinja +0 -3
  25. openapi_python_client-0.19.1/openapi_python_client/templates/property_templates/int_property.py.jinja +0 -3
  26. openapi_python_client-0.19.1/openapi_python_client/templates/property_templates/model_property.py.jinja +0 -32
  27. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/.gitignore +0 -0
  28. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/LICENSE +0 -0
  29. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/README.md +0 -0
  30. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/__main__.py +0 -0
  31. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/cli.py +0 -0
  32. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/__init__.py +0 -0
  33. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/bodies.py +0 -0
  34. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/errors.py +0 -0
  35. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/openapi.py +0 -0
  36. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/__init__.py +0 -0
  37. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/any.py +0 -0
  38. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/boolean.py +0 -0
  39. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/date.py +0 -0
  40. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/datetime.py +0 -0
  41. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/enum_property.py +0 -0
  42. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/file.py +0 -0
  43. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/float.py +0 -0
  44. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/int.py +0 -0
  45. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/list_property.py +0 -0
  46. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/none.py +0 -0
  47. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/property.py +0 -0
  48. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/schemas.py +0 -0
  49. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/string.py +0 -0
  50. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/properties/union.py +0 -0
  51. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/parser/responses.py +0 -0
  52. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/py.typed +0 -0
  53. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/3.0.3.md +0 -0
  54. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/3.1.0.md +0 -0
  55. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/__init__.py +0 -0
  56. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/data_type.py +0 -0
  57. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/LICENSE +0 -0
  58. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/README.md +0 -0
  59. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/__init__.py +0 -0
  60. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/callback.py +0 -0
  61. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/components.py +0 -0
  62. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/contact.py +0 -0
  63. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/discriminator.py +0 -0
  64. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/encoding.py +0 -0
  65. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/example.py +0 -0
  66. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/external_documentation.py +0 -0
  67. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/header.py +0 -0
  68. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/info.py +0 -0
  69. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/license.py +0 -0
  70. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/link.py +0 -0
  71. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/media_type.py +0 -0
  72. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/oauth_flow.py +0 -0
  73. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/oauth_flows.py +0 -0
  74. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/open_api.py +0 -0
  75. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/operation.py +0 -0
  76. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/parameter.py +0 -0
  77. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/path_item.py +0 -0
  78. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/paths.py +0 -0
  79. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/reference.py +0 -0
  80. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/request_body.py +0 -0
  81. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/response.py +0 -0
  82. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/responses.py +0 -0
  83. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/schema.py +0 -0
  84. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/security_requirement.py +0 -0
  85. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/security_scheme.py +0 -0
  86. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/server.py +0 -0
  87. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/server_variable.py +0 -0
  88. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/tag.py +0 -0
  89. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/openapi_schema_pydantic/xml.py +0 -0
  90. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/schema/parameter_location.py +0 -0
  91. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/.gitignore.jinja +0 -0
  92. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/README.md.jinja +0 -0
  93. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/api_init.py.jinja +0 -0
  94. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/client.py.jinja +0 -0
  95. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/endpoint_init.py.jinja +0 -0
  96. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/endpoint_module.py.jinja +0 -0
  97. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/errors.py.jinja +0 -0
  98. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/helpers.jinja +0 -0
  99. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/int_enum.py.jinja +0 -0
  100. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/models_init.py.jinja +0 -0
  101. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/package_init.py.jinja +0 -0
  102. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/property_templates/helpers.jinja +0 -0
  103. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/property_templates/property_macros.py.jinja +0 -0
  104. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/pyproject.toml.jinja +0 -0
  105. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/pyproject_ruff.toml.jinja +0 -0
  106. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/setup.py.jinja +0 -0
  107. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/str_enum.py.jinja +0 -0
  108. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/templates/types.py.jinja +0 -0
  109. {openapi_python_client-0.19.1 → openapi_python_client-0.20.0}/openapi_python_client/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: openapi-python-client
3
- Version: 0.19.1
3
+ Version: 0.20.0
4
4
  Summary: Generate modern Python clients from OpenAPI
5
5
  Project-URL: repository, https://github.com/openapi-generators/openapi-python-client
6
6
  Author-email: Dylan Anthony <contact@dylananthony.com>
@@ -25,10 +25,10 @@ Requires-Dist: httpx<0.28.0,>=0.20.0
25
25
  Requires-Dist: jinja2<4.0.0,>=3.0.0
26
26
  Requires-Dist: pydantic<3.0.0,>=2.1.1
27
27
  Requires-Dist: python-dateutil<3.0.0,>=2.8.1
28
- Requires-Dist: pyyaml<7.0,>=6.0
29
- Requires-Dist: ruff<0.4,>=0.2
28
+ Requires-Dist: ruamel-yaml<0.19.0,>=0.18.6
29
+ Requires-Dist: ruff<0.5,>=0.2
30
30
  Requires-Dist: shellingham<2.0.0,>=1.3.2
31
- Requires-Dist: typer<0.12,>0.6
31
+ Requires-Dist: typer<0.13,>0.6
32
32
  Requires-Dist: typing-extensions<5.0.0,>=4.8.0
33
33
  Description-Content-Type: text/markdown
34
34
 
@@ -11,8 +11,9 @@ from typing import Any, Dict, List, Optional, Sequence, Union
11
11
 
12
12
  import httpcore
13
13
  import httpx
14
- import yaml
15
14
  from jinja2 import BaseLoader, ChoiceLoader, Environment, FileSystemLoader, PackageLoader
15
+ from ruamel.yaml import YAML
16
+ from ruamel.yaml.error import YAMLError
16
17
 
17
18
  from openapi_python_client import utils
18
19
 
@@ -350,8 +351,9 @@ def _load_yaml_or_json(data: bytes, content_type: Optional[str]) -> Union[Dict[s
350
351
  return GeneratorError(header=f"Invalid JSON from provided source: {err}")
351
352
  else:
352
353
  try:
353
- return yaml.safe_load(data)
354
- except yaml.YAMLError as err:
354
+ yaml = YAML(typ="safe")
355
+ return yaml.load(data)
356
+ except YAMLError as err:
355
357
  return GeneratorError(header=f"Invalid YAML from provided source: {err}")
356
358
 
357
359
 
@@ -4,9 +4,9 @@ from enum import Enum
4
4
  from pathlib import Path
5
5
  from typing import Dict, List, Optional, Union
6
6
 
7
- import yaml
8
7
  from attr import define
9
8
  from pydantic import BaseModel
9
+ from ruamel.yaml import YAML
10
10
 
11
11
 
12
12
  class ClassOverride(BaseModel):
@@ -51,7 +51,8 @@ class ConfigFile(BaseModel):
51
51
  if mime == "application/json":
52
52
  config_data = json.loads(path.read_text())
53
53
  else:
54
- config_data = yaml.safe_load(path.read_text())
54
+ yaml = YAML(typ="safe")
55
+ config_data = yaml.load(path)
55
56
  config = ConfigFile(**config_data)
56
57
  return config
57
58
 
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, overload
3
+ from typing import Any, ClassVar, overload
4
4
 
5
5
  from attr import define
6
6
 
@@ -12,7 +12,7 @@ from .string import StringProperty
12
12
 
13
13
  @define
14
14
  class ConstProperty(PropertyProtocol):
15
- """A property representing a Union (anyOf) of other properties"""
15
+ """A property representing a const value"""
16
16
 
17
17
  name: str
18
18
  required: bool
@@ -21,6 +21,7 @@ class ConstProperty(PropertyProtocol):
21
21
  python_name: PythonIdentifier
22
22
  description: str | None
23
23
  example: None
24
+ template: ClassVar[str] = "const_property.py.jinja"
24
25
 
25
26
  @classmethod
26
27
  def build(
@@ -7,7 +7,9 @@ from attrs import define, evolve
7
7
 
8
8
  from ... import Config, utils
9
9
  from ... import schema as oai
10
+ from ...utils import PythonIdentifier
10
11
  from ..errors import ParseError, PropertyError
12
+ from .any import AnyProperty
11
13
  from .enum_property import EnumProperty
12
14
  from .protocol import PropertyProtocol, Value
13
15
  from .schemas import Class, ReferencePath, Schemas, parse_reference_path
@@ -30,7 +32,7 @@ class ModelProperty(PropertyProtocol):
30
32
  optional_properties: list[Property] | None
31
33
  relative_imports: set[str] | None
32
34
  lazy_imports: set[str] | None
33
- additional_properties: bool | Property | None
35
+ additional_properties: Property | None
34
36
  _json_type_string: ClassVar[str] = "Dict[str, Any]"
35
37
 
36
38
  template: ClassVar[str] = "model_property.py.jinja"
@@ -78,7 +80,7 @@ class ModelProperty(PropertyProtocol):
78
80
  optional_properties: list[Property] | None = None
79
81
  relative_imports: set[str] | None = None
80
82
  lazy_imports: set[str] | None = None
81
- additional_properties: bool | Property | None = None
83
+ additional_properties: Property | None = None
82
84
  if process_properties:
83
85
  data_or_err, schemas = _process_property_data(
84
86
  data=data, schemas=schemas, class_info=class_info, config=config, roots=model_roots
@@ -386,6 +388,16 @@ def _process_properties( # noqa: PLR0912, PLR0911
386
388
  )
387
389
 
388
390
 
391
+ ANY_ADDITIONAL_PROPERTY = AnyProperty.build(
392
+ name="additional",
393
+ required=True,
394
+ default=None,
395
+ description="",
396
+ python_name=PythonIdentifier(value="additional", prefix=""),
397
+ example=None,
398
+ )
399
+
400
+
389
401
  def _get_additional_properties(
390
402
  *,
391
403
  schema_additional: None | (bool | (oai.Reference | oai.Schema)),
@@ -393,18 +405,20 @@ def _get_additional_properties(
393
405
  class_name: utils.ClassName,
394
406
  config: Config,
395
407
  roots: set[ReferencePath | utils.ClassName],
396
- ) -> tuple[bool | (Property | PropertyError), Schemas]:
408
+ ) -> tuple[Property | None | PropertyError, Schemas]:
397
409
  from . import property_from_data
398
410
 
399
411
  if schema_additional is None:
400
- return True, schemas
412
+ return ANY_ADDITIONAL_PROPERTY, schemas
401
413
 
402
414
  if isinstance(schema_additional, bool):
403
- return schema_additional, schemas
415
+ if schema_additional:
416
+ return ANY_ADDITIONAL_PROPERTY, schemas
417
+ return None, schemas
404
418
 
405
419
  if isinstance(schema_additional, oai.Schema) and not any(schema_additional.model_dump().values()):
406
420
  # An empty schema
407
- return True, schemas
421
+ return ANY_ADDITIONAL_PROPERTY, schemas
408
422
 
409
423
  additional_properties, schemas = property_from_data(
410
424
  name="AdditionalProperty",
@@ -425,7 +439,7 @@ def _process_property_data(
425
439
  class_info: Class,
426
440
  config: Config,
427
441
  roots: set[ReferencePath | utils.ClassName],
428
- ) -> tuple[tuple[_PropertyData, bool | Property] | PropertyError, Schemas]:
442
+ ) -> tuple[tuple[_PropertyData, Property | None] | PropertyError, Schemas]:
429
443
  property_data = _process_properties(
430
444
  data=data, schemas=schemas, class_name=class_info.name, config=config, roots=roots
431
445
  )
@@ -442,7 +456,7 @@ def _process_property_data(
442
456
  )
443
457
  if isinstance(additional_properties, PropertyError):
444
458
  return additional_properties, schemas
445
- elif isinstance(additional_properties, bool):
459
+ elif additional_properties is None:
446
460
  pass
447
461
  else:
448
462
  property_data.relative_imports.update(additional_properties.get_imports(prefix=".."))
@@ -107,6 +107,8 @@ class PropertyProtocol(Protocol):
107
107
  """
108
108
  if json:
109
109
  type_string = self.get_base_json_type_string(quoted=quoted)
110
+ elif multipart:
111
+ type_string = "Tuple[None, bytes, str]"
110
112
  else:
111
113
  type_string = self.get_base_type_string(quoted=quoted)
112
114
 
@@ -83,8 +83,8 @@ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
83
83
  {% macro multipart_body(body, destination) %}
84
84
  {% set property = body.prop %}
85
85
  {% import "property_templates/" + property.template as prop_template %}
86
- {% if prop_template.transform_multipart %}
87
- {{ prop_template.transform_multipart(property, property.python_name, destination) }}
86
+ {% if prop_template.transform_multipart_body %}
87
+ {{ prop_template.transform_multipart_body(property, property.python_name, destination) }}
88
88
  {% endif %}
89
89
  {% endmacro %}
90
90
 
@@ -80,10 +80,10 @@ class {{ class_name }}:
80
80
  {% macro _to_dict(multipart=False) %}
81
81
  {% for property in model.required_properties + model.optional_properties %}
82
82
  {% import "property_templates/" + property.template as prop_template %}
83
- {% if prop_template.transform %}
84
- {{ prop_template.transform(property, "self." + property.python_name, property.python_name, multipart=multipart) }}
85
- {% elif multipart %}
86
- {{ property.python_name }} = self.{{ property.python_name }} if isinstance(self.{{ property.python_name }}, Unset) else (None, str(self.{{ property.python_name }}).encode(), "text/plain")
83
+ {% if multipart %}
84
+ {{ prop_template.transform_multipart(property, "self." + property.python_name, property.python_name) }}
85
+ {% elif prop_template.transform %}
86
+ {{ prop_template.transform(property=property, source="self." + property.python_name, destination=property.python_name) }}
87
87
  {% else %}
88
88
  {{ property.python_name }} = self.{{ property.python_name }}
89
89
  {% endif %}
@@ -92,19 +92,13 @@ class {{ class_name }}:
92
92
 
93
93
  field_dict: Dict[str, Any] = {}
94
94
  {% if model.additional_properties %}
95
- {% if model.additional_properties.template %}{# Can be a bool instead of an object #}
96
- {% import "property_templates/" + model.additional_properties.template as prop_template %}
97
- {% else %}
98
- {% set prop_template = None %}
99
- {% endif %}
100
- {% if prop_template and prop_template.transform %}
95
+ {% import "property_templates/" + model.additional_properties.template as prop_template %}
96
+ {% if multipart %}
101
97
  for prop_name, prop in self.additional_properties.items():
102
- {{ prop_template.transform(model.additional_properties, "prop", "field_dict[prop_name]", multipart=multipart, declare_type=false) | indent(4) }}
103
- {% elif multipart %}
104
- field_dict.update({
105
- key: (None, str(value).encode(), "text/plain")
106
- for key, value in self.additional_properties.items()
107
- })
98
+ {{ prop_template.transform_multipart(model.additional_properties, "prop", "field_dict[prop_name]") | indent(4) }}
99
+ {% elif prop_template.transform %}
100
+ for prop_name, prop in self.additional_properties.items():
101
+ {{ prop_template.transform(model.additional_properties, "prop", "field_dict[prop_name]", declare_type=false) | indent(4) }}
108
102
  {% else %}
109
103
  field_dict.update(self.additional_properties)
110
104
  {% endif %}
@@ -0,0 +1,7 @@
1
+ {% macro transform_multipart(property, source, destination) %}
2
+ {% if not property.required %}
3
+ {{ destination }} = {{source}} if isinstance({{source}}, Unset) else (None, str({{source}}).encode(), "text/plain")
4
+ {% else %}
5
+ {{ destination }} = (None, str({{ source }}).encode(), "text/plain")
6
+ {% endif %}
7
+ {% endmacro %}
@@ -0,0 +1,11 @@
1
+ {% macro transform_header(source) %}
2
+ "true" if {{ source }} else "false"
3
+ {% endmacro %}
4
+
5
+ {% macro transform_multipart(property, source, destination) %}
6
+ {% if not property.required %}
7
+ {{ destination }} = {{source}} if isinstance({{source}}, Unset) else (None, str({{source}}).encode(), "text/plain")
8
+ {% else %}
9
+ {{ destination }} = (None, str({{ source }}).encode(), "text/plain")
10
+ {% endif %}
11
+ {% endmacro %}
@@ -0,0 +1,5 @@
1
+ {% macro construct(property, source) %}
2
+ {{ property.python_name }} = cast({{ property.get_type_string() }} , {{ source }})
3
+ if {{ property.python_name }} != {{ property.value }}{% if not property.required %}and not isinstance({{ property.python_name }}, Unset){% endif %}:
4
+ raise ValueError(f"{{ property.name }} must match const {{ property.value }}, got '{{'{' + property.python_name + '}' }}'")
5
+ {%- endmacro %}
@@ -10,17 +10,13 @@ isoparse({{ source }}).date()
10
10
 
11
11
  {% macro check_type_for_construct(property, source) %}isinstance({{ source }}, str){% endmacro %}
12
12
 
13
- {% macro transform(property, source, destination, declare_type=True, multipart=False) %}
13
+ {% macro transform(property, source, destination, declare_type=True) %}
14
14
  {% set transformed = source + ".isoformat()" %}
15
- {% if multipart %}{# Multipart data must be bytes, not str #}
16
- {% set transformed = transformed + ".encode()" %}
17
- {% endif %}
18
15
  {% if property.required %}
19
16
  {{ destination }} = {{ transformed }}
20
17
  {%- else %}
21
18
  {% if declare_type %}
22
19
  {% set type_annotation = property.get_type_string(json=True) %}
23
- {% if multipart %}{% set type_annotation = type_annotation | replace("str", "bytes") %}{% endif %}
24
20
  {{ destination }}: {{ type_annotation }} = UNSET
25
21
  {% else %}
26
22
  {{ destination }} = UNSET
@@ -29,3 +25,15 @@ if not isinstance({{ source }}, Unset):
29
25
  {{ destination }} = {{ transformed }}
30
26
  {%- endif %}
31
27
  {% endmacro %}
28
+
29
+ {% macro transform_multipart(property, source, destination) %}
30
+ {% set transformed = source + ".isoformat().encode()" %}
31
+ {% if property.required %}
32
+ {{ destination }} = {{ transformed }}
33
+ {%- else %}
34
+ {% set type_annotation = property.get_type_string(json=True) | replace("str", "bytes") %}
35
+ {{ destination }}: {{ type_annotation }} = UNSET
36
+ if not isinstance({{ source }}, Unset):
37
+ {{ destination }} = {{ transformed }}
38
+ {%- endif %}
39
+ {% endmacro %}
@@ -10,17 +10,13 @@ isoparse({{ source }})
10
10
 
11
11
  {% macro check_type_for_construct(property, source) %}isinstance({{ source }}, str){% endmacro %}
12
12
 
13
- {% macro transform(property, source, destination, declare_type=True, multipart=False) %}
13
+ {% macro transform(property, source, destination, declare_type=True) %}
14
14
  {% set transformed = source + ".isoformat()" %}
15
- {% if multipart %}{# Multipart data must be bytes, not str #}
16
- {% set transformed = transformed + ".encode()" %}
17
- {% endif %}
18
15
  {% if property.required %}
19
16
  {{ destination }} = {{ transformed }}
20
17
  {%- else %}
21
18
  {% if declare_type %}
22
19
  {% set type_annotation = property.get_type_string(json=True) %}
23
- {% if multipart %}{% set type_annotation = type_annotation | replace("str", "bytes") %}{% endif %}
24
20
  {{ destination }}: {{ type_annotation }} = UNSET
25
21
  {% else %}
26
22
  {{ destination }} = UNSET
@@ -29,3 +25,15 @@ if not isinstance({{ source }}, Unset):
29
25
  {{ destination }} = {{ transformed }}
30
26
  {%- endif %}
31
27
  {% endmacro %}
28
+
29
+ {% macro transform_multipart(property, source, destination) %}
30
+ {% set transformed = source + ".isoformat().encode()" %}
31
+ {% if property.required %}
32
+ {{ destination }} = {{ transformed }}
33
+ {%- else %}
34
+ {% set type_annotation = property.get_type_string(json=True) | replace("str", "bytes") %}
35
+ {{ destination }}: {{ type_annotation }} = UNSET
36
+ if not isinstance({{ source }}, Unset):
37
+ {{ destination }} = {{ transformed }}
38
+ {%- endif %}
39
+ {% endmacro %}
@@ -13,10 +13,6 @@
13
13
  {% macro transform(property, source, destination, declare_type=True, multipart=False) %}
14
14
  {% set transformed = source + ".value" %}
15
15
  {% set type_string = property.get_type_string(json=True) %}
16
- {% if multipart %}
17
- {% set transformed = "(None, str(" + transformed + ").encode(), \"text/plain\")" %}
18
- {% set type_string = "Union[Unset, Tuple[None, bytes, str]]" %}
19
- {% endif %}
20
16
  {% if property.required %}
21
17
  {{ destination }} = {{ transformed }}
22
18
  {%- else %}
@@ -26,6 +22,18 @@ if not isinstance({{ source }}, Unset):
26
22
  {% endif %}
27
23
  {% endmacro %}
28
24
 
25
+ {% macro transform_multipart(property, source, destination) %}
26
+ {% set transformed = "(None, str(" + source + ".value" + ").encode(), \"text/plain\")" %}
27
+ {% set type_string = "Union[Unset, Tuple[None, bytes, str]]" %}
28
+ {% if property.required %}
29
+ {{ destination }} = {{ transformed }}
30
+ {%- else %}
31
+ {{ destination }}: {{ type_string }} = UNSET
32
+ if not isinstance({{ source }}, Unset):
33
+ {{ destination }} = {{ transformed }}
34
+ {% endif %}
35
+ {% endmacro %}
36
+
29
37
  {% macro transform_header(source) %}
30
38
  str({{ source }})
31
39
  {% endmacro %}
@@ -12,7 +12,7 @@ File(
12
12
 
13
13
  {% macro check_type_for_construct(property, source) %}isinstance({{ source }}, bytes){% endmacro %}
14
14
 
15
- {% macro transform(property, source, destination, declare_type=True, multipart=False) %}
15
+ {% macro transform(property, source, destination, declare_type=True) %}
16
16
  {% if property.required %}
17
17
  {{ destination }} = {{ source }}.to_tuple()
18
18
  {% else %}
@@ -21,3 +21,13 @@ if not isinstance({{ source }}, Unset):
21
21
  {{ destination }} = {{ source }}.to_tuple()
22
22
  {% endif %}
23
23
  {% endmacro %}
24
+
25
+ {% macro transform_multipart(property, source, destination) %}
26
+ {% if property.required %}
27
+ {{ destination }} = {{ source }}.to_tuple()
28
+ {% else %}
29
+ {{ destination }}: {{ property.get_type_string(json=True) }} = UNSET
30
+ if not isinstance({{ source }}, Unset):
31
+ {{ destination }} = {{ source }}.to_tuple()
32
+ {% endif %}
33
+ {% endmacro %}
@@ -0,0 +1,11 @@
1
+ {% macro transform_header(source) %}
2
+ str({{ source }})
3
+ {% endmacro %}
4
+
5
+ {% macro transform_multipart(property, source, destination) %}
6
+ {% if not property.required %}
7
+ {{ destination }} = {{source}} if isinstance({{source}}, Unset) else (None, str({{source}}).encode(), "text/plain")
8
+ {% else %}
9
+ {{ destination }} = (None, str({{ source }}).encode(), "text/plain")
10
+ {% endif %}
11
+ {% endmacro %}
@@ -0,0 +1,11 @@
1
+ {% macro transform_header(source) %}
2
+ str({{ source }})
3
+ {% endmacro %}
4
+
5
+ {% macro transform_multipart(property, source, destination) %}
6
+ {% if not property.required %}
7
+ {{ destination }} = {{source}} if isinstance({{source}}, Unset) else (None, str({{source}}).encode(), "text/plain")
8
+ {% else %}
9
+ {{ destination }} = (None, str({{ source }}).encode(), "text/plain")
10
+ {% endif %}
11
+ {% endmacro %}
@@ -40,24 +40,38 @@ for {{ inner_source }} in {{ source }}:
40
40
 
41
41
  {% macro check_type_for_construct(property, source) %}isinstance({{ source }}, list){% endmacro %}
42
42
 
43
- {% macro transform(property, source, destination, declare_type=True, multipart=False, transform_method="to_dict") %}
43
+ {% macro transform(property, source, destination, declare_type=True) %}
44
44
  {% set inner_property = property.inner_property %}
45
- {% if multipart %}
46
- {% set type_string = "Union[Unset, Tuple[None, bytes, str]]" %}
47
- {% else %}
48
- {% set type_string = property.get_type_string(json=True) %}
49
- {% endif %}
45
+ {% set type_string = property.get_type_string(json=True) %}
50
46
  {% if property.required %}
51
- {{ _transform(property, source, destination, multipart, transform_method) }}
47
+ {{ _transform(property, source, destination, False, "to_dict") }}
52
48
  {% else %}
53
49
  {{ destination }}{% if declare_type %}: {{ type_string }}{% endif %} = UNSET
54
50
  if not isinstance({{ source }}, Unset):
55
- {{ _transform(property, source, destination, multipart, transform_method) | indent(4)}}
51
+ {{ _transform(property, source, destination, False, "to_dict") | indent(4)}}
56
52
  {% endif %}
57
-
58
-
59
53
  {% endmacro %}
60
54
 
61
55
  {% macro transform_multipart(property, source, destination) %}
62
- {{ transform(property, source, destination, transform_method="to_multipart") }}
56
+ {% set inner_property = property.inner_property %}
57
+ {% set type_string = "Union[Unset, Tuple[None, bytes, str]]" %}
58
+ {% if property.required %}
59
+ {{ _transform(property, source, destination, True, "to_dict") }}
60
+ {% else %}
61
+ {{ destination }}: {{ type_string }} = UNSET
62
+ if not isinstance({{ source }}, Unset):
63
+ {{ _transform(property, source, destination, True, "to_dict") | indent(4)}}
64
+ {% endif %}
65
+ {% endmacro %}
66
+
67
+ {% macro transform_multipart_body(property, source, destination) %}
68
+ {% set inner_property = property.inner_property %}
69
+ {% set type_string = property.get_type_string(json=True) %}
70
+ {% if property.required %}
71
+ {{ _transform(property, source, destination, False, "to_multipart") }}
72
+ {% else %}
73
+ {{ destination }}: {{ type_string }} = UNSET
74
+ if not isinstance({{ source }}, Unset):
75
+ {{ _transform(property, source, destination, False, "to_multipart") | indent(4)}}
76
+ {% endif %}
63
77
  {% endmacro %}
@@ -0,0 +1,47 @@
1
+ {% macro construct_function(property, source) %}
2
+ {{ property.class_info.name }}.from_dict({{ source }})
3
+ {% endmacro %}
4
+
5
+ {% from "property_templates/property_macros.py.jinja" import construct_template %}
6
+
7
+ {% macro construct(property, source) %}
8
+ {{ construct_template(construct_function, property, source) }}
9
+ {% endmacro %}
10
+
11
+ {% macro check_type_for_construct(property, source) %}isinstance({{ source }}, dict){% endmacro %}
12
+
13
+ {% macro transform(property, source, destination, declare_type=True) %}
14
+ {% set transformed = source + ".to_dict()" %}
15
+ {% set type_string = property.get_type_string(json=True) %}
16
+ {% if property.required %}
17
+ {{ destination }} = {{ transformed }}
18
+ {%- else %}
19
+ {{ destination }}{% if declare_type %}: {{ type_string }}{% endif %} = UNSET
20
+ if not isinstance({{ source }}, Unset):
21
+ {{ destination }} = {{ transformed }}
22
+ {%- endif %}
23
+ {% endmacro %}
24
+
25
+ {% macro transform_multipart_body(property, source, destination) %}
26
+ {% set transformed = source + ".to_multipart()" %}
27
+ {% set type_string = property.get_type_string(multipart=True) %}
28
+ {% if property.required %}
29
+ {{ destination }} = {{ transformed }}
30
+ {%- else %}
31
+ {{ destination }}: {{ type_string }} = UNSET
32
+ if not isinstance({{ source }}, Unset):
33
+ {{ destination }} = {{ transformed }}
34
+ {%- endif %}
35
+ {% endmacro %}
36
+
37
+ {% macro transform_multipart(property, source, destination) %}
38
+ {% set transformed = "(None, json.dumps(" + source + ".to_dict()" + ").encode(), 'application/json')" %}
39
+ {% set type_string = property.get_type_string(multipart=True) %}
40
+ {% if property.required %}
41
+ {{ destination }} = {{ transformed }}
42
+ {%- else %}
43
+ {{ destination }}: {{ type_string }} = UNSET
44
+ if not isinstance({{ source }}, Unset):
45
+ {{ destination }} = {{ transformed }}
46
+ {%- endif %}
47
+ {% endmacro %}
@@ -39,9 +39,9 @@ def _parse_{{ property.python_name }}(data: object) -> {{ property.get_type_stri
39
39
  {{ property.python_name }} = _parse_{{ property.python_name }}({{ source }})
40
40
  {% endmacro %}
41
41
 
42
- {% macro transform(property, source, destination, declare_type=True, multipart=False) %}
42
+ {% macro transform(property, source, destination, declare_type=True) %}
43
43
  {% set ns = namespace(contains_properties_without_transform = false, contains_modified_properties = not property.required, has_if = false) %}
44
- {% if declare_type %}{{ destination }}: {{ property.get_type_string(json=not multipart, multipart=multipart) }}{% endif %}
44
+ {% if declare_type %}{{ destination }}: {{ property.get_type_string(json=True, multipart=False) }}{% endif %}
45
45
 
46
46
  {% if not property.required %}
47
47
  if isinstance({{ source }}, Unset):
@@ -64,7 +64,7 @@ elif isinstance({{ source }}, {{ inner_property.get_instance_type_string() }}):
64
64
  {% else %}
65
65
  else:
66
66
  {% endif %}
67
- {{ inner_template.transform(inner_property, source, destination, declare_type=False, multipart=multipart) | indent(4) }}
67
+ {{ inner_template.transform(inner_property, source, destination, declare_type=False) | indent(4) }}
68
68
  {% endfor %}
69
69
  {% if ns.contains_properties_without_transform and ns.contains_modified_properties %}
70
70
  else:
@@ -73,3 +73,27 @@ else:
73
73
  {{ destination }} = {{ source }}
74
74
  {%- endif %}
75
75
  {% endmacro %}
76
+
77
+
78
+ {% macro transform_multipart(property, source, destination) %}
79
+ {% set ns = namespace(has_if = false) %}
80
+ {{ destination }}: {{ property.get_type_string(json=False, multipart=True) }}
81
+
82
+ {% if not property.required %}
83
+ if isinstance({{ source }}, Unset):
84
+ {{ destination }} = UNSET
85
+ {% set ns.has_if = true %}
86
+ {% endif %}
87
+ {% for inner_property in property.inner_properties %}
88
+ {% if not ns.has_if %}
89
+ if isinstance({{ source }}, {{ inner_property.get_instance_type_string() }}):
90
+ {% set ns.has_if = true %}
91
+ {% elif not loop.last %}
92
+ elif isinstance({{ source }}, {{ inner_property.get_instance_type_string() }}):
93
+ {% else %}
94
+ else:
95
+ {% endif %}
96
+ {% import "property_templates/" + inner_property.template as inner_template %}
97
+ {{ inner_template.transform_multipart(inner_property, source, destination) | indent(4) | trim }}
98
+ {% endfor %}
99
+ {% endmacro %}
@@ -6,19 +6,19 @@ license = { text = "MIT" }
6
6
  requires-python = ">=3.8,<4.0"
7
7
  dependencies = [
8
8
  "jinja2>=3.0.0,<4.0.0",
9
- "typer>0.6,<0.12",
9
+ "typer>0.6,<0.13",
10
10
  "colorama>=0.4.3; sys_platform == \"win32\"",
11
11
  "shellingham>=1.3.2,<2.0.0",
12
12
  "pydantic>=2.1.1,<3.0.0",
13
13
  "attrs>=21.3.0",
14
14
  "python-dateutil>=2.8.1,<3.0.0",
15
15
  "httpx>=0.20.0,<0.28.0",
16
- "PyYAML>=6.0,<7.0",
17
- "ruff>=0.2,<0.4",
16
+ "ruamel.yaml>=0.18.6,<0.19.0",
17
+ "ruff>=0.2,<0.5",
18
18
  "typing-extensions>=4.8.0,<5.0.0",
19
19
  ]
20
20
  name = "openapi-python-client"
21
- version = "0.19.1"
21
+ version = "0.20.0"
22
22
  description = "Generate modern Python clients from OpenAPI"
23
23
  keywords = [
24
24
  "OpenAPI",
@@ -97,6 +97,7 @@ dev = [
97
97
  "types-PyYAML<7.0.0,>=6.0.3",
98
98
  "types-certifi<2021.10.9,>=2020.0.0",
99
99
  "types-python-dateutil<3.0.0,>=2.0.0",
100
+ "ruamel-yaml-string>=0.1.1",
100
101
  ]
101
102
 
102
103
  [tool.pdm.build]
@@ -1,3 +0,0 @@
1
- {% macro transform_header(source) %}
2
- "true" if {{ source }} else "false"
3
- {% endmacro %}
@@ -1,3 +0,0 @@
1
- {% macro transform_header(source) %}
2
- str({{ source }})
3
- {% endmacro %}
@@ -1,3 +0,0 @@
1
- {% macro transform_header(source) %}
2
- str({{ source }})
3
- {% endmacro %}
@@ -1,32 +0,0 @@
1
- {% macro construct_function(property, source) %}
2
- {{ property.class_info.name }}.from_dict({{ source }})
3
- {% endmacro %}
4
-
5
- {% from "property_templates/property_macros.py.jinja" import construct_template %}
6
-
7
- {% macro construct(property, source) %}
8
- {{ construct_template(construct_function, property, source) }}
9
- {% endmacro %}
10
-
11
- {% macro check_type_for_construct(property, source) %}isinstance({{ source }}, dict){% endmacro %}
12
-
13
- {% macro transform(property, source, destination, declare_type=True, multipart=False, transform_method="to_dict") %}
14
- {% set transformed = source + "." + transform_method + "()" %}
15
- {% if multipart %}
16
- {% set transformed = "(None, json.dumps(" + transformed + ").encode(), 'application/json')" %}
17
- {% set type_string = property.get_type_string(multipart=True) %}
18
- {% else %}
19
- {% set type_string = property.get_type_string(json=True) %}
20
- {% endif %}
21
- {% if property.required %}
22
- {{ destination }} = {{ transformed }}
23
- {%- else %}
24
- {{ destination }}{% if declare_type %}: {{ type_string }}{% endif %} = UNSET
25
- if not isinstance({{ source }}, Unset):
26
- {{ destination }} = {{ transformed }}
27
- {%- endif %}
28
- {% endmacro %}
29
-
30
- {% macro transform_multipart(property, source, destination) %}
31
- {{ transform(property, source, destination, transform_method="to_multipart") }}
32
- {% endmacro %}