RESTFly 2.0.3__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.
restfly/_sync.py ADDED
@@ -0,0 +1,1565 @@
1
+ from __future__ import annotations
2
+
3
+ import random
4
+ from collections.abc import Callable, Iterator
5
+ from contextlib import contextmanager
6
+ from ssl import SSLContext
7
+ from time import sleep
8
+ from typing import Any, Self, overload, override
9
+
10
+ from ._base import APIBaseEndpoint, APIClientBase
11
+ from ._errors import APIError, ErrorStatus, RetryError
12
+ from ._utils import assign_annotations, unmarshal
13
+ from .types import (
14
+ DEFAULT_LIMITS,
15
+ DEFAULT_MAX_REDIRECTS,
16
+ DEFAULT_TIMEOUT_CONFIG,
17
+ USE_CLIENT_DEFAULT,
18
+ AuthTypes,
19
+ BaseTransport,
20
+ CertTypes,
21
+ Client,
22
+ CookieTypes,
23
+ EventHook,
24
+ HeaderTypes,
25
+ HTTPMethods,
26
+ Limits,
27
+ Model,
28
+ ProxyTypes,
29
+ QueryParamTypes,
30
+ Request,
31
+ RequestContent,
32
+ RequestData,
33
+ RequestExtensions,
34
+ RequestFiles,
35
+ Response,
36
+ TimeoutTypes,
37
+ UseClientDefault,
38
+ XMLModel,
39
+ codes,
40
+ )
41
+
42
+
43
+ class HTTPClientVerbs:
44
+ def _request(
45
+ self,
46
+ method: HTTPMethods,
47
+ path: str = "",
48
+ *,
49
+ response_model: type[Model | list[Model]] | None = None,
50
+ params: QueryParamTypes | None = None,
51
+ content: RequestContent | None = None,
52
+ data: RequestData | None = None,
53
+ files: RequestFiles | None = None,
54
+ headers: dict[str, str] | None = None,
55
+ json: Model | Any | None = None,
56
+ xml: XMLModel | str | bytes | None = None,
57
+ response_model_kwargs: dict[str, Any] | None = None,
58
+ request_model_kwargs: dict[str, Any] | None = None,
59
+ cookies: CookieTypes | None = None,
60
+ auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
61
+ follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
62
+ timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
63
+ extensions: RequestExtensions | None = None,
64
+ max_retries: int | None = None,
65
+ error_map: dict[int, ErrorStatus] | None = None,
66
+ stream: bool = False,
67
+ ) -> Model | list[Model] | Response:
68
+ raise NotImplementedError
69
+
70
+ @contextmanager
71
+ def _stream(
72
+ self,
73
+ method: HTTPMethods,
74
+ path: str = "",
75
+ *,
76
+ params: QueryParamTypes | None = None,
77
+ content: RequestContent | None = None,
78
+ data: RequestData | None = None,
79
+ files: RequestFiles | None = None,
80
+ headers: dict[str, str] | None = None,
81
+ json: Model | Any | None = None,
82
+ xml: XMLModel | str | bytes | None = None,
83
+ request_model_kwargs: dict[str, Any] | None = None,
84
+ cookies: CookieTypes | None = None,
85
+ auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
86
+ follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
87
+ timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
88
+ extensions: RequestExtensions | None = None,
89
+ max_retries: int | None = None,
90
+ error_map: dict[int, ErrorStatus] | None = None,
91
+ ) -> Iterator[Response]:
92
+ """
93
+ Construct and send an HTTP request and stream the response back. This is an
94
+ alternative method to making a call to _request that also supports closing of
95
+ the response through the use of a context manager.
96
+
97
+ Args:
98
+ method:
99
+ The HTTP method used to make the call.
100
+ path:
101
+ URL to query.
102
+ request_model_kwargs:
103
+ Keyword arguments to pass to Pydantic/Pydantic-XML as part of
104
+ marshalling the body of the data into the request.
105
+ params:
106
+ Request query parameters.
107
+ content:
108
+ Raw body of the request.
109
+ data:
110
+ URL form-encoded body for the request.
111
+ json:
112
+ Data object to marshal into JSON. Content passed with this parameter
113
+ will also set the ``Content-Type`` header to ``application/json``.
114
+ xml:
115
+ Data object to marshal into XML. Content passed with this parameter
116
+ will also set the ``Content-Type`` header to ``application/json``.
117
+ files:
118
+ A dictionary of upload files to include in the body of the request.
119
+ headers:
120
+ Request-specific headers.
121
+ cookies:
122
+ Request-specific cookies.
123
+ auth:
124
+ Request-specific authentication.
125
+ follow_redirects:
126
+ Should the client follow any redirects?
127
+ timeout:
128
+ Request-specific timeout settings.
129
+ extensions:
130
+ Any additional httpx extensions to pass to the client.
131
+ max_retries:
132
+ The maximum number of retries to attempt before giving up. Overloads
133
+ the client default.
134
+ error_map:
135
+ Replaces the client error map with this one instead.
136
+
137
+ Returns:
138
+ Returns the HTTPX Response object with streaming enabled.
139
+ """
140
+ response: Response = self._request( # type: ignore[assignment] # ty: ignore[invalid-assignment]
141
+ method=method,
142
+ path=path,
143
+ params=params,
144
+ content=content,
145
+ data=data,
146
+ files=files,
147
+ headers=headers,
148
+ json=json,
149
+ xml=xml,
150
+ request_model_kwargs=request_model_kwargs,
151
+ cookies=cookies,
152
+ auth=auth,
153
+ follow_redirects=follow_redirects,
154
+ timeout=timeout,
155
+ extensions=extensions,
156
+ max_retries=max_retries,
157
+ error_map=error_map,
158
+ stream=True,
159
+ response_model=None,
160
+ response_model_kwargs=None,
161
+ )
162
+ try:
163
+ yield response
164
+ finally:
165
+ response.close()
166
+
167
+ @overload
168
+ def _get(
169
+ self,
170
+ path: str = ...,
171
+ *,
172
+ response_model: None = ...,
173
+ response_model_kwargs: dict[str, Any] | None = ...,
174
+ params: QueryParamTypes | None = ...,
175
+ headers: dict[str, str] | None = ...,
176
+ cookies: CookieTypes | None = ...,
177
+ auth: AuthTypes | UseClientDefault | None = ...,
178
+ follow_redirects: bool | UseClientDefault = ...,
179
+ timeout: TimeoutTypes | UseClientDefault = ...,
180
+ extensions: RequestExtensions | None = ...,
181
+ max_retries: int | None = ...,
182
+ error_map: dict[int, ErrorStatus] | None = ...,
183
+ ) -> Response: ...
184
+
185
+ @overload
186
+ def _get(
187
+ self,
188
+ path: str = ...,
189
+ *,
190
+ response_model: type[Model],
191
+ response_model_kwargs: dict[str, Any] | None = ...,
192
+ params: QueryParamTypes | None = ...,
193
+ headers: dict[str, str] | None = ...,
194
+ cookies: CookieTypes | None = ...,
195
+ auth: AuthTypes | UseClientDefault | None = ...,
196
+ follow_redirects: bool | UseClientDefault = ...,
197
+ timeout: TimeoutTypes | UseClientDefault = ...,
198
+ extensions: RequestExtensions | None = ...,
199
+ max_retries: int | None = ...,
200
+ error_map: dict[int, ErrorStatus] | None = ...,
201
+ ) -> Model: ...
202
+
203
+ @overload
204
+ def _get(
205
+ self,
206
+ path: str = ...,
207
+ *,
208
+ response_model: type[list[Model]],
209
+ response_model_kwargs: dict[str, Any] | None = ...,
210
+ params: QueryParamTypes | None = ...,
211
+ headers: dict[str, str] | None = ...,
212
+ cookies: CookieTypes | None = ...,
213
+ auth: AuthTypes | UseClientDefault | None = ...,
214
+ follow_redirects: bool | UseClientDefault = ...,
215
+ timeout: TimeoutTypes | UseClientDefault = ...,
216
+ extensions: RequestExtensions | None = ...,
217
+ max_retries: int | None = ...,
218
+ error_map: dict[int, ErrorStatus] | None = ...,
219
+ ) -> list[Model]: ...
220
+
221
+ def _get(
222
+ self,
223
+ path: str = "",
224
+ *,
225
+ response_model: type[Model | list[Model]] | None = None,
226
+ response_model_kwargs: dict[str, Any] | None = None,
227
+ params: QueryParamTypes | None = None,
228
+ headers: dict[str, str] | None = None,
229
+ cookies: CookieTypes | None = None,
230
+ auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
231
+ follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
232
+ timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
233
+ extensions: RequestExtensions | None = None,
234
+ max_retries: int | None = None,
235
+ error_map: dict[int, ErrorStatus] | None = None,
236
+ ) -> Model | list[Model] | Response:
237
+ """
238
+ Construct and send an HTTP GET request.
239
+
240
+ Args:
241
+ path:
242
+ URL to query.
243
+ response_model:
244
+ Pydantic model to coerce the response into.
245
+ response_model_kwargs:
246
+ Keyword arguments to pass to Pydantic/Pydantic-XML as part of
247
+ un-marshalling the response data.
248
+ params:
249
+ Request query parameters.
250
+ headers:
251
+ Request-specific headers.
252
+ cookies:
253
+ Request-specific cookies.
254
+ auth:
255
+ Request-specific authentication.
256
+ follow_redirects:
257
+ Should the client follow any redirects?
258
+ timeout:
259
+ Request-specific timeout settings.
260
+ extensions:
261
+ Any additional httpx extensions to pass to the client.
262
+ max_retries:
263
+ The maximum number of retries to attempt before giving up. Overloads
264
+ the client default.
265
+ error_map:
266
+ Replaces the client error map with this one instead.
267
+
268
+ Returns:
269
+ Returns the HTTPX Response object if no response_model is specified. If a
270
+ response_model _is_ specified, then the response will be coerced into the
271
+ response model and the instance of the model will be returned.
272
+ """
273
+ return self._request(
274
+ method="GET",
275
+ path=path,
276
+ params=params,
277
+ headers=headers,
278
+ cookies=cookies,
279
+ auth=auth,
280
+ follow_redirects=follow_redirects,
281
+ timeout=timeout,
282
+ extensions=extensions,
283
+ response_model=response_model,
284
+ response_model_kwargs=response_model_kwargs,
285
+ max_retries=max_retries,
286
+ error_map=error_map,
287
+ )
288
+
289
+ @overload
290
+ def _post(
291
+ self,
292
+ path: str = ...,
293
+ *,
294
+ response_model: None = ...,
295
+ params: QueryParamTypes | None = ...,
296
+ content: RequestContent | None = ...,
297
+ data: RequestData | None = ...,
298
+ files: RequestFiles | None = ...,
299
+ json: Model | Any | None = ...,
300
+ xml: XMLModel | str | bytes | None = ...,
301
+ response_model_kwargs: dict[str, Any] | None = ...,
302
+ request_model_kwargs: dict[str, Any] | None = ...,
303
+ headers: dict[str, str] | None = ...,
304
+ cookies: CookieTypes | None = ...,
305
+ auth: AuthTypes | UseClientDefault | None = ...,
306
+ follow_redirects: bool | UseClientDefault = ...,
307
+ timeout: TimeoutTypes | UseClientDefault = ...,
308
+ extensions: RequestExtensions | None = ...,
309
+ max_retries: int | None = ...,
310
+ error_map: dict[int, ErrorStatus] | None = ...,
311
+ ) -> Response: ...
312
+
313
+ @overload
314
+ def _post(
315
+ self,
316
+ path: str = ...,
317
+ *,
318
+ response_model: type[Model],
319
+ params: QueryParamTypes | None = ...,
320
+ content: RequestContent | None = ...,
321
+ data: RequestData | None = ...,
322
+ files: RequestFiles | None = ...,
323
+ json: Model | Any | None = ...,
324
+ xml: XMLModel | str | bytes | None = ...,
325
+ response_model_kwargs: dict[str, Any] | None = ...,
326
+ request_model_kwargs: dict[str, Any] | None = ...,
327
+ headers: dict[str, str] | None = ...,
328
+ cookies: CookieTypes | None = ...,
329
+ auth: AuthTypes | UseClientDefault | None = ...,
330
+ follow_redirects: bool | UseClientDefault = ...,
331
+ timeout: TimeoutTypes | UseClientDefault = ...,
332
+ extensions: RequestExtensions | None = ...,
333
+ max_retries: int | None = ...,
334
+ error_map: dict[int, ErrorStatus] | None = ...,
335
+ ) -> Model: ...
336
+
337
+ @overload
338
+ def _post(
339
+ self,
340
+ path: str = ...,
341
+ *,
342
+ response_model: type[list[Model]],
343
+ params: QueryParamTypes | None = ...,
344
+ content: RequestContent | None = ...,
345
+ data: RequestData | None = ...,
346
+ files: RequestFiles | None = ...,
347
+ json: Model | Any | None = ...,
348
+ xml: XMLModel | str | bytes | None = ...,
349
+ response_model_kwargs: dict[str, Any] | None = ...,
350
+ request_model_kwargs: dict[str, Any] | None = ...,
351
+ headers: dict[str, str] | None = ...,
352
+ cookies: CookieTypes | None = ...,
353
+ auth: AuthTypes | UseClientDefault | None = ...,
354
+ follow_redirects: bool | UseClientDefault = ...,
355
+ timeout: TimeoutTypes | UseClientDefault = ...,
356
+ extensions: RequestExtensions | None = ...,
357
+ max_retries: int | None = ...,
358
+ error_map: dict[int, ErrorStatus] | None = ...,
359
+ ) -> list[Model]: ...
360
+
361
+ def _post(
362
+ self,
363
+ path: str = "",
364
+ *,
365
+ params: QueryParamTypes | None = None,
366
+ content: RequestContent | None = None,
367
+ data: RequestData | None = None,
368
+ files: RequestFiles | None = None,
369
+ json: Model | Any | None = None,
370
+ xml: XMLModel | str | bytes | None = None,
371
+ headers: dict[str, str] | None = None,
372
+ response_model: type[Model | list[Model]] | None = None,
373
+ response_model_kwargs: dict[str, Any] | None = None,
374
+ request_model_kwargs: dict[str, Any] | None = None,
375
+ cookies: CookieTypes | None = None,
376
+ auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
377
+ follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
378
+ timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
379
+ extensions: RequestExtensions | None = None,
380
+ max_retries: int | None = None,
381
+ error_map: dict[int, ErrorStatus] | None = None,
382
+ ) -> Model | list[Model] | Response:
383
+ """
384
+ Construct and send an HTTP POST request.
385
+
386
+ Args:
387
+ path:
388
+ URL to query.
389
+ response_model:
390
+ Pydantic model to coerce the response into.
391
+ response_model_kwargs:
392
+ Keyword arguments to pass to Pydantic/Pydantic-XML as part of
393
+ un-marshalling the response data.
394
+ request_model_kwargs:
395
+ Keyword arguments to pass to Pydantic/Pydantic-XML as part of
396
+ marshalling the body of the data into the request.
397
+ params:
398
+ Request query parameters.
399
+ content:
400
+ Raw body of the request.
401
+ data:
402
+ URL form-encoded body for the request.
403
+ json:
404
+ Data object to marshal into JSON. Content passed with this parameter
405
+ will also set the ``Content-Type`` header to ``application/json``.
406
+ xml:
407
+ Data object to marshal into XML. Content passed with this parameter
408
+ will also set the ``Content-Type`` header to ``application/json``.
409
+ files:
410
+ A dictionary of upload files to include in the body of the request.
411
+ headers:
412
+ Request-specific headers.
413
+ cookies:
414
+ Request-specific cookies.
415
+ auth:
416
+ Request-specific authentication.
417
+ follow_redirects:
418
+ Should the client follow any redirects?
419
+ timeout:
420
+ Request-specific timeout settings.
421
+ extensions:
422
+ Any additional httpx extensions to pass to the client.
423
+ max_retries:
424
+ The maximum number of retries to attempt before giving up. Overloads
425
+ the client default.
426
+ error_map:
427
+ Replaces the client error map with this one instead.
428
+
429
+ Returns:
430
+ Returns the HTTPX Response object if no response_model is specified. If a
431
+ response_model _is_ specified, then the response will be coerced into the
432
+ response model and the instance of the model will be returned.
433
+ """
434
+ return self._request(
435
+ method="POST",
436
+ path=path,
437
+ params=params,
438
+ content=content,
439
+ data=data,
440
+ files=files,
441
+ json=json,
442
+ xml=xml,
443
+ headers=headers,
444
+ cookies=cookies,
445
+ auth=auth,
446
+ follow_redirects=follow_redirects,
447
+ timeout=timeout,
448
+ extensions=extensions,
449
+ response_model=response_model,
450
+ response_model_kwargs=response_model_kwargs,
451
+ request_model_kwargs=request_model_kwargs,
452
+ max_retries=max_retries,
453
+ error_map=error_map,
454
+ )
455
+
456
+ @overload
457
+ def _put(
458
+ self,
459
+ path: str = ...,
460
+ *,
461
+ response_model: None = ...,
462
+ params: QueryParamTypes | None = ...,
463
+ content: RequestContent | None = ...,
464
+ data: RequestData | None = ...,
465
+ files: RequestFiles | None = ...,
466
+ json: Model | Any | None = ...,
467
+ xml: XMLModel | str | bytes | None = ...,
468
+ response_model_kwargs: dict[str, Any] | None = ...,
469
+ request_model_kwargs: dict[str, Any] | None = ...,
470
+ headers: dict[str, str] | None = ...,
471
+ cookies: CookieTypes | None = ...,
472
+ auth: AuthTypes | UseClientDefault | None = ...,
473
+ follow_redirects: bool | UseClientDefault = ...,
474
+ timeout: TimeoutTypes | UseClientDefault = ...,
475
+ extensions: RequestExtensions | None = ...,
476
+ max_retries: int | None = ...,
477
+ error_map: dict[int, ErrorStatus] | None = ...,
478
+ ) -> Response: ...
479
+
480
+ @overload
481
+ def _put(
482
+ self,
483
+ path: str = ...,
484
+ *,
485
+ response_model: type[Model],
486
+ params: QueryParamTypes | None = ...,
487
+ content: RequestContent | None = ...,
488
+ data: RequestData | None = ...,
489
+ files: RequestFiles | None = ...,
490
+ json: Model | Any | None = ...,
491
+ xml: XMLModel | str | bytes | None = ...,
492
+ response_model_kwargs: dict[str, Any] | None = ...,
493
+ request_model_kwargs: dict[str, Any] | None = ...,
494
+ headers: dict[str, str] | None = ...,
495
+ cookies: CookieTypes | None = ...,
496
+ auth: AuthTypes | UseClientDefault | None = ...,
497
+ follow_redirects: bool | UseClientDefault = ...,
498
+ timeout: TimeoutTypes | UseClientDefault = ...,
499
+ extensions: RequestExtensions | None = ...,
500
+ max_retries: int | None = ...,
501
+ error_map: dict[int, ErrorStatus] | None = ...,
502
+ ) -> Model: ...
503
+
504
+ @overload
505
+ def _put(
506
+ self,
507
+ path: str = ...,
508
+ *,
509
+ response_model: type[list[Model]],
510
+ params: QueryParamTypes | None = ...,
511
+ content: RequestContent | None = ...,
512
+ data: RequestData | None = ...,
513
+ files: RequestFiles | None = ...,
514
+ json: Model | Any | None = ...,
515
+ xml: XMLModel | str | bytes | None = ...,
516
+ response_model_kwargs: dict[str, Any] | None = ...,
517
+ request_model_kwargs: dict[str, Any] | None = ...,
518
+ headers: dict[str, str] | None = ...,
519
+ cookies: CookieTypes | None = ...,
520
+ auth: AuthTypes | UseClientDefault | None = ...,
521
+ follow_redirects: bool | UseClientDefault = ...,
522
+ timeout: TimeoutTypes | UseClientDefault = ...,
523
+ extensions: RequestExtensions | None = ...,
524
+ max_retries: int | None = ...,
525
+ error_map: dict[int, ErrorStatus] | None = ...,
526
+ ) -> list[Model]: ...
527
+
528
+ def _put(
529
+ self,
530
+ path: str = "",
531
+ *,
532
+ params: QueryParamTypes | None = None,
533
+ content: RequestContent | None = None,
534
+ data: RequestData | None = None,
535
+ files: RequestFiles | None = None,
536
+ json: Model | Any | None = None,
537
+ xml: XMLModel | str | bytes | None = None,
538
+ headers: dict[str, str] | None = None,
539
+ response_model: type[Model | list[Model]] | None = None,
540
+ response_model_kwargs: dict[str, Any] | None = None,
541
+ request_model_kwargs: dict[str, Any] | None = None,
542
+ cookies: CookieTypes | None = None,
543
+ auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
544
+ follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
545
+ timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
546
+ extensions: RequestExtensions | None = None,
547
+ max_retries: int | None = None,
548
+ error_map: dict[int, ErrorStatus] | None = None,
549
+ ) -> Model | list[Model] | Response:
550
+ """
551
+ Construct and send an HTTP PUT request.
552
+
553
+ Args:
554
+ path:
555
+ URL to query.
556
+ response_model:
557
+ Pydantic model to coerce the response into.
558
+ response_model_kwargs:
559
+ Keyword arguments to pass to Pydantic/Pydantic-XML as part of
560
+ un-marshalling the response data.
561
+ request_model_kwargs:
562
+ Keyword arguments to pass to Pydantic/Pydantic-XML as part of
563
+ marshalling the body of the data into the request.
564
+ params:
565
+ Request query parameters.
566
+ content:
567
+ Raw body of the request.
568
+ data:
569
+ URL form-encoded body for the request.
570
+ json:
571
+ Data object to marshal into JSON. Content passed with this parameter
572
+ will also set the ``Content-Type`` header to ``application/json``.
573
+ xml:
574
+ Data object to marshal into XML. Content passed with this parameter
575
+ will also set the ``Content-Type`` header to ``application/json``.
576
+ files:
577
+ A dictionary of upload files to include in the body of the request.
578
+ headers:
579
+ Request-specific headers.
580
+ cookies:
581
+ Request-specific cookies.
582
+ auth:
583
+ Request-specific authentication.
584
+ follow_redirects:
585
+ Should the client follow any redirects?
586
+ timeout:
587
+ Request-specific timeout settings.
588
+ extensions:
589
+ Any additional httpx extensions to pass to the client.
590
+ max_retries:
591
+ The maximum number of retries to attempt before giving up. Overloads
592
+ the client default.
593
+ error_map:
594
+ Replaces the client error map with this one instead.
595
+
596
+ Returns:
597
+ Returns the HTTPX Response object if no response_model is specified. If a
598
+ response_model _is_ specified, then the response will be coerced into the
599
+ response model and the instance of the model will be returned.
600
+ """
601
+ return self._request(
602
+ method="PUT",
603
+ path=path,
604
+ params=params,
605
+ content=content,
606
+ data=data,
607
+ files=files,
608
+ json=json,
609
+ xml=xml,
610
+ headers=headers,
611
+ cookies=cookies,
612
+ auth=auth,
613
+ follow_redirects=follow_redirects,
614
+ timeout=timeout,
615
+ extensions=extensions,
616
+ response_model=response_model,
617
+ response_model_kwargs=response_model_kwargs,
618
+ request_model_kwargs=request_model_kwargs,
619
+ max_retries=max_retries,
620
+ error_map=error_map,
621
+ )
622
+
623
+ @overload
624
+ def _patch(
625
+ self,
626
+ path: str = ...,
627
+ *,
628
+ response_model: None = ...,
629
+ params: QueryParamTypes | None = ...,
630
+ content: RequestContent | None = ...,
631
+ data: RequestData | None = ...,
632
+ files: RequestFiles | None = ...,
633
+ json: Model | Any | None = ...,
634
+ xml: XMLModel | str | bytes | None = ...,
635
+ response_model_kwargs: dict[str, Any] | None = ...,
636
+ request_model_kwargs: dict[str, Any] | None = ...,
637
+ headers: dict[str, str] | None = ...,
638
+ cookies: CookieTypes | None = ...,
639
+ auth: AuthTypes | UseClientDefault | None = ...,
640
+ follow_redirects: bool | UseClientDefault = ...,
641
+ timeout: TimeoutTypes | UseClientDefault = ...,
642
+ extensions: RequestExtensions | None = ...,
643
+ max_retries: int | None = ...,
644
+ error_map: dict[int, ErrorStatus] | None = ...,
645
+ ) -> Response: ...
646
+
647
+ @overload
648
+ def _patch(
649
+ self,
650
+ path: str = ...,
651
+ *,
652
+ response_model: type[Model],
653
+ params: QueryParamTypes | None = ...,
654
+ content: RequestContent | None = ...,
655
+ data: RequestData | None = ...,
656
+ files: RequestFiles | None = ...,
657
+ json: Model | Any | None = ...,
658
+ xml: XMLModel | str | bytes | None = ...,
659
+ response_model_kwargs: dict[str, Any] | None = ...,
660
+ request_model_kwargs: dict[str, Any] | None = ...,
661
+ headers: dict[str, str] | None = ...,
662
+ cookies: CookieTypes | None = ...,
663
+ auth: AuthTypes | UseClientDefault | None = ...,
664
+ follow_redirects: bool | UseClientDefault = ...,
665
+ timeout: TimeoutTypes | UseClientDefault = ...,
666
+ extensions: RequestExtensions | None = ...,
667
+ max_retries: int | None = ...,
668
+ error_map: dict[int, ErrorStatus] | None = ...,
669
+ ) -> Model: ...
670
+
671
+ @overload
672
+ def _patch(
673
+ self,
674
+ path: str = ...,
675
+ *,
676
+ response_model: type[list[Model]],
677
+ params: QueryParamTypes | None = ...,
678
+ content: RequestContent | None = ...,
679
+ data: RequestData | None = ...,
680
+ files: RequestFiles | None = ...,
681
+ json: Model | Any | None = ...,
682
+ xml: XMLModel | str | bytes | None = ...,
683
+ response_model_kwargs: dict[str, Any] | None = ...,
684
+ request_model_kwargs: dict[str, Any] | None = ...,
685
+ headers: dict[str, str] | None = ...,
686
+ cookies: CookieTypes | None = ...,
687
+ auth: AuthTypes | UseClientDefault | None = ...,
688
+ follow_redirects: bool | UseClientDefault = ...,
689
+ timeout: TimeoutTypes | UseClientDefault = ...,
690
+ extensions: RequestExtensions | None = ...,
691
+ max_retries: int | None = ...,
692
+ error_map: dict[int, ErrorStatus] | None = ...,
693
+ ) -> list[Model]: ...
694
+
695
+ def _patch(
696
+ self,
697
+ path: str = "",
698
+ *,
699
+ params: QueryParamTypes | None = None,
700
+ content: RequestContent | None = None,
701
+ data: RequestData | None = None,
702
+ files: RequestFiles | None = None,
703
+ json: Model | Any | None = None,
704
+ xml: XMLModel | str | bytes | None = None,
705
+ headers: dict[str, str] | None = None,
706
+ response_model: type[Model | list[Model]] | None = None,
707
+ response_model_kwargs: dict[str, Any] | None = None,
708
+ request_model_kwargs: dict[str, Any] | None = None,
709
+ cookies: CookieTypes | None = None,
710
+ auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
711
+ follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
712
+ timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
713
+ extensions: RequestExtensions | None = None,
714
+ max_retries: int | None = None,
715
+ error_map: dict[int, ErrorStatus] | None = None,
716
+ ) -> Model | list[Model] | Response:
717
+ """
718
+ Construct and send an HTTP PATCH request.
719
+
720
+ Args:
721
+ path:
722
+ URL to query.
723
+ response_model:
724
+ Pydantic model to coerce the response into.
725
+ response_model_kwargs:
726
+ Keyword arguments to pass to Pydantic/Pydantic-XML as part of
727
+ un-marshalling the response data.
728
+ request_model_kwargs:
729
+ Keyword arguments to pass to Pydantic/Pydantic-XML as part of
730
+ marshalling the body of the data into the request.
731
+ params:
732
+ Request query parameters.
733
+ content:
734
+ Raw body of the request.
735
+ data:
736
+ URL form-encoded body for the request.
737
+ json:
738
+ Data object to marshal into JSON. Content passed with this parameter
739
+ will also set the ``Content-Type`` header to ``application/json``.
740
+ xml:
741
+ Data object to marshal into XML. Content passed with this parameter
742
+ will also set the ``Content-Type`` header to ``application/json``.
743
+ files:
744
+ A dictionary of upload files to include in the body of the request.
745
+ headers:
746
+ Request-specific headers.
747
+ cookies:
748
+ Request-specific cookies.
749
+ auth:
750
+ Request-specific authentication.
751
+ follow_redirects:
752
+ Should the client follow any redirects?
753
+ timeout:
754
+ Request-specific timeout settings.
755
+ extensions:
756
+ Any additional httpx extensions to pass to the client.
757
+ max_retries:
758
+ The maximum number of retries to attempt before giving up. Overloads
759
+ the client default.
760
+ error_map:
761
+ Replaces the client error map with this one instead.
762
+
763
+ Returns:
764
+ Returns the HTTPX Response object if no response_model is specified. If a
765
+ response_model _is_ specified, then the response will be coerced into the
766
+ response model and the instance of the model will be returned.
767
+ """
768
+ return self._request(
769
+ method="PATCH",
770
+ path=path,
771
+ params=params,
772
+ content=content,
773
+ data=data,
774
+ files=files,
775
+ json=json,
776
+ xml=xml,
777
+ headers=headers,
778
+ cookies=cookies,
779
+ auth=auth,
780
+ follow_redirects=follow_redirects,
781
+ timeout=timeout,
782
+ extensions=extensions,
783
+ response_model=response_model,
784
+ response_model_kwargs=response_model_kwargs,
785
+ request_model_kwargs=request_model_kwargs,
786
+ max_retries=max_retries,
787
+ error_map=error_map,
788
+ )
789
+
790
+ @overload
791
+ def _delete(
792
+ self,
793
+ path: str = ...,
794
+ *,
795
+ response_model: None = ...,
796
+ params: QueryParamTypes | None = ...,
797
+ content: RequestContent | None = ...,
798
+ data: RequestData | None = ...,
799
+ files: RequestFiles | None = ...,
800
+ json: Model | Any | None = ...,
801
+ xml: XMLModel | str | bytes | None = ...,
802
+ response_model_kwargs: dict[str, Any] | None = ...,
803
+ request_model_kwargs: dict[str, Any] | None = ...,
804
+ headers: dict[str, str] | None = ...,
805
+ cookies: CookieTypes | None = ...,
806
+ auth: AuthTypes | UseClientDefault | None = ...,
807
+ follow_redirects: bool | UseClientDefault = ...,
808
+ timeout: TimeoutTypes | UseClientDefault = ...,
809
+ extensions: RequestExtensions | None = ...,
810
+ max_retries: int | None = ...,
811
+ error_map: dict[int, ErrorStatus] | None = ...,
812
+ ) -> Response: ...
813
+
814
+ @overload
815
+ def _delete(
816
+ self,
817
+ path: str = ...,
818
+ *,
819
+ response_model: type[Model],
820
+ params: QueryParamTypes | None = ...,
821
+ content: RequestContent | None = ...,
822
+ data: RequestData | None = ...,
823
+ files: RequestFiles | None = ...,
824
+ json: Model | Any | None = ...,
825
+ xml: XMLModel | str | bytes | None = ...,
826
+ response_model_kwargs: dict[str, Any] | None = ...,
827
+ request_model_kwargs: dict[str, Any] | None = ...,
828
+ headers: dict[str, str] | None = ...,
829
+ cookies: CookieTypes | None = ...,
830
+ auth: AuthTypes | UseClientDefault | None = ...,
831
+ follow_redirects: bool | UseClientDefault = ...,
832
+ timeout: TimeoutTypes | UseClientDefault = ...,
833
+ extensions: RequestExtensions | None = ...,
834
+ max_retries: int | None = ...,
835
+ error_map: dict[int, ErrorStatus] | None = ...,
836
+ ) -> Model: ...
837
+
838
+ @overload
839
+ def _delete(
840
+ self,
841
+ path: str = ...,
842
+ *,
843
+ response_model: type[list[Model]],
844
+ params: QueryParamTypes | None = ...,
845
+ content: RequestContent | None = ...,
846
+ data: RequestData | None = ...,
847
+ files: RequestFiles | None = ...,
848
+ json: Model | Any | None = ...,
849
+ xml: XMLModel | str | bytes | None = ...,
850
+ response_model_kwargs: dict[str, Any] | None = ...,
851
+ request_model_kwargs: dict[str, Any] | None = ...,
852
+ headers: dict[str, str] | None = ...,
853
+ cookies: CookieTypes | None = ...,
854
+ auth: AuthTypes | UseClientDefault | None = ...,
855
+ follow_redirects: bool | UseClientDefault = ...,
856
+ timeout: TimeoutTypes | UseClientDefault = ...,
857
+ extensions: RequestExtensions | None = ...,
858
+ max_retries: int | None = ...,
859
+ error_map: dict[int, ErrorStatus] | None = ...,
860
+ ) -> list[Model]: ...
861
+
862
+ def _delete(
863
+ self,
864
+ path: str = "",
865
+ *,
866
+ params: QueryParamTypes | None = None,
867
+ content: RequestContent | None = None,
868
+ data: RequestData | None = None,
869
+ files: RequestFiles | None = None,
870
+ json: Model | Any | None = None,
871
+ xml: XMLModel | str | bytes | None = None,
872
+ headers: dict[str, str] | None = None,
873
+ response_model: type[Model | list[Model]] | None = None,
874
+ response_model_kwargs: dict[str, Any] | None = None,
875
+ request_model_kwargs: dict[str, Any] | None = None,
876
+ cookies: CookieTypes | None = None,
877
+ auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
878
+ follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
879
+ timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
880
+ extensions: RequestExtensions | None = None,
881
+ max_retries: int | None = None,
882
+ error_map: dict[int, ErrorStatus] | None = None,
883
+ ) -> Model | list[Model] | Response:
884
+ """
885
+ Construct and send an HTTP DELETE request.
886
+
887
+ Args:
888
+ path:
889
+ URL to query.
890
+ response_model:
891
+ Pydantic model to coerce the response into.
892
+ response_model_kwargs:
893
+ Keyword arguments to pass to Pydantic/Pydantic-XML as part of
894
+ un-marshalling the response data.
895
+ request_model_kwargs:
896
+ Keyword arguments to pass to Pydantic/Pydantic-XML as part of
897
+ marshalling the body of the data into the request.
898
+ params:
899
+ Request query parameters.
900
+ content:
901
+ Raw body of the request.
902
+ data:
903
+ URL form-encoded body for the request.
904
+ json:
905
+ Data object to marshal into JSON. Content passed with this parameter
906
+ will also set the ``Content-Type`` header to ``application/json``.
907
+ xml:
908
+ Data object to marshal into XML. Content passed with this parameter
909
+ will also set the ``Content-Type`` header to ``application/json``.
910
+ files:
911
+ A dictionary of upload files to include in the body of the request.
912
+ headers:
913
+ Request-specific headers.
914
+ cookies:
915
+ Request-specific cookies.
916
+ auth:
917
+ Request-specific authentication.
918
+ follow_redirects:
919
+ Should the client follow any redirects?
920
+ timeout:
921
+ Request-specific timeout settings.
922
+ extensions:
923
+ Any additional httpx extensions to pass to the client.
924
+ max_retries:
925
+ The maximum number of retries to attempt before giving up. Overloads
926
+ the client default.
927
+ error_map:
928
+ Replaces the client error map with this one instead.
929
+
930
+ Returns:
931
+ Returns the HTTPX Response object if no response_model is specified. If a
932
+ response_model _is_ specified, then the response will be coerced into the
933
+ response model and the instance of the model will be returned.
934
+ """
935
+ return self._request(
936
+ method="DELETE",
937
+ path=path,
938
+ params=params,
939
+ content=content,
940
+ data=data,
941
+ files=files,
942
+ json=json,
943
+ xml=xml,
944
+ headers=headers,
945
+ cookies=cookies,
946
+ auth=auth,
947
+ follow_redirects=follow_redirects,
948
+ timeout=timeout,
949
+ extensions=extensions,
950
+ response_model=response_model,
951
+ response_model_kwargs=response_model_kwargs,
952
+ request_model_kwargs=request_model_kwargs,
953
+ max_retries=max_retries,
954
+ error_map=error_map,
955
+ )
956
+
957
+
958
+ class APIEndpoint(APIBaseEndpoint, HTTPClientVerbs):
959
+ _client: APIClient
960
+
961
+ def __init__(self, client: APIClient | APIEndpoint) -> None:
962
+ super().__init__(client)
963
+
964
+ @overload
965
+ def _request(
966
+ self,
967
+ method: HTTPMethods,
968
+ path: str = ...,
969
+ *,
970
+ response_model: None = ...,
971
+ params: QueryParamTypes | None = ...,
972
+ content: RequestContent | None = ...,
973
+ data: RequestData | None = ...,
974
+ files: RequestFiles | None = ...,
975
+ json: Model | Any | None = ...,
976
+ xml: XMLModel | str | bytes | None = ...,
977
+ response_model_kwargs: dict[str, Any] | None = ...,
978
+ request_model_kwargs: dict[str, Any] | None = ...,
979
+ headers: dict[str, str] | None = ...,
980
+ cookies: CookieTypes | None = ...,
981
+ auth: AuthTypes | UseClientDefault | None = ...,
982
+ follow_redirects: bool | UseClientDefault = ...,
983
+ timeout: TimeoutTypes | UseClientDefault = ...,
984
+ extensions: RequestExtensions | None = ...,
985
+ max_retries: int | None = ...,
986
+ error_map: dict[int, ErrorStatus] | None = ...,
987
+ stream: bool = ...,
988
+ ) -> Response: ...
989
+
990
+ @overload
991
+ def _request(
992
+ self,
993
+ method: HTTPMethods,
994
+ path: str = ...,
995
+ *,
996
+ response_model: type[Model],
997
+ params: QueryParamTypes | None = ...,
998
+ content: RequestContent | None = ...,
999
+ data: RequestData | None = ...,
1000
+ files: RequestFiles | None = ...,
1001
+ json: Model | Any | None = ...,
1002
+ xml: XMLModel | str | bytes | None = ...,
1003
+ response_model_kwargs: dict[str, Any] | None = ...,
1004
+ request_model_kwargs: dict[str, Any] | None = ...,
1005
+ headers: dict[str, str] | None = ...,
1006
+ cookies: CookieTypes | None = ...,
1007
+ auth: AuthTypes | UseClientDefault | None = ...,
1008
+ follow_redirects: bool | UseClientDefault = ...,
1009
+ timeout: TimeoutTypes | UseClientDefault = ...,
1010
+ extensions: RequestExtensions | None = ...,
1011
+ max_retries: int | None = ...,
1012
+ error_map: dict[int, ErrorStatus] | None = ...,
1013
+ stream: bool = False,
1014
+ ) -> Model: ...
1015
+
1016
+ @overload
1017
+ def _request(
1018
+ self,
1019
+ method: HTTPMethods,
1020
+ path: str = ...,
1021
+ *,
1022
+ response_model: type[list[Model]],
1023
+ params: QueryParamTypes | None = ...,
1024
+ content: RequestContent | None = ...,
1025
+ data: RequestData | None = ...,
1026
+ files: RequestFiles | None = ...,
1027
+ json: Model | Any | None = ...,
1028
+ xml: XMLModel | str | bytes | None = ...,
1029
+ response_model_kwargs: dict[str, Any] | None = ...,
1030
+ request_model_kwargs: dict[str, Any] | None = ...,
1031
+ headers: dict[str, str] | None = ...,
1032
+ cookies: CookieTypes | None = ...,
1033
+ auth: AuthTypes | UseClientDefault | None = ...,
1034
+ follow_redirects: bool | UseClientDefault = ...,
1035
+ timeout: TimeoutTypes | UseClientDefault = ...,
1036
+ extensions: RequestExtensions | None = ...,
1037
+ max_retries: int | None = ...,
1038
+ error_map: dict[int, ErrorStatus] | None = ...,
1039
+ stream: bool = False,
1040
+ ) -> list[Model]: ...
1041
+
1042
+ @overload
1043
+ def _request(
1044
+ self,
1045
+ method: HTTPMethods,
1046
+ path: str = ...,
1047
+ *,
1048
+ response_model: type[Model | list[Model]] | None = ...,
1049
+ params: QueryParamTypes | None = ...,
1050
+ content: RequestContent | None = ...,
1051
+ data: RequestData | None = ...,
1052
+ files: RequestFiles | None = ...,
1053
+ json: Model | Any | None = ...,
1054
+ xml: XMLModel | str | bytes | None = ...,
1055
+ response_model_kwargs: dict[str, Any] | None = ...,
1056
+ request_model_kwargs: dict[str, Any] | None = ...,
1057
+ headers: dict[str, str] | None = ...,
1058
+ cookies: CookieTypes | None = ...,
1059
+ auth: AuthTypes | UseClientDefault | None = ...,
1060
+ follow_redirects: bool | UseClientDefault = ...,
1061
+ timeout: TimeoutTypes | UseClientDefault = ...,
1062
+ extensions: RequestExtensions | None = ...,
1063
+ max_retries: int | None = ...,
1064
+ error_map: dict[int, ErrorStatus] | None = ...,
1065
+ stream: bool = ...,
1066
+ ) -> Model | list[Model] | Response: ...
1067
+
1068
+ @override
1069
+ def _request(
1070
+ self,
1071
+ method: HTTPMethods,
1072
+ path: str = "",
1073
+ *,
1074
+ params: QueryParamTypes | None = None,
1075
+ content: RequestContent | None = None,
1076
+ data: RequestData | None = None,
1077
+ files: RequestFiles | None = None,
1078
+ headers: dict[str, str] | None = None,
1079
+ json: Model | Any | None = None,
1080
+ xml: XMLModel | str | bytes | None = None,
1081
+ response_model: type[Model | list[Model]] | None = None,
1082
+ response_model_kwargs: dict[str, Any] | None = None,
1083
+ request_model_kwargs: dict[str, Any] | None = None,
1084
+ cookies: CookieTypes | None = None,
1085
+ auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
1086
+ follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
1087
+ timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
1088
+ extensions: RequestExtensions | None = None,
1089
+ max_retries: int | None = None,
1090
+ error_map: dict[int, ErrorStatus] | None = None,
1091
+ stream: bool = False,
1092
+ ) -> Model | list[Model] | Response:
1093
+ """
1094
+ Construct and send an HTTP POST request.
1095
+
1096
+ Args:
1097
+ method:
1098
+ The HTTP method used for the request.
1099
+ path:
1100
+ URL to query.
1101
+ response_model:
1102
+ Pydantic model to coerce the response into.
1103
+ response_model_kwargs:
1104
+ Keyword arguments to pass to Pydantic/Pydantic-XML as part of
1105
+ un-marshalling the response data.
1106
+ request_model_kwargs:
1107
+ Keyword arguments to pass to Pydantic/Pydantic-XML as part of
1108
+ marshalling the body of the data into the request.
1109
+ params:
1110
+ Request query parameters.
1111
+ content:
1112
+ Raw body of the request.
1113
+ data:
1114
+ URL form-encoded body for the request.
1115
+ json:
1116
+ Data object to marshal into JSON. Content passed with this parameter
1117
+ will also set the ``Content-Type`` header to ``application/json``.
1118
+ xml:
1119
+ Data object to marshal into XML. Content passed with this parameter
1120
+ will also set the ``Content-Type`` header to ``application/json``.
1121
+ files:
1122
+ A dictionary of upload files to include in the body of the request.
1123
+ headers:
1124
+ Request-specific headers.
1125
+ cookies:
1126
+ Request-specific cookies.
1127
+ auth:
1128
+ Request-specific authentication.
1129
+ follow_redirects:
1130
+ Should the client follow any redirects?
1131
+ timeout:
1132
+ Request-specific timeout settings.
1133
+ extensions:
1134
+ Any additional httpx extensions to pass to the client.
1135
+ max_retries:
1136
+ The maximum number of retries to attempt before giving up. Overloads
1137
+ the client default.
1138
+ error_map:
1139
+ Replaces the client error map with this one instead.
1140
+
1141
+ Returns:
1142
+ Returns the HTTPX Response object if no response_model is specified. If a
1143
+ response_model _is_ specified, then the response will be coerced into the
1144
+ response model and the instance of the model will be returned.
1145
+ """
1146
+ if self._path is not None:
1147
+ path = f"{self._path}{path}"
1148
+
1149
+ return self._client._request(
1150
+ method=method,
1151
+ path=path,
1152
+ params=params,
1153
+ headers=headers,
1154
+ cookies=cookies,
1155
+ auth=auth,
1156
+ follow_redirects=follow_redirects,
1157
+ timeout=timeout,
1158
+ extensions=extensions,
1159
+ json=json,
1160
+ xml=xml,
1161
+ content=content,
1162
+ data=data,
1163
+ files=files,
1164
+ response_model=response_model,
1165
+ max_retries=max_retries,
1166
+ response_model_kwargs=response_model_kwargs,
1167
+ request_model_kwargs=request_model_kwargs,
1168
+ error_map=error_map,
1169
+ stream=stream,
1170
+ )
1171
+
1172
+
1173
+ class APIClient(APIClientBase, HTTPClientVerbs):
1174
+ __client_class__: type[Client] = Client
1175
+ __endpoint_class__: type[APIEndpoint] = APIEndpoint
1176
+ _client: Client
1177
+
1178
+ @override
1179
+ def __assign_annotations__(self) -> None:
1180
+ """
1181
+ Any public annotations that are a subclass of the APIEndpoint class will be
1182
+ assigned at initialization of the object through this method.
1183
+ """
1184
+ assign_annotations(self, APIEndpoint)
1185
+
1186
+ def __enter__(self) -> Self:
1187
+ """
1188
+ Context Manager __enter__ dunder. See PEP-343 for more details.
1189
+ """
1190
+ return self
1191
+
1192
+ def __exit__(self, exc_type, exc_value, exc_traceback):
1193
+ """
1194
+ Context Manager __exit__ dunder. See PEP-343 for more details.
1195
+ """
1196
+ return self._deauthenticate()
1197
+
1198
+ def __init__(
1199
+ self,
1200
+ *,
1201
+ auth: AuthTypes | None = None,
1202
+ params: QueryParamTypes | None = None,
1203
+ headers: HeaderTypes | None = None,
1204
+ cookies: CookieTypes | None = None,
1205
+ verify: SSLContext | str | bool = True,
1206
+ cert: CertTypes | None = None,
1207
+ http1: bool = True,
1208
+ http2: bool = False,
1209
+ proxy: ProxyTypes | None = None,
1210
+ mounts: (dict[str, BaseTransport | None]) | None = None,
1211
+ timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG,
1212
+ follow_redirects: bool = False,
1213
+ limits: Limits = DEFAULT_LIMITS,
1214
+ max_redirects: int = DEFAULT_MAX_REDIRECTS,
1215
+ event_hooks: (dict[str, list[EventHook]]) | None = None,
1216
+ base_url: str | None = None,
1217
+ transport: BaseTransport | None = None,
1218
+ trust_env: bool = True,
1219
+ default_encoding: str | Callable[[bytes], str] = "utf-8",
1220
+ vendor: str = "unknown",
1221
+ product: str = "unknown",
1222
+ build: str = "unknown",
1223
+ retry_max: int = 5,
1224
+ json_load_kwargs: dict[str, Any] | None = None,
1225
+ json_dump_kwargs: dict[str, Any] | None = None,
1226
+ xml_load_kwargs: dict[str, Any] | None = None,
1227
+ xml_dump_kwargs: dict[str, Any] | None = None,
1228
+ error_map: dict[int, ErrorStatus] | None = None,
1229
+ error_class: type[APIError] | None = None,
1230
+ ) -> None:
1231
+ # Add the class event hooks to loop in the logging facilities.
1232
+ event_hooks = {} if event_hooks is None else event_hooks
1233
+ event_hooks = {
1234
+ "request": [self._request_hook] + list(event_hooks.get("request", [])),
1235
+ "response": [self._response_hook] + list(event_hooks.get("response", [])),
1236
+ }
1237
+ super().__init__(
1238
+ auth=auth,
1239
+ params=params,
1240
+ headers=headers,
1241
+ cookies=cookies,
1242
+ verify=verify,
1243
+ cert=cert,
1244
+ http1=http1,
1245
+ http2=http2,
1246
+ proxy=proxy,
1247
+ mounts=mounts,
1248
+ timeout=timeout,
1249
+ follow_redirects=follow_redirects,
1250
+ limits=limits,
1251
+ max_redirects=max_redirects,
1252
+ event_hooks=event_hooks,
1253
+ base_url=base_url,
1254
+ transport=transport,
1255
+ trust_env=trust_env,
1256
+ default_encoding=default_encoding,
1257
+ vendor=vendor,
1258
+ product=product,
1259
+ build=build,
1260
+ retry_max=retry_max,
1261
+ json_load_kwargs=json_load_kwargs,
1262
+ json_dump_kwargs=json_dump_kwargs,
1263
+ xml_load_kwargs=xml_load_kwargs,
1264
+ xml_dump_kwargs=xml_dump_kwargs,
1265
+ error_map=error_map,
1266
+ error_class=error_class,
1267
+ )
1268
+
1269
+ def _deauthenticate(self):
1270
+ """
1271
+ De-authentication stub. De-authentication is automatically run as part
1272
+ of leaving context within the context manager.
1273
+
1274
+ Example:
1275
+ >>> class ExampleAPISession(APISession):
1276
+ ... def _deauthenticate(self):
1277
+ ... self.delete('session/token')
1278
+ """
1279
+
1280
+ def _request_hook(self, request: Request) -> None:
1281
+ """
1282
+ The Request hook used for debug logging.
1283
+
1284
+ Args:
1285
+ request: The request object.
1286
+ """
1287
+ self._logger.debug(f"REQUESTING {request.method}: {request.url}")
1288
+
1289
+ def _response_hook(self, response: Response) -> None:
1290
+ """
1291
+ The Response hook used for informational logging.
1292
+
1293
+ Args:
1294
+ response: The response object.
1295
+ """
1296
+ self._logger.info(
1297
+ f"[{response.status_code}] {response.request.method}: {response.request.url}"
1298
+ )
1299
+
1300
+ def _retry_request(self, response: Response) -> Request:
1301
+ """
1302
+ Processes the request from the response for the purpose of retrying it again.
1303
+
1304
+ Args:
1305
+ response: The response object
1306
+ """
1307
+ return response.request
1308
+
1309
+ @overload
1310
+ def _request(
1311
+ self,
1312
+ method: HTTPMethods,
1313
+ path: str = ...,
1314
+ *,
1315
+ response_model: None = ...,
1316
+ params: QueryParamTypes | None = ...,
1317
+ content: RequestContent | None = ...,
1318
+ data: RequestData | None = ...,
1319
+ files: RequestFiles | None = ...,
1320
+ json: Model | Any | None = ...,
1321
+ xml: XMLModel | str | bytes | None = ...,
1322
+ response_model_kwargs: dict[str, Any] | None = ...,
1323
+ request_model_kwargs: dict[str, Any] | None = ...,
1324
+ headers: dict[str, str] | None = ...,
1325
+ cookies: CookieTypes | None = ...,
1326
+ auth: AuthTypes | UseClientDefault | None = ...,
1327
+ follow_redirects: bool | UseClientDefault = ...,
1328
+ timeout: TimeoutTypes | UseClientDefault = ...,
1329
+ extensions: RequestExtensions | None = ...,
1330
+ max_retries: int | None = ...,
1331
+ error_map: dict[int, ErrorStatus] | None = ...,
1332
+ stream: bool = ...,
1333
+ ) -> Response: ...
1334
+
1335
+ @overload
1336
+ def _request(
1337
+ self,
1338
+ method: HTTPMethods,
1339
+ path: str = ...,
1340
+ *,
1341
+ response_model: type[Model],
1342
+ params: QueryParamTypes | None = ...,
1343
+ content: RequestContent | None = ...,
1344
+ data: RequestData | None = ...,
1345
+ files: RequestFiles | None = ...,
1346
+ json: Model | Any | None = ...,
1347
+ xml: XMLModel | str | bytes | None = ...,
1348
+ response_model_kwargs: dict[str, Any] | None = ...,
1349
+ request_model_kwargs: dict[str, Any] | None = ...,
1350
+ headers: dict[str, str] | None = ...,
1351
+ cookies: CookieTypes | None = ...,
1352
+ auth: AuthTypes | UseClientDefault | None = ...,
1353
+ follow_redirects: bool | UseClientDefault = ...,
1354
+ timeout: TimeoutTypes | UseClientDefault = ...,
1355
+ extensions: RequestExtensions | None = ...,
1356
+ max_retries: int | None = ...,
1357
+ error_map: dict[int, ErrorStatus] | None = ...,
1358
+ stream: bool = False,
1359
+ ) -> Model: ...
1360
+
1361
+ @overload
1362
+ def _request(
1363
+ self,
1364
+ method: HTTPMethods,
1365
+ path: str = ...,
1366
+ *,
1367
+ response_model: type[list[Model]],
1368
+ params: QueryParamTypes | None = ...,
1369
+ content: RequestContent | None = ...,
1370
+ data: RequestData | None = ...,
1371
+ files: RequestFiles | None = ...,
1372
+ json: Model | Any | None = ...,
1373
+ xml: XMLModel | str | bytes | None = ...,
1374
+ response_model_kwargs: dict[str, Any] | None = ...,
1375
+ request_model_kwargs: dict[str, Any] | None = ...,
1376
+ headers: dict[str, str] | None = ...,
1377
+ cookies: CookieTypes | None = ...,
1378
+ auth: AuthTypes | UseClientDefault | None = ...,
1379
+ follow_redirects: bool | UseClientDefault = ...,
1380
+ timeout: TimeoutTypes | UseClientDefault = ...,
1381
+ extensions: RequestExtensions | None = ...,
1382
+ max_retries: int | None = ...,
1383
+ error_map: dict[int, ErrorStatus] | None = ...,
1384
+ stream: bool = False,
1385
+ ) -> list[Model]: ...
1386
+
1387
+ @overload
1388
+ def _request(
1389
+ self,
1390
+ method: HTTPMethods,
1391
+ path: str = ...,
1392
+ *,
1393
+ response_model: type[Model | list[Model]] | None = ...,
1394
+ params: QueryParamTypes | None = ...,
1395
+ content: RequestContent | None = ...,
1396
+ data: RequestData | None = ...,
1397
+ files: RequestFiles | None = ...,
1398
+ json: Model | Any | None = ...,
1399
+ xml: XMLModel | str | bytes | None = ...,
1400
+ response_model_kwargs: dict[str, Any] | None = ...,
1401
+ request_model_kwargs: dict[str, Any] | None = ...,
1402
+ headers: dict[str, str] | None = ...,
1403
+ cookies: CookieTypes | None = ...,
1404
+ auth: AuthTypes | UseClientDefault | None = ...,
1405
+ follow_redirects: bool | UseClientDefault = ...,
1406
+ timeout: TimeoutTypes | UseClientDefault = ...,
1407
+ extensions: RequestExtensions | None = ...,
1408
+ max_retries: int | None = ...,
1409
+ error_map: dict[int, ErrorStatus] | None = ...,
1410
+ stream: bool = ...,
1411
+ ) -> Model | list[Model] | Response: ...
1412
+
1413
+ @override
1414
+ def _request(
1415
+ self,
1416
+ method: HTTPMethods,
1417
+ path: str = "",
1418
+ *,
1419
+ response_model: type[Model | list[Model]] | None = None,
1420
+ params: QueryParamTypes | None = None,
1421
+ content: RequestContent | None = None,
1422
+ data: RequestData | None = None,
1423
+ files: RequestFiles | None = None,
1424
+ headers: dict[str, str] | None = None,
1425
+ json: Model | Any | None = None,
1426
+ xml: XMLModel | str | bytes | None = None,
1427
+ response_model_kwargs: dict[str, Any] | None = None,
1428
+ request_model_kwargs: dict[str, Any] | None = None,
1429
+ cookies: CookieTypes | None = None,
1430
+ auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
1431
+ follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT,
1432
+ timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT,
1433
+ extensions: RequestExtensions | None = None,
1434
+ max_retries: int | None = None,
1435
+ error_map: dict[int, ErrorStatus] | None = None,
1436
+ stream: bool = False,
1437
+ ) -> Model | list[Model] | Response:
1438
+ """
1439
+ Construct and send an HTTP request.
1440
+
1441
+ Args:
1442
+ method:
1443
+ The HTTP method used to make the call.
1444
+ path:
1445
+ URL to query.
1446
+ response_model:
1447
+ Pydantic model to coerce the response into.
1448
+ response_model_kwargs:
1449
+ Keyword arguments to pass to Pydantic/Pydantic-XML as part of
1450
+ un-marshalling the response data.
1451
+ request_model_kwargs:
1452
+ Keyword arguments to pass to Pydantic/Pydantic-XML as part of
1453
+ marshalling the body of the data into the request.
1454
+ params:
1455
+ Request query parameters.
1456
+ content:
1457
+ Raw body of the request.
1458
+ data:
1459
+ URL form-encoded body for the request.
1460
+ json:
1461
+ Data object to marshal into JSON. Content passed with this parameter
1462
+ will also set the ``Content-Type`` header to ``application/json``.
1463
+ xml:
1464
+ Data object to marshal into XML. Content passed with this parameter
1465
+ will also set the ``Content-Type`` header to ``application/json``.
1466
+ files:
1467
+ A dictionary of upload files to include in the body of the request.
1468
+ headers:
1469
+ Request-specific headers.
1470
+ cookies:
1471
+ Request-specific cookies.
1472
+ auth:
1473
+ Request-specific authentication.
1474
+ follow_redirects:
1475
+ Should the client follow any redirects?
1476
+ timeout:
1477
+ Request-specific timeout settings.
1478
+ extensions:
1479
+ Any additional httpx extensions to pass to the client.
1480
+ max_retries:
1481
+ The maximum number of retries to attempt before giving up. Overloads
1482
+ the client default.
1483
+ error_map:
1484
+ Replaces the client error map with this one instead.
1485
+
1486
+ Returns:
1487
+ Returns the HTTPX Response object if no response_model is specified. If a
1488
+ response_model _is_ specified, then the response will be coerced into the
1489
+ response model and the instance of the model will be returned.
1490
+ """
1491
+ max_retries = max_retries if max_retries else self._retry_max
1492
+ error_map = self._error_map if error_map is None else error_map
1493
+ response_model_kwargs = (
1494
+ {} if response_model_kwargs is None else response_model_kwargs
1495
+ )
1496
+
1497
+ # Perform any pre-processing necessary on the request.
1498
+ kwargs = self._request_pre_process(
1499
+ method=method,
1500
+ url=path,
1501
+ params=params,
1502
+ content=content,
1503
+ data=data,
1504
+ files=files,
1505
+ json=json,
1506
+ xml=xml,
1507
+ headers=headers,
1508
+ cookies=cookies,
1509
+ timeout=timeout,
1510
+ extensions=extensions,
1511
+ request_model_kwargs=request_model_kwargs,
1512
+ )
1513
+
1514
+ # Build the initial request and initialize the counter.
1515
+ request = self._client.build_request(**kwargs)
1516
+ request_counter = 0
1517
+
1518
+ # While the number of requests being performed is less than or equal to the
1519
+ # maximum number allowed, then keep calling the API.
1520
+ while request_counter <= max_retries:
1521
+ request_counter += 1
1522
+ response = self._client.send(
1523
+ request, auth=auth, follow_redirects=follow_redirects, stream=stream
1524
+ )
1525
+
1526
+ # If the response is ok, then we should return the response. If a model is
1527
+ # presented to us, then we will pass the model to the unmarshal utility to
1528
+ # handle transitioning the data into the expected class.
1529
+ if response.status_code == codes.OK and response_model:
1530
+ return unmarshal(
1531
+ response=response,
1532
+ model=response_model,
1533
+ client=self,
1534
+ json_model_kwargs=self._json_load_kwargs | response_model_kwargs,
1535
+ xml_model_kwargs=self._xml_load_kwargs | response_model_kwargs,
1536
+ )
1537
+
1538
+ # If no model was passed, then simply return the response object.
1539
+ elif response.status_code == codes.OK:
1540
+ return response
1541
+
1542
+ # As the response wasn't ok, let's grab the ErrorStatus object that relates
1543
+ # to the status code that we got and determine the next steps.
1544
+ status = error_map[response.status_code]
1545
+
1546
+ # If the status code is retryable, then pass the response to the retry
1547
+ # handler to perform any optional transformation. Then sleep the amount
1548
+ # if time determined by the status code and then continue to the next
1549
+ # iteration.
1550
+ if status.retry:
1551
+ request = self._retry_request(response)
1552
+ timer = random.uniform(0, status.jitter) + (
1553
+ request_counter * status.backoff
1554
+ )
1555
+ sleep(timer)
1556
+ continue
1557
+
1558
+ # Otherwise we will want to raise the error as specified by the error map
1559
+ error_obj = None
1560
+ raise status.exception(
1561
+ response=response, template=status.template, obj=error_obj
1562
+ )
1563
+
1564
+ # If too many attempts were made, then raise a retry error.
1565
+ raise RetryError(url=str(path), method=method, attempts=request_counter)