latitudesh-python-sdk 1.1.0__py3-none-any.whl → 2.0.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.

Potentially problematic release.


This version of latitudesh-python-sdk might be problematic. Click here for more details.

Files changed (93) hide show
  1. latitudesh_python_sdk/_hooks/types.py +7 -0
  2. latitudesh_python_sdk/_version.py +6 -4
  3. latitudesh_python_sdk/apikeys.py +73 -156
  4. latitudesh_python_sdk/basesdk.py +16 -24
  5. latitudesh_python_sdk/billing.py +13 -32
  6. latitudesh_python_sdk/events_sdk.py +11 -34
  7. latitudesh_python_sdk/firewalls_sdk.py +105 -264
  8. latitudesh_python_sdk/httpclient.py +6 -16
  9. latitudesh_python_sdk/ipaddresses_sdk.py +29 -68
  10. latitudesh_python_sdk/models/__init__.py +2586 -1126
  11. latitudesh_python_sdk/models/apierror.py +30 -14
  12. latitudesh_python_sdk/models/assign_server_virtual_networkop.py +2 -2
  13. latitudesh_python_sdk/models/{bandwidth_plan.py → bandwidth_plan_data.py} +9 -9
  14. latitudesh_python_sdk/models/bandwidth_plans.py +14 -3
  15. latitudesh_python_sdk/models/custom_tag.py +15 -0
  16. latitudesh_python_sdk/models/custom_tag_data.py +54 -0
  17. latitudesh_python_sdk/models/custom_tags.py +26 -0
  18. latitudesh_python_sdk/models/delete_ssh_keyop.py +16 -0
  19. latitudesh_python_sdk/models/delete_user_dataop.py +16 -0
  20. latitudesh_python_sdk/models/deploy_config.py +11 -6
  21. latitudesh_python_sdk/models/error_object.py +11 -6
  22. latitudesh_python_sdk/models/event_data.py +98 -0
  23. latitudesh_python_sdk/models/events.py +16 -1
  24. latitudesh_python_sdk/models/filesystem_data.py +4 -0
  25. latitudesh_python_sdk/models/firewall.py +15 -0
  26. latitudesh_python_sdk/models/firewall_assignment_data.py +50 -0
  27. latitudesh_python_sdk/models/firewall_assignments.py +29 -0
  28. latitudesh_python_sdk/models/firewall_data.py +71 -0
  29. latitudesh_python_sdk/models/firewall_server.py +4 -1
  30. latitudesh_python_sdk/models/firewalls.py +7 -7
  31. latitudesh_python_sdk/models/get_firewall_assignmentsop.py +3 -3
  32. latitudesh_python_sdk/models/get_ssh_keyop.py +30 -0
  33. latitudesh_python_sdk/models/get_ssh_keysop.py +22 -0
  34. latitudesh_python_sdk/models/get_traffic_consumptionop.py +8 -4
  35. latitudesh_python_sdk/models/get_user_dataop.py +31 -0
  36. latitudesh_python_sdk/models/get_users_dataop.py +35 -0
  37. latitudesh_python_sdk/models/latitudesherror.py +26 -0
  38. latitudesh_python_sdk/models/no_response_error.py +13 -0
  39. latitudesh_python_sdk/models/operating_system_data.py +65 -0
  40. latitudesh_python_sdk/models/operating_systems.py +15 -0
  41. latitudesh_python_sdk/models/out_of_band_connection.py +4 -4
  42. latitudesh_python_sdk/models/patch_user_dataop.py +69 -0
  43. latitudesh_python_sdk/models/post_ssh_keyop.py +58 -0
  44. latitudesh_python_sdk/models/post_user_dataop.py +45 -0
  45. latitudesh_python_sdk/models/project_include.py +3 -0
  46. latitudesh_python_sdk/models/put_ssh_keyop.py +80 -0
  47. latitudesh_python_sdk/models/region_resource_data.py +4 -4
  48. latitudesh_python_sdk/models/responsevalidationerror.py +25 -0
  49. latitudesh_python_sdk/models/role.py +11 -0
  50. latitudesh_python_sdk/models/server.py +11 -6
  51. latitudesh_python_sdk/models/server_data.py +14 -3
  52. latitudesh_python_sdk/models/server_region_resource_data.py +40 -0
  53. latitudesh_python_sdk/models/{ssh_key.py → ssh_keys.py} +13 -2
  54. latitudesh_python_sdk/models/storage_plan_data.py +47 -0
  55. latitudesh_python_sdk/models/storage_plans.py +14 -3
  56. latitudesh_python_sdk/models/update_serverop.py +58 -10
  57. latitudesh_python_sdk/models/user_data.py +11 -0
  58. latitudesh_python_sdk/models/virtual_network.py +30 -6
  59. latitudesh_python_sdk/models/virtual_network1.py +15 -0
  60. latitudesh_python_sdk/models/virtual_network_assignment.py +41 -0
  61. latitudesh_python_sdk/models/virtual_network_assignment_data.py +68 -0
  62. latitudesh_python_sdk/models/virtual_network_assignments.py +5 -5
  63. latitudesh_python_sdk/models/virtual_network_data.py +88 -0
  64. latitudesh_python_sdk/models/virtual_networks.py +3 -3
  65. latitudesh_python_sdk/operatingsystems_sdk.py +13 -32
  66. latitudesh_python_sdk/plans.py +99 -214
  67. latitudesh_python_sdk/privatenetworks.py +131 -290
  68. latitudesh_python_sdk/projects_sdk.py +79 -158
  69. latitudesh_python_sdk/regions_sdk.py +25 -66
  70. latitudesh_python_sdk/roles.py +25 -64
  71. latitudesh_python_sdk/sdk.py +110 -73
  72. latitudesh_python_sdk/sdkconfiguration.py +0 -7
  73. latitudesh_python_sdk/servers_sdk.py +305 -646
  74. latitudesh_python_sdk/sshkeys_sdk.py +1856 -0
  75. latitudesh_python_sdk/storage.py +41 -120
  76. latitudesh_python_sdk/tags.py +67 -146
  77. latitudesh_python_sdk/teams_sdk.py +41 -100
  78. latitudesh_python_sdk/teamsmembers.py +37 -96
  79. latitudesh_python_sdk/traffic_sdk.py +37 -76
  80. latitudesh_python_sdk/userdata_sdk.py +959 -149
  81. latitudesh_python_sdk/userprofile.py +37 -100
  82. latitudesh_python_sdk/utils/__init__.py +131 -46
  83. latitudesh_python_sdk/utils/forms.py +49 -28
  84. latitudesh_python_sdk/utils/serializers.py +3 -2
  85. latitudesh_python_sdk/utils/unmarshal_json_response.py +24 -0
  86. latitudesh_python_sdk/virtualmachines.py +71 -140
  87. latitudesh_python_sdk/vpnsessions.py +93 -172
  88. {latitudesh_python_sdk-1.1.0.dist-info → latitudesh_python_sdk-2.0.1.dist-info}/METADATA +76 -43
  89. {latitudesh_python_sdk-1.1.0.dist-info → latitudesh_python_sdk-2.0.1.dist-info}/RECORD +91 -67
  90. {latitudesh_python_sdk-1.1.0.dist-info → latitudesh_python_sdk-2.0.1.dist-info}/WHEEL +1 -1
  91. latitudesh_python_sdk/models/storage_plan.py +0 -36
  92. latitudesh_python_sdk/sshkeys.py +0 -1050
  93. {latitudesh_python_sdk-1.1.0.dist-info → latitudesh_python_sdk-2.0.1.dist-info}/LICENSE +0 -0
@@ -5,6 +5,7 @@ from latitudesh_python_sdk import models, utils
5
5
  from latitudesh_python_sdk._hooks import HookContext
6
6
  from latitudesh_python_sdk.types import OptionalNullable, UNSET
7
7
  from latitudesh_python_sdk.utils import get_security_from_env
8
+ from latitudesh_python_sdk.utils.unmarshal_json_response import unmarshal_json_response
8
9
  from typing import Any, Mapping, Optional, Union
9
10
 
10
11
 
@@ -62,6 +63,7 @@ class UserProfile(BaseSDK):
62
63
 
63
64
  http_res = self.do_request(
64
65
  hook_ctx=HookContext(
66
+ config=self.sdk_configuration,
65
67
  base_url=base_url or "",
66
68
  operation_id="get-user-profile",
67
69
  oauth2_scopes=[],
@@ -75,28 +77,15 @@ class UserProfile(BaseSDK):
75
77
  )
76
78
 
77
79
  if utils.match_response(http_res, "200", "application/vnd.api+json"):
78
- return utils.unmarshal_json(
79
- http_res.text, models.GetUserProfileResponseBody
80
- )
80
+ return unmarshal_json_response(models.GetUserProfileResponseBody, http_res)
81
81
  if utils.match_response(http_res, "4XX", "*"):
82
82
  http_res_text = utils.stream_to_text(http_res)
83
- raise models.APIError(
84
- "API error occurred", http_res.status_code, http_res_text, http_res
85
- )
83
+ raise models.APIError("API error occurred", http_res, http_res_text)
86
84
  if utils.match_response(http_res, "5XX", "*"):
87
85
  http_res_text = utils.stream_to_text(http_res)
88
- raise models.APIError(
89
- "API error occurred", http_res.status_code, http_res_text, http_res
90
- )
86
+ raise models.APIError("API error occurred", http_res, http_res_text)
91
87
 
92
- content_type = http_res.headers.get("Content-Type")
93
- http_res_text = utils.stream_to_text(http_res)
94
- raise models.APIError(
95
- f"Unexpected response received (code: {http_res.status_code}, type: {content_type})",
96
- http_res.status_code,
97
- http_res_text,
98
- http_res,
99
- )
88
+ raise models.APIError("Unexpected response received", http_res)
100
89
 
101
90
  async def get_async(
102
91
  self,
@@ -151,6 +140,7 @@ class UserProfile(BaseSDK):
151
140
 
152
141
  http_res = await self.do_request_async(
153
142
  hook_ctx=HookContext(
143
+ config=self.sdk_configuration,
154
144
  base_url=base_url or "",
155
145
  operation_id="get-user-profile",
156
146
  oauth2_scopes=[],
@@ -164,28 +154,15 @@ class UserProfile(BaseSDK):
164
154
  )
165
155
 
166
156
  if utils.match_response(http_res, "200", "application/vnd.api+json"):
167
- return utils.unmarshal_json(
168
- http_res.text, models.GetUserProfileResponseBody
169
- )
157
+ return unmarshal_json_response(models.GetUserProfileResponseBody, http_res)
170
158
  if utils.match_response(http_res, "4XX", "*"):
171
159
  http_res_text = await utils.stream_to_text_async(http_res)
172
- raise models.APIError(
173
- "API error occurred", http_res.status_code, http_res_text, http_res
174
- )
160
+ raise models.APIError("API error occurred", http_res, http_res_text)
175
161
  if utils.match_response(http_res, "5XX", "*"):
176
162
  http_res_text = await utils.stream_to_text_async(http_res)
177
- raise models.APIError(
178
- "API error occurred", http_res.status_code, http_res_text, http_res
179
- )
163
+ raise models.APIError("API error occurred", http_res, http_res_text)
180
164
 
181
- content_type = http_res.headers.get("Content-Type")
182
- http_res_text = await utils.stream_to_text_async(http_res)
183
- raise models.APIError(
184
- f"Unexpected response received (code: {http_res.status_code}, type: {content_type})",
185
- http_res.status_code,
186
- http_res_text,
187
- http_res,
188
- )
165
+ raise models.APIError("Unexpected response received", http_res)
189
166
 
190
167
  def update(
191
168
  self,
@@ -264,6 +241,7 @@ class UserProfile(BaseSDK):
264
241
 
265
242
  http_res = self.do_request(
266
243
  hook_ctx=HookContext(
244
+ config=self.sdk_configuration,
267
245
  base_url=base_url or "",
268
246
  operation_id="patch-user-profile",
269
247
  oauth2_scopes=[],
@@ -278,31 +256,20 @@ class UserProfile(BaseSDK):
278
256
 
279
257
  response_data: Any = None
280
258
  if utils.match_response(http_res, "200", "application/vnd.api+json"):
281
- return utils.unmarshal_json(
282
- http_res.text, models.PatchUserProfileResponseBody
259
+ return unmarshal_json_response(
260
+ models.PatchUserProfileResponseBody, http_res
283
261
  )
284
262
  if utils.match_response(http_res, "403", "application/vnd.api+json"):
285
- response_data = utils.unmarshal_json(http_res.text, models.ErrorObjectData)
286
- raise models.ErrorObject(data=response_data)
263
+ response_data = unmarshal_json_response(models.ErrorObjectData, http_res)
264
+ raise models.ErrorObject(response_data, http_res)
287
265
  if utils.match_response(http_res, ["422", "4XX"], "*"):
288
266
  http_res_text = utils.stream_to_text(http_res)
289
- raise models.APIError(
290
- "API error occurred", http_res.status_code, http_res_text, http_res
291
- )
267
+ raise models.APIError("API error occurred", http_res, http_res_text)
292
268
  if utils.match_response(http_res, "5XX", "*"):
293
269
  http_res_text = utils.stream_to_text(http_res)
294
- raise models.APIError(
295
- "API error occurred", http_res.status_code, http_res_text, http_res
296
- )
270
+ raise models.APIError("API error occurred", http_res, http_res_text)
297
271
 
298
- content_type = http_res.headers.get("Content-Type")
299
- http_res_text = utils.stream_to_text(http_res)
300
- raise models.APIError(
301
- f"Unexpected response received (code: {http_res.status_code}, type: {content_type})",
302
- http_res.status_code,
303
- http_res_text,
304
- http_res,
305
- )
272
+ raise models.APIError("Unexpected response received", http_res)
306
273
 
307
274
  async def update_async(
308
275
  self,
@@ -381,6 +348,7 @@ class UserProfile(BaseSDK):
381
348
 
382
349
  http_res = await self.do_request_async(
383
350
  hook_ctx=HookContext(
351
+ config=self.sdk_configuration,
384
352
  base_url=base_url or "",
385
353
  operation_id="patch-user-profile",
386
354
  oauth2_scopes=[],
@@ -395,31 +363,20 @@ class UserProfile(BaseSDK):
395
363
 
396
364
  response_data: Any = None
397
365
  if utils.match_response(http_res, "200", "application/vnd.api+json"):
398
- return utils.unmarshal_json(
399
- http_res.text, models.PatchUserProfileResponseBody
366
+ return unmarshal_json_response(
367
+ models.PatchUserProfileResponseBody, http_res
400
368
  )
401
369
  if utils.match_response(http_res, "403", "application/vnd.api+json"):
402
- response_data = utils.unmarshal_json(http_res.text, models.ErrorObjectData)
403
- raise models.ErrorObject(data=response_data)
370
+ response_data = unmarshal_json_response(models.ErrorObjectData, http_res)
371
+ raise models.ErrorObject(response_data, http_res)
404
372
  if utils.match_response(http_res, ["422", "4XX"], "*"):
405
373
  http_res_text = await utils.stream_to_text_async(http_res)
406
- raise models.APIError(
407
- "API error occurred", http_res.status_code, http_res_text, http_res
408
- )
374
+ raise models.APIError("API error occurred", http_res, http_res_text)
409
375
  if utils.match_response(http_res, "5XX", "*"):
410
376
  http_res_text = await utils.stream_to_text_async(http_res)
411
- raise models.APIError(
412
- "API error occurred", http_res.status_code, http_res_text, http_res
413
- )
377
+ raise models.APIError("API error occurred", http_res, http_res_text)
414
378
 
415
- content_type = http_res.headers.get("Content-Type")
416
- http_res_text = await utils.stream_to_text_async(http_res)
417
- raise models.APIError(
418
- f"Unexpected response received (code: {http_res.status_code}, type: {content_type})",
419
- http_res.status_code,
420
- http_res_text,
421
- http_res,
422
- )
379
+ raise models.APIError("Unexpected response received", http_res)
423
380
 
424
381
  def list_teams(
425
382
  self,
@@ -474,6 +431,7 @@ class UserProfile(BaseSDK):
474
431
 
475
432
  http_res = self.do_request(
476
433
  hook_ctx=HookContext(
434
+ config=self.sdk_configuration,
477
435
  base_url=base_url or "",
478
436
  operation_id="get-user-teams",
479
437
  oauth2_scopes=[],
@@ -487,26 +445,15 @@ class UserProfile(BaseSDK):
487
445
  )
488
446
 
489
447
  if utils.match_response(http_res, "200", "application/vnd.api+json"):
490
- return utils.unmarshal_json(http_res.text, models.UserTeams)
448
+ return unmarshal_json_response(models.UserTeams, http_res)
491
449
  if utils.match_response(http_res, "4XX", "*"):
492
450
  http_res_text = utils.stream_to_text(http_res)
493
- raise models.APIError(
494
- "API error occurred", http_res.status_code, http_res_text, http_res
495
- )
451
+ raise models.APIError("API error occurred", http_res, http_res_text)
496
452
  if utils.match_response(http_res, "5XX", "*"):
497
453
  http_res_text = utils.stream_to_text(http_res)
498
- raise models.APIError(
499
- "API error occurred", http_res.status_code, http_res_text, http_res
500
- )
454
+ raise models.APIError("API error occurred", http_res, http_res_text)
501
455
 
502
- content_type = http_res.headers.get("Content-Type")
503
- http_res_text = utils.stream_to_text(http_res)
504
- raise models.APIError(
505
- f"Unexpected response received (code: {http_res.status_code}, type: {content_type})",
506
- http_res.status_code,
507
- http_res_text,
508
- http_res,
509
- )
456
+ raise models.APIError("Unexpected response received", http_res)
510
457
 
511
458
  async def list_teams_async(
512
459
  self,
@@ -561,6 +508,7 @@ class UserProfile(BaseSDK):
561
508
 
562
509
  http_res = await self.do_request_async(
563
510
  hook_ctx=HookContext(
511
+ config=self.sdk_configuration,
564
512
  base_url=base_url or "",
565
513
  operation_id="get-user-teams",
566
514
  oauth2_scopes=[],
@@ -574,23 +522,12 @@ class UserProfile(BaseSDK):
574
522
  )
575
523
 
576
524
  if utils.match_response(http_res, "200", "application/vnd.api+json"):
577
- return utils.unmarshal_json(http_res.text, models.UserTeams)
525
+ return unmarshal_json_response(models.UserTeams, http_res)
578
526
  if utils.match_response(http_res, "4XX", "*"):
579
527
  http_res_text = await utils.stream_to_text_async(http_res)
580
- raise models.APIError(
581
- "API error occurred", http_res.status_code, http_res_text, http_res
582
- )
528
+ raise models.APIError("API error occurred", http_res, http_res_text)
583
529
  if utils.match_response(http_res, "5XX", "*"):
584
530
  http_res_text = await utils.stream_to_text_async(http_res)
585
- raise models.APIError(
586
- "API error occurred", http_res.status_code, http_res_text, http_res
587
- )
531
+ raise models.APIError("API error occurred", http_res, http_res_text)
588
532
 
589
- content_type = http_res.headers.get("Content-Type")
590
- http_res_text = await utils.stream_to_text_async(http_res)
591
- raise models.APIError(
592
- f"Unexpected response received (code: {http_res.status_code}, type: {content_type})",
593
- http_res.status_code,
594
- http_res_text,
595
- http_res,
596
- )
533
+ raise models.APIError("Unexpected response received", http_res)
@@ -1,52 +1,56 @@
1
1
  """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
2
2
 
3
- from .annotations import get_discriminator
4
- from .datetimes import parse_datetime
5
- from .enums import OpenEnumMeta
6
- from .headers import get_headers, get_response_headers
7
- from .metadata import (
8
- FieldMetadata,
9
- find_metadata,
10
- FormMetadata,
11
- HeaderMetadata,
12
- MultipartFormMetadata,
13
- PathParamMetadata,
14
- QueryParamMetadata,
15
- RequestMetadata,
16
- SecurityMetadata,
17
- )
18
- from .queryparams import get_query_params
19
- from .retries import BackoffStrategy, Retries, retry, retry_async, RetryConfig
20
- from .requestbodies import serialize_request_body, SerializedRequestBody
21
- from .security import get_security, get_security_from_env
3
+ from typing import TYPE_CHECKING
4
+ from importlib import import_module
22
5
 
23
- from .serializers import (
24
- get_pydantic_model,
25
- marshal_json,
26
- unmarshal,
27
- unmarshal_json,
28
- serialize_decimal,
29
- serialize_float,
30
- serialize_int,
31
- stream_to_text,
32
- stream_to_text_async,
33
- stream_to_bytes,
34
- stream_to_bytes_async,
35
- validate_const,
36
- validate_decimal,
37
- validate_float,
38
- validate_int,
39
- validate_open_enum,
40
- )
41
- from .url import generate_url, template_url, remove_suffix
42
- from .values import (
43
- get_global_from_env,
44
- match_content_type,
45
- match_status_codes,
46
- match_response,
47
- cast_partial,
48
- )
49
- from .logger import Logger, get_body_content, get_default_logger
6
+ if TYPE_CHECKING:
7
+ from .annotations import get_discriminator
8
+ from .datetimes import parse_datetime
9
+ from .enums import OpenEnumMeta
10
+ from .headers import get_headers, get_response_headers
11
+ from .metadata import (
12
+ FieldMetadata,
13
+ find_metadata,
14
+ FormMetadata,
15
+ HeaderMetadata,
16
+ MultipartFormMetadata,
17
+ PathParamMetadata,
18
+ QueryParamMetadata,
19
+ RequestMetadata,
20
+ SecurityMetadata,
21
+ )
22
+ from .queryparams import get_query_params
23
+ from .retries import BackoffStrategy, Retries, retry, retry_async, RetryConfig
24
+ from .requestbodies import serialize_request_body, SerializedRequestBody
25
+ from .security import get_security, get_security_from_env
26
+
27
+ from .serializers import (
28
+ get_pydantic_model,
29
+ marshal_json,
30
+ unmarshal,
31
+ unmarshal_json,
32
+ serialize_decimal,
33
+ serialize_float,
34
+ serialize_int,
35
+ stream_to_text,
36
+ stream_to_text_async,
37
+ stream_to_bytes,
38
+ stream_to_bytes_async,
39
+ validate_const,
40
+ validate_decimal,
41
+ validate_float,
42
+ validate_int,
43
+ validate_open_enum,
44
+ )
45
+ from .url import generate_url, template_url, remove_suffix
46
+ from .values import (
47
+ get_global_from_env,
48
+ match_content_type,
49
+ match_status_codes,
50
+ match_response,
51
+ cast_partial,
52
+ )
53
+ from .logger import Logger, get_body_content, get_default_logger
50
54
 
51
55
  __all__ = [
52
56
  "BackoffStrategy",
@@ -57,6 +61,7 @@ __all__ = [
57
61
  "get_body_content",
58
62
  "get_default_logger",
59
63
  "get_discriminator",
64
+ "parse_datetime",
60
65
  "get_global_from_env",
61
66
  "get_headers",
62
67
  "get_pydantic_model",
@@ -100,3 +105,83 @@ __all__ = [
100
105
  "validate_open_enum",
101
106
  "cast_partial",
102
107
  ]
108
+
109
+ _dynamic_imports: dict[str, str] = {
110
+ "BackoffStrategy": ".retries",
111
+ "FieldMetadata": ".metadata",
112
+ "find_metadata": ".metadata",
113
+ "FormMetadata": ".metadata",
114
+ "generate_url": ".url",
115
+ "get_body_content": ".logger",
116
+ "get_default_logger": ".logger",
117
+ "get_discriminator": ".annotations",
118
+ "parse_datetime": ".datetimes",
119
+ "get_global_from_env": ".values",
120
+ "get_headers": ".headers",
121
+ "get_pydantic_model": ".serializers",
122
+ "get_query_params": ".queryparams",
123
+ "get_response_headers": ".headers",
124
+ "get_security": ".security",
125
+ "get_security_from_env": ".security",
126
+ "HeaderMetadata": ".metadata",
127
+ "Logger": ".logger",
128
+ "marshal_json": ".serializers",
129
+ "match_content_type": ".values",
130
+ "match_status_codes": ".values",
131
+ "match_response": ".values",
132
+ "MultipartFormMetadata": ".metadata",
133
+ "OpenEnumMeta": ".enums",
134
+ "PathParamMetadata": ".metadata",
135
+ "QueryParamMetadata": ".metadata",
136
+ "remove_suffix": ".url",
137
+ "Retries": ".retries",
138
+ "retry": ".retries",
139
+ "retry_async": ".retries",
140
+ "RetryConfig": ".retries",
141
+ "RequestMetadata": ".metadata",
142
+ "SecurityMetadata": ".metadata",
143
+ "serialize_decimal": ".serializers",
144
+ "serialize_float": ".serializers",
145
+ "serialize_int": ".serializers",
146
+ "serialize_request_body": ".requestbodies",
147
+ "SerializedRequestBody": ".requestbodies",
148
+ "stream_to_text": ".serializers",
149
+ "stream_to_text_async": ".serializers",
150
+ "stream_to_bytes": ".serializers",
151
+ "stream_to_bytes_async": ".serializers",
152
+ "template_url": ".url",
153
+ "unmarshal": ".serializers",
154
+ "unmarshal_json": ".serializers",
155
+ "validate_decimal": ".serializers",
156
+ "validate_const": ".serializers",
157
+ "validate_float": ".serializers",
158
+ "validate_int": ".serializers",
159
+ "validate_open_enum": ".serializers",
160
+ "cast_partial": ".values",
161
+ }
162
+
163
+
164
+ def __getattr__(attr_name: str) -> object:
165
+ module_name = _dynamic_imports.get(attr_name)
166
+ if module_name is None:
167
+ raise AttributeError(
168
+ f"no {attr_name} found in _dynamic_imports, module name -> {__name__} "
169
+ )
170
+
171
+ try:
172
+ module = import_module(module_name, __package__)
173
+ result = getattr(module, attr_name)
174
+ return result
175
+ except ImportError as e:
176
+ raise ImportError(
177
+ f"Failed to import {attr_name} from {module_name}: {e}"
178
+ ) from e
179
+ except AttributeError as e:
180
+ raise AttributeError(
181
+ f"Failed to get {attr_name} from {module_name}: {e}"
182
+ ) from e
183
+
184
+
185
+ def __dir__():
186
+ lazy_attrs = list(_dynamic_imports.keys())
187
+ return sorted(lazy_attrs)
@@ -86,11 +86,39 @@ def _populate_form(
86
86
  return form
87
87
 
88
88
 
89
+ def _extract_file_properties(file_obj: Any) -> Tuple[str, Any, Any]:
90
+ """Extract file name, content, and content type from a file object."""
91
+ file_fields: Dict[str, FieldInfo] = file_obj.__class__.model_fields
92
+
93
+ file_name = ""
94
+ content = None
95
+ content_type = None
96
+
97
+ for file_field_name in file_fields:
98
+ file_field = file_fields[file_field_name]
99
+
100
+ file_metadata = find_field_metadata(file_field, MultipartFormMetadata)
101
+ if file_metadata is None:
102
+ continue
103
+
104
+ if file_metadata.content:
105
+ content = getattr(file_obj, file_field_name, None)
106
+ elif file_field_name == "content_type":
107
+ content_type = getattr(file_obj, file_field_name, None)
108
+ else:
109
+ file_name = getattr(file_obj, file_field_name)
110
+
111
+ if file_name == "" or content is None:
112
+ raise ValueError("invalid multipart/form-data file")
113
+
114
+ return file_name, content, content_type
115
+
116
+
89
117
  def serialize_multipart_form(
90
118
  media_type: str, request: Any
91
- ) -> Tuple[str, Dict[str, Any], Dict[str, Any]]:
119
+ ) -> Tuple[str, Dict[str, Any], List[Tuple[str, Any]]]:
92
120
  form: Dict[str, Any] = {}
93
- files: Dict[str, Any] = {}
121
+ files: List[Tuple[str, Any]] = []
94
122
 
95
123
  if not isinstance(request, BaseModel):
96
124
  raise TypeError("invalid request body type")
@@ -112,39 +140,32 @@ def serialize_multipart_form(
112
140
  f_name = field.alias if field.alias else name
113
141
 
114
142
  if field_metadata.file:
115
- file_fields: Dict[str, FieldInfo] = val.__class__.model_fields
116
-
117
- file_name = ""
118
- content = None
119
- content_type = None
120
-
121
- for file_field_name in file_fields:
122
- file_field = file_fields[file_field_name]
143
+ if isinstance(val, List):
144
+ # Handle array of files
145
+ for file_obj in val:
146
+ if not _is_set(file_obj):
147
+ continue
148
+
149
+ file_name, content, content_type = _extract_file_properties(file_obj)
123
150
 
124
- file_metadata = find_field_metadata(file_field, MultipartFormMetadata)
125
- if file_metadata is None:
126
- continue
151
+ if content_type is not None:
152
+ files.append((f_name + "[]", (file_name, content, content_type)))
153
+ else:
154
+ files.append((f_name + "[]", (file_name, content)))
155
+ else:
156
+ # Handle single file
157
+ file_name, content, content_type = _extract_file_properties(val)
127
158
 
128
- if file_metadata.content:
129
- content = getattr(val, file_field_name, None)
130
- elif file_field_name == "content_type":
131
- content_type = getattr(val, file_field_name, None)
159
+ if content_type is not None:
160
+ files.append((f_name, (file_name, content, content_type)))
132
161
  else:
133
- file_name = getattr(val, file_field_name)
134
-
135
- if file_name == "" or content is None:
136
- raise ValueError("invalid multipart/form-data file")
137
-
138
- if content_type is not None:
139
- files[f_name] = (file_name, content, content_type)
140
- else:
141
- files[f_name] = (file_name, content)
162
+ files.append((f_name, (file_name, content)))
142
163
  elif field_metadata.json:
143
- files[f_name] = (
164
+ files.append((f_name, (
144
165
  None,
145
166
  marshal_json(val, request_field_types[name]),
146
167
  "application/json",
147
- )
168
+ )))
148
169
  else:
149
170
  if isinstance(val, List):
150
171
  values = []
@@ -192,7 +192,9 @@ def is_union(obj: object) -> bool:
192
192
  """
193
193
  Returns True if the given object is a typing.Union or typing_extensions.Union.
194
194
  """
195
- return any(obj is typing_obj for typing_obj in _get_typing_objects_by_name_of("Union"))
195
+ return any(
196
+ obj is typing_obj for typing_obj in _get_typing_objects_by_name_of("Union")
197
+ )
196
198
 
197
199
 
198
200
  def stream_to_text(stream: httpx.Response) -> str:
@@ -245,4 +247,3 @@ def _get_typing_objects_by_name_of(name: str) -> Tuple[Any, ...]:
245
247
  f"Neither typing nor typing_extensions has an object called {name!r}"
246
248
  )
247
249
  return result
248
-
@@ -0,0 +1,24 @@
1
+ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
2
+
3
+ from typing import Any, Optional
4
+
5
+ import httpx
6
+
7
+ from .serializers import unmarshal_json
8
+ from latitudesh_python_sdk import models
9
+
10
+
11
+ def unmarshal_json_response(
12
+ typ: Any, http_res: httpx.Response, body: Optional[str] = None
13
+ ) -> Any:
14
+ if body is None:
15
+ body = http_res.text
16
+ try:
17
+ return unmarshal_json(body, typ)
18
+ except Exception as e:
19
+ raise models.ResponseValidationError(
20
+ "Response validation failed",
21
+ http_res,
22
+ e,
23
+ body,
24
+ ) from e