openapi-python-client 0.28.4__py3-none-any.whl → 0.29.1__py3-none-any.whl

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 (92) hide show
  1. openapi_python_client/__init__.py +26 -17
  2. openapi_python_client/cli.py +1 -2
  3. openapi_python_client/config.py +5 -3
  4. openapi_python_client/parser/bodies.py +14 -23
  5. openapi_python_client/parser/openapi.py +58 -48
  6. openapi_python_client/parser/properties/__init__.py +34 -33
  7. openapi_python_client/parser/properties/any.py +11 -10
  8. openapi_python_client/parser/properties/boolean.py +13 -13
  9. openapi_python_client/parser/properties/const.py +11 -10
  10. openapi_python_client/parser/properties/date.py +15 -14
  11. openapi_python_client/parser/properties/datetime.py +15 -14
  12. openapi_python_client/parser/properties/enum_property.py +23 -20
  13. openapi_python_client/parser/properties/file.py +11 -10
  14. openapi_python_client/parser/properties/float.py +13 -13
  15. openapi_python_client/parser/properties/int.py +11 -11
  16. openapi_python_client/parser/properties/list_property.py +22 -22
  17. openapi_python_client/parser/properties/literal_enum_property.py +20 -20
  18. openapi_python_client/parser/properties/merge_properties.py +9 -6
  19. openapi_python_client/parser/properties/model_property.py +34 -33
  20. openapi_python_client/parser/properties/none.py +11 -11
  21. openapi_python_client/parser/properties/protocol.py +42 -32
  22. openapi_python_client/parser/properties/schemas.py +30 -23
  23. openapi_python_client/parser/properties/string.py +10 -11
  24. openapi_python_client/parser/properties/union.py +24 -22
  25. openapi_python_client/parser/properties/uuid.py +11 -11
  26. openapi_python_client/parser/responses.py +30 -23
  27. openapi_python_client/schema/__init__.py +2 -1
  28. openapi_python_client/schema/data_type.py +2 -2
  29. openapi_python_client/schema/openapi_schema_pydantic/callback.py +3 -1
  30. openapi_python_client/schema/openapi_schema_pydantic/components.py +10 -9
  31. openapi_python_client/schema/openapi_schema_pydantic/contact.py +5 -3
  32. openapi_python_client/schema/openapi_schema_pydantic/discriminator.py +4 -2
  33. openapi_python_client/schema/openapi_schema_pydantic/encoding.py +4 -3
  34. openapi_python_client/schema/openapi_schema_pydantic/example.py +5 -3
  35. openapi_python_client/schema/openapi_schema_pydantic/external_documentation.py +4 -2
  36. openapi_python_client/schema/openapi_schema_pydantic/header.py +20 -6
  37. openapi_python_client/schema/openapi_schema_pydantic/info.py +5 -4
  38. openapi_python_client/schema/openapi_schema_pydantic/license.py +4 -2
  39. openapi_python_client/schema/openapi_schema_pydantic/link.py +5 -4
  40. openapi_python_client/schema/openapi_schema_pydantic/media_type.py +3 -2
  41. openapi_python_client/schema/openapi_schema_pydantic/oauth_flow.py +6 -4
  42. openapi_python_client/schema/openapi_schema_pydantic/open_api.py +5 -3
  43. openapi_python_client/schema/openapi_schema_pydantic/operation.py +6 -5
  44. openapi_python_client/schema/openapi_schema_pydantic/parameter.py +6 -5
  45. openapi_python_client/schema/openapi_schema_pydantic/path_item.py +5 -3
  46. openapi_python_client/schema/openapi_schema_pydantic/paths.py +2 -1
  47. openapi_python_client/schema/openapi_schema_pydantic/reference.py +3 -1
  48. openapi_python_client/schema/openapi_schema_pydantic/request_body.py +3 -2
  49. openapi_python_client/schema/openapi_schema_pydantic/response.py +5 -4
  50. openapi_python_client/schema/openapi_schema_pydantic/responses.py +2 -1
  51. openapi_python_client/schema/openapi_schema_pydantic/schema.py +7 -6
  52. openapi_python_client/schema/openapi_schema_pydantic/security_requirement.py +3 -1
  53. openapi_python_client/schema/openapi_schema_pydantic/security_scheme.py +8 -7
  54. openapi_python_client/schema/openapi_schema_pydantic/server.py +4 -3
  55. openapi_python_client/schema/openapi_schema_pydantic/server_variable.py +5 -3
  56. openapi_python_client/schema/openapi_schema_pydantic/tag.py +3 -2
  57. openapi_python_client/schema/openapi_schema_pydantic/xml.py +5 -3
  58. openapi_python_client/schema/parameter_location.py +7 -22
  59. openapi_python_client/schema/ref.py +52 -0
  60. openapi_python_client/schema/untrusted_string.py +56 -0
  61. openapi_python_client/strings.py +245 -0
  62. openapi_python_client/templates/README.md.jinja +3 -3
  63. openapi_python_client/templates/client.py.jinja +5 -5
  64. openapi_python_client/templates/endpoint_macros.py.jinja +18 -18
  65. openapi_python_client/templates/endpoint_module.py.jinja +20 -14
  66. openapi_python_client/templates/helpers.jinja +3 -7
  67. openapi_python_client/templates/literal_enum.py.jinja +3 -3
  68. openapi_python_client/templates/model.py.jinja +18 -18
  69. openapi_python_client/templates/package_init.py.jinja +2 -2
  70. openapi_python_client/templates/property_templates/const_property.py.jinja +3 -3
  71. openapi_python_client/templates/property_templates/date_property.py.jinja +2 -2
  72. openapi_python_client/templates/property_templates/datetime_property.py.jinja +2 -2
  73. openapi_python_client/templates/property_templates/enum_property.py.jinja +1 -1
  74. openapi_python_client/templates/property_templates/file_property.py.jinja +1 -1
  75. openapi_python_client/templates/property_templates/list_property.py.jinja +3 -3
  76. openapi_python_client/templates/property_templates/literal_enum_property.py.jinja +2 -2
  77. openapi_python_client/templates/property_templates/model_property.py.jinja +1 -1
  78. openapi_python_client/templates/property_templates/property_macros.py.jinja +1 -1
  79. openapi_python_client/templates/property_templates/union_property.py.jinja +9 -9
  80. openapi_python_client/templates/property_templates/uuid_property.py.jinja +1 -1
  81. openapi_python_client/templates/pyproject_pdm.toml.jinja +4 -5
  82. openapi_python_client/templates/pyproject_poetry.toml.jinja +4 -5
  83. openapi_python_client/templates/pyproject_uv.toml.jinja +5 -6
  84. openapi_python_client/templates/setup.py.jinja +4 -4
  85. openapi_python_client/templates/str_enum.py.jinja +2 -2
  86. {openapi_python_client-0.28.4.dist-info → openapi_python_client-0.29.1.dist-info}/METADATA +6 -9
  87. openapi_python_client-0.29.1.dist-info/RECORD +115 -0
  88. {openapi_python_client-0.28.4.dist-info → openapi_python_client-0.29.1.dist-info}/WHEEL +1 -1
  89. openapi_python_client/utils.py +0 -122
  90. openapi_python_client-0.28.4.dist-info/RECORD +0 -113
  91. {openapi_python_client-0.28.4.dist-info → openapi_python_client-0.29.1.dist-info}/entry_points.txt +0 -0
  92. {openapi_python_client-0.28.4.dist-info → openapi_python_client-0.29.1.dist-info}/licenses/LICENSE +0 -0
@@ -18,8 +18,10 @@ from collections.abc import Iterable
18
18
 
19
19
  from attrs import evolve
20
20
 
21
- from ... import Config, utils
21
+ from ... import Config, strings
22
22
  from ... import schema as oai
23
+ from ...schema.ref import Ref
24
+ from ...schema.untrusted_string import UntrustedString
23
25
  from ..errors import ParameterError, ParseError, PropertyError
24
26
  from .any import AnyProperty
25
27
  from .boolean import BooleanProperty
@@ -51,11 +53,11 @@ from .uuid import UuidProperty
51
53
 
52
54
 
53
55
  def _string_based_property(
54
- name: str, required: bool, data: oai.Schema, config: Config
56
+ name: UntrustedString, required: bool, data: oai.Schema, config: Config
55
57
  ) -> StringProperty | DateProperty | DateTimeProperty | FileProperty | UuidProperty | PropertyError:
56
58
  """Construct a Property from the type "string" """
57
59
  string_format = data.schema_format
58
- python_name = utils.PythonIdentifier(value=name, prefix=config.field_prefix)
60
+ python_name = strings.PythonIdentifier(value=name, prefix=config.field_prefix)
59
61
  if string_format == "date-time":
60
62
  return DateTimeProperty.build(
61
63
  name=name,
@@ -103,16 +105,16 @@ def _string_based_property(
103
105
 
104
106
 
105
107
  def _property_from_ref(
106
- name: str,
108
+ name: UntrustedString,
107
109
  required: bool,
108
110
  parent: oai.Schema | None,
109
111
  data: oai.Reference,
110
112
  schemas: Schemas,
111
113
  config: Config,
112
- roots: set[ReferencePath | utils.ClassName],
114
+ roots: set[ReferencePath | strings.ClassName],
113
115
  ) -> tuple[Property | PropertyError, Schemas]:
114
116
  ref_path = parse_reference_path(data.ref)
115
- if isinstance(ref_path, ParseError):
117
+ if isinstance(ref_path, ParseError): # pragma: no cover
116
118
  return PropertyError(data=data, detail=ref_path.detail), schemas
117
119
  existing = schemas.classes_by_reference.get(ref_path)
118
120
  if not existing:
@@ -130,7 +132,7 @@ def _property_from_ref(
130
132
  existing,
131
133
  required=required,
132
134
  name=name,
133
- python_name=utils.PythonIdentifier(value=name, prefix=config.field_prefix),
135
+ python_name=strings.PythonIdentifier(value=name, prefix=config.field_prefix),
134
136
  default=default, # type: ignore # mypy can't tell that default comes from the same class...
135
137
  )
136
138
 
@@ -139,18 +141,17 @@ def _property_from_ref(
139
141
 
140
142
 
141
143
  def property_from_data( # noqa: PLR0911, PLR0912
142
- name: str,
144
+ name: UntrustedString,
143
145
  required: bool,
144
146
  data: oai.Reference | oai.Schema,
145
147
  schemas: Schemas,
146
148
  parent_name: str,
147
149
  config: Config,
148
150
  process_properties: bool = True,
149
- roots: set[ReferencePath | utils.ClassName] | None = None,
151
+ roots: set[ReferencePath | strings.ClassName] | None = None,
150
152
  ) -> tuple[Property | PropertyError, Schemas]:
151
153
  """Generate a Property from the OpenAPI dictionary representation of it"""
152
154
  roots = roots or set()
153
- name = utils.remove_string_escapes(name)
154
155
  if isinstance(data, oai.Reference):
155
156
  return _property_from_ref(
156
157
  name=name,
@@ -190,7 +191,7 @@ def property_from_data( # noqa: PLR0911, PLR0912
190
191
  name=name,
191
192
  required=required,
192
193
  default=data.default,
193
- python_name=utils.PythonIdentifier(value=name, prefix=config.field_prefix),
194
+ python_name=strings.PythonIdentifier(value=name, prefix=config.field_prefix),
194
195
  description=data.description,
195
196
  example=data.example,
196
197
  ),
@@ -230,7 +231,7 @@ def property_from_data( # noqa: PLR0911, PLR0912
230
231
  required=required,
231
232
  default=data.default,
232
233
  const=data.const,
233
- python_name=utils.PythonIdentifier(value=name, prefix=config.field_prefix),
234
+ python_name=strings.PythonIdentifier(value=name, prefix=config.field_prefix),
234
235
  description=data.description,
235
236
  ),
236
237
  schemas,
@@ -246,7 +247,7 @@ def property_from_data( # noqa: PLR0911, PLR0912
246
247
  name=name,
247
248
  default=data.default,
248
249
  required=required,
249
- python_name=utils.PythonIdentifier(value=name, prefix=config.field_prefix),
250
+ python_name=strings.PythonIdentifier(value=name, prefix=config.field_prefix),
250
251
  description=data.description,
251
252
  example=data.example,
252
253
  ),
@@ -258,7 +259,7 @@ def property_from_data( # noqa: PLR0911, PLR0912
258
259
  name=name,
259
260
  default=data.default,
260
261
  required=required,
261
- python_name=utils.PythonIdentifier(value=name, prefix=config.field_prefix),
262
+ python_name=strings.PythonIdentifier(value=name, prefix=config.field_prefix),
262
263
  description=data.description,
263
264
  example=data.example,
264
265
  ),
@@ -270,7 +271,7 @@ def property_from_data( # noqa: PLR0911, PLR0912
270
271
  name=name,
271
272
  required=required,
272
273
  default=None,
273
- python_name=utils.PythonIdentifier(value=name, prefix=config.field_prefix),
274
+ python_name=strings.PythonIdentifier(value=name, prefix=config.field_prefix),
274
275
  description=data.description,
275
276
  example=data.example,
276
277
  ),
@@ -303,7 +304,7 @@ def property_from_data( # noqa: PLR0911, PLR0912
303
304
  name=name,
304
305
  required=required,
305
306
  default=data.default,
306
- python_name=utils.PythonIdentifier(value=name, prefix=config.field_prefix),
307
+ python_name=strings.PythonIdentifier(value=name, prefix=config.field_prefix),
307
308
  description=data.description,
308
309
  example=data.example,
309
310
  ),
@@ -313,11 +314,11 @@ def property_from_data( # noqa: PLR0911, PLR0912
313
314
 
314
315
  def _create_schemas(
315
316
  *,
316
- components: dict[str, oai.Reference | oai.Schema],
317
+ components: dict[UntrustedString, oai.Reference | oai.Schema],
317
318
  schemas: Schemas,
318
319
  config: Config,
319
320
  ) -> Schemas:
320
- to_process: Iterable[tuple[str, oai.Reference | oai.Schema]] = components.items()
321
+ to_process: Iterable[tuple[UntrustedString, oai.Reference | oai.Schema]] = components.items()
321
322
  still_making_progress = True
322
323
  errors: list[PropertyError] = []
323
324
 
@@ -325,12 +326,12 @@ def _create_schemas(
325
326
  while still_making_progress:
326
327
  still_making_progress = False
327
328
  errors = []
328
- next_round: list[tuple[str, oai.Reference | oai.Schema]] = []
329
+ next_round: list[tuple[UntrustedString, oai.Reference | oai.Schema]] = []
329
330
  # Only accumulate errors from the last round, since we might fix some along the way
330
331
  for name, data in to_process:
331
332
  schema_data: oai.Reference | oai.Schema | None = data
332
- ref_path = parse_reference_path(f"#/components/schemas/{name}")
333
- if isinstance(ref_path, ParseError):
333
+ ref_path = parse_reference_path(Ref(f"#/components/schemas/{name.get_untrusted_value()}"))
334
+ if isinstance(ref_path, ParseError): # pragma: no cover
334
335
  schemas.errors.append(PropertyError(detail=ref_path.detail, data=data))
335
336
  continue
336
337
  if isinstance(data, oai.Reference):
@@ -361,13 +362,13 @@ def _create_schemas(
361
362
  return schemas
362
363
 
363
364
 
364
- def _propogate_removal(*, root: ReferencePath | utils.ClassName, schemas: Schemas, error: PropertyError) -> None:
365
- if isinstance(root, utils.ClassName):
365
+ def _propogate_removal(*, root: ReferencePath | strings.ClassName, schemas: Schemas, error: PropertyError) -> None:
366
+ if isinstance(root, strings.ClassName):
366
367
  schemas.classes_by_name.pop(root, None)
367
368
  return
368
369
  if root in schemas.classes_by_reference:
369
370
  error.detail = error.detail or ""
370
- error.detail += f"\n{root}"
371
+ error.detail += f"\n{root.get_untrusted_value()}"
371
372
  del schemas.classes_by_reference[root]
372
373
  for child in schemas.dependencies.get(root, set()):
373
374
  _propogate_removal(root=child, schemas=schemas, error=error)
@@ -399,10 +400,10 @@ def _process_models(*, schemas: Schemas, config: Config) -> Schemas:
399
400
  for model_prop in to_process:
400
401
  schemas_or_err = process_model(model_prop, schemas=schemas, config=config)
401
402
  if isinstance(schemas_or_err, PropertyError):
402
- schemas_or_err.header = f"\nUnable to process schema {model_prop.name}:"
403
+ schemas_or_err.header = f"\nUnable to process schema {model_prop.name.get_untrusted_value()}:"
403
404
  if isinstance(schemas_or_err.data, oai.Reference) and schemas_or_err.data.ref.endswith(
404
405
  f"/{model_prop.class_info.name}"
405
- ):
406
+ ): # pragma: no cover
406
407
  schemas_or_err.detail = schemas_or_err.detail or ""
407
408
  schemas_or_err.detail += "\n\nRecursive allOf reference found"
408
409
  final_model_errors.append((model_prop, schemas_or_err))
@@ -421,7 +422,7 @@ def _process_models(*, schemas: Schemas, config: Config) -> Schemas:
421
422
 
422
423
  def build_schemas(
423
424
  *,
424
- components: dict[str, oai.Reference | oai.Schema],
425
+ components: dict[UntrustedString, oai.Reference | oai.Schema],
425
426
  schemas: Schemas,
426
427
  config: Config,
427
428
  ) -> Schemas:
@@ -433,12 +434,12 @@ def build_schemas(
433
434
 
434
435
  def build_parameters(
435
436
  *,
436
- components: dict[str, oai.Reference | oai.Parameter],
437
+ components: dict[UntrustedString, oai.Reference | oai.Parameter],
437
438
  parameters: Parameters,
438
439
  config: Config,
439
440
  ) -> Parameters:
440
441
  """Get a list of Parameters from an OpenAPI dict"""
441
- to_process: Iterable[tuple[str, oai.Reference | oai.Parameter]] = []
442
+ to_process: Iterable[tuple[UntrustedString, oai.Reference | oai.Parameter]] = []
442
443
  if components is not None:
443
444
  to_process = components.items()
444
445
  still_making_progress = True
@@ -451,17 +452,17 @@ def build_parameters(
451
452
  next_round = []
452
453
  # Only accumulate errors from the last round, since we might fix some along the way
453
454
  for name, data in to_process:
454
- if isinstance(data, oai.Reference):
455
+ if isinstance(data, oai.Reference): # pragma: no cover
455
456
  parameters.errors.append(ParameterError(data=data, detail="Reference parameters are not supported."))
456
457
  continue
457
- ref_path = parse_reference_path(f"#/components/parameters/{name}")
458
- if isinstance(ref_path, ParseError):
458
+ ref_path = parse_reference_path(Ref(f"#/components/parameters/{name.get_untrusted_value()}"))
459
+ if isinstance(ref_path, ParseError): # pragma: no cover
459
460
  parameters.errors.append(ParameterError(detail=ref_path.detail, data=data))
460
461
  continue
461
462
  parameters_or_err = update_parameters_with_data(
462
463
  ref_path=ref_path, data=data, parameters=parameters, config=config
463
464
  )
464
- if isinstance(parameters_or_err, ParameterError):
465
+ if isinstance(parameters_or_err, ParameterError): # pragma: no cover
465
466
  next_round.append((name, data))
466
467
  errors.append(parameters_or_err)
467
468
  continue
@@ -2,10 +2,11 @@ from __future__ import annotations
2
2
 
3
3
  from typing import Any, ClassVar
4
4
 
5
- from attr import define
5
+ from attr import define, field
6
6
 
7
- from ...utils import PythonIdentifier
8
- from .protocol import PropertyProtocol, Value
7
+ from ...schema.untrusted_string import UntrustedString
8
+ from ...strings import PythonCode, PythonIdentifier
9
+ from .protocol import PropertyProtocol, Value, convert_example
9
10
 
10
11
 
11
12
  @define
@@ -15,12 +16,12 @@ class AnyProperty(PropertyProtocol):
15
16
  @classmethod
16
17
  def build(
17
18
  cls,
18
- name: str,
19
+ name: UntrustedString,
19
20
  required: bool,
20
21
  default: Any,
21
22
  python_name: PythonIdentifier,
22
- description: str | None,
23
- example: str | None,
23
+ description: UntrustedString | None,
24
+ example: Any,
24
25
  ) -> AnyProperty:
25
26
  return cls(
26
27
  name=name,
@@ -39,13 +40,13 @@ class AnyProperty(PropertyProtocol):
39
40
  return value
40
41
  if isinstance(value, str):
41
42
  return StringProperty.convert_value(value)
42
- return Value(python_code=str(value), raw_value=value)
43
+ return Value(python_code=PythonCode(str(value)), raw_value=value)
43
44
 
44
- name: str
45
+ name: UntrustedString
45
46
  required: bool
46
47
  default: Value | None
47
48
  python_name: PythonIdentifier
48
- description: str | None
49
- example: str | None
49
+ description: UntrustedString | None
50
+ example: UntrustedString | None = field(converter=convert_example)
50
51
  _type_string: ClassVar[str] = "Any"
51
52
  _json_type_string: ClassVar[str] = "Any"
@@ -2,24 +2,24 @@ from __future__ import annotations
2
2
 
3
3
  from typing import Any, ClassVar
4
4
 
5
- from attr import define
5
+ from attr import define, field
6
6
 
7
7
  from ... import schema as oai
8
- from ...utils import PythonIdentifier
8
+ from ...strings import PythonCode, PythonIdentifier
9
9
  from ..errors import PropertyError
10
- from .protocol import PropertyProtocol, Value
10
+ from .protocol import PropertyProtocol, Value, convert_example
11
11
 
12
12
 
13
13
  @define
14
14
  class BooleanProperty(PropertyProtocol):
15
15
  """Property for bool"""
16
16
 
17
- name: str
17
+ name: oai.UntrustedString
18
18
  required: bool
19
19
  default: Value | None
20
20
  python_name: PythonIdentifier
21
- description: str | None
22
- example: str | None
21
+ description: oai.UntrustedString | None
22
+ example: oai.UntrustedString | None = field(converter=convert_example)
23
23
 
24
24
  _type_string: ClassVar[str] = "bool"
25
25
  _json_type_string: ClassVar[str] = "bool"
@@ -34,12 +34,12 @@ class BooleanProperty(PropertyProtocol):
34
34
  @classmethod
35
35
  def build(
36
36
  cls,
37
- name: str,
37
+ name: oai.UntrustedString,
38
38
  required: bool,
39
39
  default: Any,
40
40
  python_name: PythonIdentifier,
41
- description: str | None,
42
- example: str | None,
41
+ description: oai.UntrustedString | None,
42
+ example: Any,
43
43
  ) -> BooleanProperty | PropertyError:
44
44
  checked_default = cls.convert_value(default)
45
45
  if isinstance(checked_default, PropertyError):
@@ -54,14 +54,14 @@ class BooleanProperty(PropertyProtocol):
54
54
  )
55
55
 
56
56
  @classmethod
57
- def convert_value(cls, value: Any) -> Value | None | PropertyError:
57
+ def convert_value(cls, value: Any) -> Value | PropertyError | None:
58
58
  if isinstance(value, Value) or value is None:
59
59
  return value
60
60
  if isinstance(value, str):
61
61
  if value.lower() == "true":
62
- return Value(python_code="True", raw_value=value)
62
+ return Value(python_code=PythonCode("True"), raw_value=value)
63
63
  elif value.lower() == "false":
64
- return Value(python_code="False", raw_value=value)
64
+ return Value(python_code=PythonCode("False"), raw_value=value)
65
65
  if isinstance(value, bool):
66
- return Value(python_code=str(value), raw_value=value)
66
+ return Value(python_code=PythonCode(str(value)), raw_value=value)
67
67
  return PropertyError(f"Invalid boolean value: {value}")
@@ -4,7 +4,8 @@ from typing import Any, ClassVar, overload
4
4
 
5
5
  from attr import define
6
6
 
7
- from ...utils import PythonIdentifier
7
+ from ... import schema as oai
8
+ from ...strings import PythonCode, PythonIdentifier
8
9
  from ..errors import PropertyError
9
10
  from .protocol import PropertyProtocol, Value
10
11
  from .string import StringProperty
@@ -14,12 +15,12 @@ from .string import StringProperty
14
15
  class ConstProperty(PropertyProtocol):
15
16
  """A property representing a const value"""
16
17
 
17
- name: str
18
+ name: oai.UntrustedString
18
19
  required: bool
19
20
  value: Value
20
21
  default: Value | None
21
22
  python_name: PythonIdentifier
22
- description: str | None
23
+ description: oai.UntrustedString | None
23
24
  example: None
24
25
  template: ClassVar[str] = "const_property.py.jinja"
25
26
 
@@ -29,10 +30,10 @@ class ConstProperty(PropertyProtocol):
29
30
  *,
30
31
  const: str | int | float | bool,
31
32
  default: Any,
32
- name: str,
33
+ name: oai.UntrustedString,
33
34
  python_name: PythonIdentifier,
34
35
  required: bool,
35
- description: str | None,
36
+ description: oai.UntrustedString | None,
36
37
  ) -> ConstProperty | PropertyError:
37
38
  """
38
39
  Create a `ConstProperty` the right way.
@@ -62,7 +63,7 @@ class ConstProperty(PropertyProtocol):
62
63
  prop.default = converted_default
63
64
  return prop
64
65
 
65
- def convert_value(self, value: Any) -> Value | None | PropertyError:
66
+ def convert_value(self, value: Any) -> Value | PropertyError | None:
66
67
  value = self._convert_value(value)
67
68
  if value is None:
68
69
  return value
@@ -87,16 +88,16 @@ class ConstProperty(PropertyProtocol):
87
88
  return value
88
89
  if isinstance(value, str):
89
90
  return StringProperty.convert_value(value)
90
- return Value(python_code=str(value), raw_value=value)
91
+ return Value(python_code=PythonCode(str(value)), raw_value=value)
91
92
 
92
93
  def get_type_string(
93
94
  self,
94
95
  no_optional: bool = False,
95
96
  json: bool = False,
96
- ) -> str:
97
- lit = f"Literal[{self.value.python_code}]"
97
+ ) -> PythonCode:
98
+ lit = PythonCode(f"Literal[{self.value.python_code.as_unembedded_code()}]")
98
99
  if not no_optional and not self.required:
99
- return f"{lit} | Unset"
100
+ return PythonCode(f"{lit.as_unembedded_code()} | Unset")
100
101
  return lit
101
102
 
102
103
  def get_imports(self, *, prefix: str) -> set[str]:
@@ -1,25 +1,26 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import datetime
3
4
  from typing import Any, ClassVar
4
5
 
5
- from attr import define
6
- from dateutil.parser import isoparse
6
+ from attr import define, field
7
7
 
8
- from ...utils import PythonIdentifier
8
+ from ... import schema as oai
9
+ from ...strings import PythonCode, PythonIdentifier
9
10
  from ..errors import PropertyError
10
- from .protocol import PropertyProtocol, Value
11
+ from .protocol import PropertyProtocol, Value, convert_example
11
12
 
12
13
 
13
14
  @define
14
15
  class DateProperty(PropertyProtocol):
15
16
  """A property of type datetime.date"""
16
17
 
17
- name: str
18
+ name: oai.UntrustedString
18
19
  required: bool
19
20
  default: Value | None
20
21
  python_name: PythonIdentifier
21
- description: str | None
22
- example: str | None
22
+ description: oai.UntrustedString | None
23
+ example: oai.UntrustedString | None = field(converter=convert_example)
23
24
 
24
25
  _type_string: ClassVar[str] = "datetime.date"
25
26
  _json_type_string: ClassVar[str] = "str"
@@ -28,12 +29,12 @@ class DateProperty(PropertyProtocol):
28
29
  @classmethod
29
30
  def build(
30
31
  cls,
31
- name: str,
32
+ name: oai.UntrustedString,
32
33
  required: bool,
33
34
  default: Any,
34
35
  python_name: PythonIdentifier,
35
- description: str | None,
36
- example: str | None,
36
+ description: oai.UntrustedString | None,
37
+ example: Any,
37
38
  ) -> DateProperty | PropertyError:
38
39
  checked_default = cls.convert_value(default)
39
40
  if isinstance(checked_default, PropertyError):
@@ -49,15 +50,15 @@ class DateProperty(PropertyProtocol):
49
50
  )
50
51
 
51
52
  @classmethod
52
- def convert_value(cls, value: Any) -> Value | None | PropertyError:
53
+ def convert_value(cls, value: Any) -> Value | PropertyError | None:
53
54
  if isinstance(value, Value) or value is None:
54
55
  return value
55
56
  if isinstance(value, str):
56
57
  try:
57
- isoparse(value).date() # make sure it's a valid value
58
+ datetime.date.fromisoformat(value) # make sure it's a valid value
58
59
  except ValueError as e:
59
60
  return PropertyError(f"Invalid date: {e}")
60
- return Value(python_code=f"isoparse({value!r}).date()", raw_value=value)
61
+ return Value(python_code=PythonCode(f"datetime.date.fromisoformat({value!r})"), raw_value=value)
61
62
  return PropertyError(f"Cannot convert {value} to a date")
62
63
 
63
64
  def get_imports(self, *, prefix: str) -> set[str]:
@@ -69,5 +70,5 @@ class DateProperty(PropertyProtocol):
69
70
  back to the root of the generated client.
70
71
  """
71
72
  imports = super().get_imports(prefix=prefix)
72
- imports.update({"import datetime", "from typing import cast", "from dateutil.parser import isoparse"})
73
+ imports.update({"import datetime", "from typing import cast"})
73
74
  return imports
@@ -1,13 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import datetime
3
4
  from typing import Any, ClassVar
4
5
 
5
- from attr import define
6
- from dateutil.parser import isoparse
6
+ from attr import define, field
7
7
 
8
- from ...utils import PythonIdentifier
8
+ from ... import schema as oai
9
+ from ...strings import PythonCode, PythonIdentifier
9
10
  from ..errors import PropertyError
10
- from .protocol import PropertyProtocol, Value
11
+ from .protocol import PropertyProtocol, Value, convert_example
11
12
 
12
13
 
13
14
  @define
@@ -16,12 +17,12 @@ class DateTimeProperty(PropertyProtocol):
16
17
  A property of type datetime.datetime
17
18
  """
18
19
 
19
- name: str
20
+ name: oai.UntrustedString
20
21
  required: bool
21
22
  default: Value | None
22
23
  python_name: PythonIdentifier
23
- description: str | None
24
- example: str | None
24
+ description: oai.UntrustedString | None
25
+ example: oai.UntrustedString | None = field(converter=convert_example)
25
26
 
26
27
  _type_string: ClassVar[str] = "datetime.datetime"
27
28
  _json_type_string: ClassVar[str] = "str"
@@ -30,12 +31,12 @@ class DateTimeProperty(PropertyProtocol):
30
31
  @classmethod
31
32
  def build(
32
33
  cls,
33
- name: str,
34
+ name: oai.UntrustedString,
34
35
  required: bool,
35
36
  default: Any,
36
37
  python_name: PythonIdentifier,
37
- description: str | None,
38
- example: str | None,
38
+ description: oai.UntrustedString | None,
39
+ example: Any,
39
40
  ) -> DateTimeProperty | PropertyError:
40
41
  checked_default = cls.convert_value(default)
41
42
  if isinstance(checked_default, PropertyError):
@@ -51,15 +52,15 @@ class DateTimeProperty(PropertyProtocol):
51
52
  )
52
53
 
53
54
  @classmethod
54
- def convert_value(cls, value: Any) -> Value | None | PropertyError:
55
+ def convert_value(cls, value: Any) -> Value | PropertyError | None:
55
56
  if value is None or isinstance(value, Value):
56
57
  return value
57
58
  if isinstance(value, str):
58
59
  try:
59
- isoparse(value) # make sure it's a valid value
60
+ datetime.datetime.fromisoformat(value) # make sure it's a valid value
60
61
  except ValueError as e:
61
62
  return PropertyError(f"Invalid datetime: {e}")
62
- return Value(python_code=f"isoparse({value!r})", raw_value=value)
63
+ return Value(python_code=PythonCode(f"datetime.datetime.fromisoformat({value!r})"), raw_value=value)
63
64
  return PropertyError(f"Cannot convert {value} to a datetime")
64
65
 
65
66
  def get_imports(self, *, prefix: str) -> set[str]:
@@ -71,5 +72,5 @@ class DateTimeProperty(PropertyProtocol):
71
72
  back to the root of the generated client.
72
73
  """
73
74
  imports = super().get_imports(prefix=prefix)
74
- imports.update({"import datetime", "from typing import cast", "from dateutil.parser import isoparse"})
75
+ imports.update({"import datetime", "from typing import cast"})
75
76
  return imports