redc 0.1.6__cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.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.
redc/client.py ADDED
@@ -0,0 +1,810 @@
1
+ import asyncio
2
+ from typing import BinaryIO, Union
3
+ from urllib.parse import urlencode
4
+
5
+ import redc
6
+
7
+ from .callbacks import ProgressCallback, StreamCallback
8
+ from .redc_ext import RedC
9
+ from .response import Response
10
+ from .utils import Headers, json_dumps, parse_base_url, get_fsize
11
+
12
+
13
+ class Client:
14
+ """RedC client for making HTTP requests"""
15
+
16
+ def __init__(
17
+ self,
18
+ base_url: str = None,
19
+ buffer_size: int = 16384,
20
+ headers: dict = None,
21
+ timeout: tuple = (30.0, 0.0),
22
+ ca_cert_path: str = None,
23
+ force_verbose: bool = None,
24
+ raise_for_status: bool = False,
25
+ json_encoder=json_dumps,
26
+ ):
27
+ """
28
+ Initialize the RedC client
29
+
30
+ Example:
31
+ .. code-block:: python
32
+
33
+ >>> client = Client(base_url="https://example.com")
34
+ >>> response = await client.get("/api/data")
35
+
36
+ Parameters:
37
+ base_url (``str``, *optional*):
38
+ The base URL for the client. Default is ``None``
39
+
40
+ buffer_size (``int``, *optional*):
41
+ The buffer size for libcurl. Must be greater than ``1024`` bytes. Default is ``16384`` (16KB)
42
+
43
+ headers (``dict``, *optional*):
44
+ Headers to include in every request. Default is ``None``
45
+
46
+ timeout (``tuple``, *optional*):
47
+ A tuple of `(total_timeout, connect_timeout)` in seconds to include in every request. Default is ``(30.0, 0.0)``
48
+
49
+ ca_cert_path (``str``, *optional*):
50
+ Path to a CA certificate bundle file for SSL/TLS verification. Default is ``None``
51
+
52
+ force_verbose (``bool``, *optional*):
53
+ Force verbose output for all requests. Default is ``None``
54
+
55
+ raise_for_status (``bool``, *optional*):
56
+ If ``True``, automatically raises an :class:`redc.HTTPError` for responses with HTTP status codes
57
+ indicating an error (i.e., 4xx or 5xx) or for CURL errors (e.g., network issues, timeouts). Default is ``False``
58
+
59
+ json_encoder (``Callable`` , *optional*):
60
+ A callable for encoding JSON data. Default is :class:`redc.utils.json_dumps`
61
+ """
62
+
63
+ assert isinstance(base_url, (str, type(None))), "base_url must be string"
64
+ assert isinstance(buffer_size, int), "buffer_size must be int"
65
+ assert isinstance(ca_cert_path, (str, type(None))), (
66
+ "ca_cert_path must be string"
67
+ )
68
+ assert isinstance(timeout, tuple) and len(timeout) == 2, (
69
+ "timeout must be a tuple of (total_timeout, connect_timeout)"
70
+ )
71
+ assert isinstance(force_verbose, (bool, type(None))), (
72
+ "force_verbose must be bool or None"
73
+ )
74
+ assert isinstance(raise_for_status, bool), "raise_for_status must be bool"
75
+
76
+ assert buffer_size >= 1024, "buffer_size must be bigger than 1024 bytes"
77
+
78
+ self.force_verbose = force_verbose
79
+ self.raise_for_status = raise_for_status
80
+
81
+ self.__base_url = (
82
+ parse_base_url(base_url) if isinstance(base_url, str) else None
83
+ )
84
+ self.__default_headers = Headers(headers if isinstance(headers, dict) else {})
85
+ self.__timeout = timeout
86
+ self.__ca_cert_path = ca_cert_path if isinstance(ca_cert_path, str) else ""
87
+ self.__json_encoder = json_encoder
88
+ self.__loop = asyncio.get_event_loop()
89
+ self.__redc_ext = RedC(buffer_size)
90
+
91
+ self.__set_default_headers()
92
+
93
+ async def __aenter__(self):
94
+ return self
95
+
96
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
97
+ await self.close()
98
+
99
+ @property
100
+ def is_running(self):
101
+ """Checks if RedC is currently running
102
+
103
+ Returns:
104
+ ``bool``: ``True`` if RedC is running, False otherwise
105
+ """
106
+
107
+ return self.__redc_ext.is_running()
108
+
109
+ @property
110
+ def default_headers(self):
111
+ """Returns default headers that are set on all requests"""
112
+
113
+ return self.__default_headers
114
+
115
+ async def request(
116
+ self,
117
+ method: str,
118
+ url: str,
119
+ form: dict = None,
120
+ json: dict = None,
121
+ data: Union[dict[str, str], BinaryIO] = None,
122
+ files: dict[str, str] = None,
123
+ headers: dict[str, str] = None,
124
+ timeout: tuple = None,
125
+ allow_redirect: bool = True,
126
+ proxy_url: str = "",
127
+ verify: bool = True,
128
+ stream_callback: StreamCallback = None,
129
+ progress_callback: ProgressCallback = None,
130
+ verbose: bool = False,
131
+ ):
132
+ """
133
+ Make an HTTP request with the specified method and parameters
134
+
135
+ Example:
136
+ .. code-block:: python
137
+
138
+ >>> response = await client.request("GET", "/api/data", headers={"Authorization": "Bearer token"})
139
+
140
+ Parameters:
141
+ method (``str``):
142
+ The HTTP method to use (e.g., "GET", "POST")
143
+
144
+ url (``str``):
145
+ The URL to send the request to or path if ``base_url`` is specified in ``Client``
146
+
147
+ form (``dict``, *optional*):
148
+ Form data to send in the request body. Default is ``None``
149
+
150
+ json (``dict``, *optional*):
151
+ JSON data to send in the request body. Default is ``None``
152
+
153
+ data (``dict[str, str]`` || ``BinaryIO``, *optional*):
154
+ Multipart form data dict or a binary file-like object (requires ``readinto``). Default is ``None``
155
+
156
+ files (``dict[str, str]``, *optional*):
157
+ A dictionary specifying files to upload as part of a multipart form request, ``key`` is the form field and ``value`` is string containing the file path
158
+
159
+ headers (``dict[str, str]``, *optional*):
160
+ Headers to include in the request. Default is ``None``
161
+
162
+ timeout (``tuple``, *optional*):
163
+ A tuple of ``(total_timeout, connect_timeout)`` in seconds to override the default timeout.
164
+ If ``None``, the default timeout specified in ``Client`` is used.
165
+
166
+ allow_redirect (``bool``, *optional*):
167
+ Whether to allow redirects. Default is ``True``
168
+
169
+ proxy_url (``str``, *optional*):
170
+ The proxy URL to use for the request
171
+
172
+ verify (``bool``, *optional*):
173
+ Whether to verify SSL certificates. Default is ``True``
174
+
175
+ stream_callback (:class:`redc.StreamCallback`, *optional*):
176
+ Callback for streaming response data. Default is ``None``
177
+
178
+ progress_callback (:class:`redc.ProgressCallback`, *optional*):
179
+ Callback for tracking upload and download progress. Default is ``None``
180
+
181
+ verbose (``bool``, *optional*):
182
+ Whether to enable verbose output for the request. Default is ``False``
183
+
184
+ Returns:
185
+ :class:`redc.Response`
186
+ """
187
+
188
+ if stream_callback is not None:
189
+ if not isinstance(stream_callback, StreamCallback):
190
+ raise TypeError("stream_callback must be of type StreamCallback")
191
+
192
+ stream_callback = stream_callback.callback
193
+
194
+ if progress_callback is not None:
195
+ if not isinstance(progress_callback, ProgressCallback):
196
+ raise TypeError("progress_callback must be of type ProgressCallback")
197
+
198
+ progress_callback = progress_callback.callback
199
+
200
+ if form is not None:
201
+ if isinstance(form, dict):
202
+ form = urlencode(form)
203
+ else:
204
+ raise TypeError("form must be of type dict[str, str]")
205
+
206
+ if json is not None:
207
+ if isinstance(json, dict):
208
+ json = self.__json_encoder(json)
209
+ if headers is None:
210
+ headers = {}
211
+ headers["Content-Type"] = "application/json"
212
+ else:
213
+ raise TypeError("json must be of type dict[str, str]")
214
+
215
+ file_stream = None
216
+ file_size = 0
217
+ if data is not None:
218
+ if hasattr(data, "readinto"):
219
+ file_stream = data
220
+ file_size = get_fsize(file_stream)
221
+ data = None
222
+ elif not isinstance(data, dict):
223
+ raise TypeError(
224
+ "data must be either dict[str, str] or a file-like object with readinto method"
225
+ )
226
+
227
+ if files is not None:
228
+ if not isinstance(files, dict):
229
+ raise TypeError("files must be of type dict[str, str]")
230
+
231
+ timeout, connect_timeout = timeout if timeout is not None else self.__timeout
232
+
233
+ if timeout <= 0:
234
+ raise ValueError("timeout must be greater than 0")
235
+
236
+ if connect_timeout < 0:
237
+ raise ValueError("connect_timeout must be 0 or greater")
238
+ elif connect_timeout > timeout:
239
+ raise ValueError("connect_timeout must be less than `timeout` argument")
240
+
241
+ if headers is not None:
242
+ if isinstance(headers, dict):
243
+ headers = {
244
+ **self.__default_headers,
245
+ **{k.lower(): v for k, v in headers.items()},
246
+ }
247
+ headers = [f"{k}: {v}" for k, v in headers.items()]
248
+ else:
249
+ raise TypeError("headers must be of type dict[str, str]")
250
+ else:
251
+ headers = [f"{k}: {v}" for k, v in self.__default_headers.items()]
252
+
253
+ if self.__base_url:
254
+ url = f"{self.__base_url}{url.lstrip('/')}"
255
+
256
+ return Response(
257
+ *(
258
+ await self.__redc_ext.request(
259
+ method=method,
260
+ url=url,
261
+ raw_data=form or json or "",
262
+ file_stream=file_stream,
263
+ file_size=file_size,
264
+ data=data,
265
+ files=files,
266
+ headers=headers,
267
+ timeout_ms=int(timeout * 1000),
268
+ connect_timeout_ms=int(connect_timeout * 1000),
269
+ allow_redirect=allow_redirect,
270
+ proxy_url=proxy_url,
271
+ verify=verify,
272
+ ca_cert_path=self.__ca_cert_path,
273
+ stream_callback=stream_callback,
274
+ progress_callback=progress_callback,
275
+ verbose=self.force_verbose or verbose,
276
+ )
277
+ ),
278
+ raise_for_status=self.raise_for_status,
279
+ )
280
+
281
+ async def get(
282
+ self,
283
+ url: str,
284
+ headers: dict[str, str] = None,
285
+ timeout: tuple = None,
286
+ allow_redirect: bool = True,
287
+ proxy_url: str = "",
288
+ verify: bool = True,
289
+ stream_callback: StreamCallback = None,
290
+ progress_callback: ProgressCallback = None,
291
+ verbose: bool = False,
292
+ ):
293
+ """
294
+ Make a GET request
295
+
296
+ Example:
297
+ .. code-block:: python
298
+
299
+ >>> response = await client.get("/api/data", headers={"Authorization": "Bearer token"})
300
+
301
+ Parameters:
302
+ url (``str``):
303
+ The URL to send the GET request to or path if ``base_url`` is specified in ``Client``
304
+
305
+ headers (``dict[str, str]``, *optional*):
306
+ Headers to include in the request. Default is ``None``
307
+
308
+ timeout (``tuple``, *optional*):
309
+ A tuple of ``(total_timeout, connect_timeout)`` in seconds to override the default timeout.
310
+ If ``None``, the default timeout specified in ``Client`` is used.
311
+
312
+ allow_redirect (``bool``, *optional*):
313
+ Whether to allow redirects. Default is ``True``
314
+
315
+ proxy_url (``str``, *optional*):
316
+ The proxy URL to use for the request
317
+
318
+ verify (``bool``, *optional*):
319
+ Whether to verify SSL certificates. Default is ``True``
320
+
321
+ stream_callback (:class:`redc.StreamCallback`, *optional*):
322
+ Callback for streaming response data. Default is ``None``
323
+
324
+ progress_callback (:class:`redc.ProgressCallback`, *optional*):
325
+ Callback for tracking upload and download progress. Default is ``None``
326
+
327
+ verbose (``bool``, *optional*):
328
+ Whether to enable verbose output for the request. Default is ``False``
329
+
330
+ Returns:
331
+ :class:`redc.Response`
332
+ """
333
+
334
+ return await self.request(
335
+ method="GET",
336
+ url=url,
337
+ headers=headers,
338
+ timeout=timeout,
339
+ allow_redirect=allow_redirect,
340
+ proxy_url=proxy_url,
341
+ verify=verify,
342
+ stream_callback=stream_callback,
343
+ progress_callback=progress_callback,
344
+ verbose=self.force_verbose or verbose,
345
+ )
346
+
347
+ async def head(
348
+ self,
349
+ url: str,
350
+ headers: dict[str, str] = None,
351
+ timeout: tuple = None,
352
+ allow_redirect: bool = True,
353
+ proxy_url: str = "",
354
+ verify: bool = True,
355
+ verbose: bool = False,
356
+ ):
357
+ """
358
+ Make a HEAD request
359
+
360
+ Example:
361
+ .. code-block:: python
362
+
363
+ >>> response = await client.head("/api/data", headers={"Authorization": "Bearer token"})
364
+
365
+ Parameters:
366
+ url (``str``):
367
+ The URL to send the HEAD request to or path if ``base_url`` is specified in ``Client``
368
+
369
+ headers (``dict[str, str]``, *optional*):
370
+ Headers to include in the request. Default is ``None``
371
+
372
+ timeout (``tuple``, *optional*):
373
+ A tuple of ``(total_timeout, connect_timeout)`` in seconds to override the default timeout.
374
+ If ``None``, the default timeout specified in ``Client`` is used.
375
+
376
+ allow_redirect (``bool``, *optional*):
377
+ Whether to allow redirects. Default is ``True``
378
+
379
+ proxy_url (``str``, *optional*):
380
+ The proxy URL to use for the request
381
+
382
+ verify (``bool``, *optional*):
383
+ Whether to verify SSL certificates. Default is ``True``
384
+
385
+ verbose (``bool``, *optional*):
386
+ Whether to enable verbose output for the request. Default is ``False``
387
+
388
+ Returns:
389
+ :class:`redc.Response`
390
+ """
391
+
392
+ return await self.request(
393
+ method="HEAD",
394
+ url=url,
395
+ headers=headers,
396
+ timeout=timeout,
397
+ allow_redirect=allow_redirect,
398
+ proxy_url=proxy_url,
399
+ verify=verify,
400
+ verbose=self.force_verbose or verbose,
401
+ )
402
+
403
+ async def post(
404
+ self,
405
+ url: str,
406
+ form: dict = None,
407
+ json: dict = None,
408
+ data: Union[dict[str, str], BinaryIO] = None,
409
+ files: dict[str, str] = None,
410
+ headers: dict[str, str] = None,
411
+ timeout: tuple = None,
412
+ allow_redirect: bool = True,
413
+ proxy_url: str = "",
414
+ verify: bool = True,
415
+ stream_callback: StreamCallback = None,
416
+ progress_callback: ProgressCallback = None,
417
+ verbose: bool = False,
418
+ ):
419
+ """
420
+ Make a POST request
421
+
422
+ Example:
423
+ .. code-block:: python
424
+
425
+ >>> response = await client.post(
426
+ ... "/api/data",
427
+ ... json={"key": "value"},
428
+ ... headers={"Authorization": "Bearer token"}
429
+ ... )
430
+
431
+ Parameters:
432
+ url (``str``):
433
+ The URL to send the POST request to or path if ``base_url`` is specified in ``Client``
434
+
435
+ form (``dict``, *optional*):
436
+ Form data to send in the request body. Default is ``None``
437
+
438
+ json (``dict``, *optional*):
439
+ JSON data to send in the request body. Default is ``None``
440
+
441
+ data (``dict[str, str]`` || ``BinaryIO``, *optional*):
442
+ Multipart form data dict or a binary file-like object (requires ``readinto``). Default is ``None``
443
+
444
+ files (``dict[str, str]``, *optional*):
445
+ A dictionary specifying files to upload as part of a multipart form request, ``key`` is the form field and ``value`` is string containing the file path
446
+
447
+ headers (``dict[str, str]``, *optional*):
448
+ Headers to include in the request. Default is ``None``
449
+
450
+ timeout (``tuple``, *optional*):
451
+ A tuple of ``(total_timeout, connect_timeout)`` in seconds to override the default timeout.
452
+ If ``None``, the default timeout specified in ``Client`` is used.
453
+
454
+ allow_redirect (``bool``, *optional*):
455
+ Whether to allow redirects. Default is ``True``
456
+
457
+ proxy_url (``str``, *optional*):
458
+ The proxy URL to use for the request
459
+
460
+ verify (``bool``, *optional*):
461
+ Whether to verify SSL certificates. Default is ``True``
462
+
463
+ stream_callback (:class:`redc.StreamCallback`, *optional*):
464
+ Callback for streaming response data. Default is ``None``
465
+
466
+ progress_callback (:class:`redc.ProgressCallback`, *optional*):
467
+ Callback for tracking upload and download progress. Default is ``None``
468
+
469
+ verbose (``bool``, *optional*):
470
+ Whether to enable verbose output for the request. Default is ``False``
471
+
472
+ Returns:
473
+ :class:`redc.Response`
474
+ """
475
+
476
+ return await self.request(
477
+ method="POST",
478
+ url=url,
479
+ form=form,
480
+ json=json,
481
+ data=data,
482
+ files=files,
483
+ headers=headers,
484
+ timeout=timeout,
485
+ allow_redirect=allow_redirect,
486
+ proxy_url=proxy_url,
487
+ verify=verify,
488
+ stream_callback=stream_callback,
489
+ progress_callback=progress_callback,
490
+ verbose=self.force_verbose or verbose,
491
+ )
492
+
493
+ async def put(
494
+ self,
495
+ url: str,
496
+ form: dict = None,
497
+ json: dict = None,
498
+ data: Union[dict[str, str], BinaryIO] = None,
499
+ files: dict[str, str] = None,
500
+ headers: dict[str, str] = None,
501
+ timeout: tuple = None,
502
+ allow_redirect: bool = True,
503
+ proxy_url: str = "",
504
+ verify: bool = True,
505
+ stream_callback: StreamCallback = None,
506
+ progress_callback: ProgressCallback = None,
507
+ verbose: bool = False,
508
+ ):
509
+ """
510
+ Make a PUT request
511
+
512
+ Example:
513
+ .. code-block:: python
514
+
515
+ >>> response = await client.put(
516
+ ... "/api/data/1",
517
+ ... json={"key": "new_value"},
518
+ ... headers={"Authorization": "Bearer token"}
519
+ ... )
520
+
521
+ Parameters:
522
+ url (``str``):
523
+ The URL to send the PUT request to or path if ``base_url`` is specified in ``Client``
524
+
525
+ form (``dict``, *optional*):
526
+ Form data to send in the request body. Default is ``None``
527
+
528
+ json (``dict``, *optional*):
529
+ JSON data to send in the request body. Default is ``None``
530
+
531
+ data (``dict[str, str]`` || ``BinaryIO``, *optional*):
532
+ Multipart form data dict or a binary file-like object (requires ``readinto``). Default is ``None``
533
+
534
+ files (``dict[str, str]``, *optional*):
535
+ A dictionary specifying files to upload as part of a multipart form request, ``key`` is the form field and ``value`` is string containing the file path
536
+
537
+ headers (``dict[str, str]``, *optional*):
538
+ Headers to include in the request. Default is ``None``
539
+
540
+ timeout (``tuple``, *optional*):
541
+ A tuple of ``(total_timeout, connect_timeout)`` in seconds to override the default timeout.
542
+ If ``None``, the default timeout specified in ``Client`` is used.
543
+
544
+ allow_redirect (``bool``, *optional*):
545
+ Whether to allow redirects. Default is ``True``
546
+
547
+ proxy_url (``str``, *optional*):
548
+ The proxy URL to use for the request
549
+
550
+ verify (``bool``, *optional*):
551
+ Whether to verify SSL certificates. Default is ``True``
552
+
553
+ stream_callback (:class:`redc.StreamCallback`, *optional*):
554
+ Callback for streaming response data. Default is ``None``
555
+
556
+ progress_callback (:class:`redc.ProgressCallback`, *optional*):
557
+ Callback for tracking upload and download progress. Default is ``None``
558
+
559
+ verbose (``bool``, *optional*):
560
+ Whether to enable verbose output for the request. Default is ``False``
561
+
562
+ Returns:
563
+ :class:`redc.Response`
564
+ """
565
+
566
+ return await self.request(
567
+ method="PUT",
568
+ url=url,
569
+ form=form,
570
+ json=json,
571
+ data=data,
572
+ files=files,
573
+ headers=headers,
574
+ timeout=timeout,
575
+ allow_redirect=allow_redirect,
576
+ proxy_url=proxy_url,
577
+ verify=verify,
578
+ stream_callback=stream_callback,
579
+ progress_callback=progress_callback,
580
+ verbose=self.force_verbose or verbose,
581
+ )
582
+
583
+ async def patch(
584
+ self,
585
+ url: str,
586
+ form: dict = None,
587
+ json: dict = None,
588
+ data: Union[dict[str, str], BinaryIO] = None,
589
+ files: dict[str, str] = None,
590
+ headers: dict[str, str] = None,
591
+ timeout: tuple = None,
592
+ allow_redirect: bool = True,
593
+ proxy_url: str = "",
594
+ verify: bool = True,
595
+ stream_callback: StreamCallback = None,
596
+ progress_callback: ProgressCallback = None,
597
+ verbose: bool = False,
598
+ ):
599
+ """
600
+ Make a PATCH request
601
+
602
+ Example:
603
+ .. code-block:: python
604
+
605
+ >>> response = await client.patch(
606
+ ... "/api/data/1",
607
+ ... json={"key": "updated_value"},
608
+ ... headers={"Authorization": "Bearer token"}
609
+ ... )
610
+
611
+ Parameters:
612
+ url (``str``):
613
+ The URL to send the PATCH request to or path if ``base_url`` is specified in ``Client``
614
+
615
+ form (``dict``, *optional*):
616
+ Form data to send in the request body. Default is ``None``
617
+
618
+ json (``dict``, *optional*):
619
+ JSON data to send in the request body. Default is ``None``
620
+
621
+ data (``dict[str, str]`` || ``BinaryIO``, *optional*):
622
+ Multipart form data dict or a binary file-like object (requires ``readinto``). Default is ``None``
623
+
624
+ files (``dict[str, str]``, *optional*):
625
+ A dictionary specifying files to upload as part of a multipart form request, ``key`` is the form field and ``value`` is string containing the file path
626
+
627
+ headers (``dict[str, str]``, *optional*):
628
+ Headers to include in the request. Default is ``None``
629
+
630
+ timeout (``tuple``, *optional*):
631
+ A tuple of ``(total_timeout, connect_timeout)`` in seconds to override the default timeout.
632
+ If ``None``, the default timeout specified in ``Client`` is used.
633
+
634
+ allow_redirect (``bool``, *optional*):
635
+ Whether to allow redirects. Default is ``True``
636
+
637
+ proxy_url (``str``, *optional*):
638
+ The proxy URL to use for the request
639
+
640
+ verify (``bool``, *optional*):
641
+ Whether to verify SSL certificates. Default is ``True``
642
+
643
+ stream_callback (:class:`redc.StreamCallback`, *optional*):
644
+ Callback for streaming response data. Default is ``None``
645
+
646
+ progress_callback (:class:`redc.ProgressCallback`, *optional*):
647
+ Callback for tracking upload and download progress. Default is ``None``
648
+
649
+ verbose (``bool``, *optional*):
650
+ Whether to enable verbose output for the request. Default is ``False``
651
+
652
+ Returns:
653
+ :class:`redc.Response`
654
+ """
655
+
656
+ return await self.request(
657
+ method="PATCH",
658
+ url=url,
659
+ form=form,
660
+ json=json,
661
+ data=data,
662
+ files=files,
663
+ headers=headers,
664
+ timeout=timeout,
665
+ allow_redirect=allow_redirect,
666
+ proxy_url=proxy_url,
667
+ verify=verify,
668
+ stream_callback=stream_callback,
669
+ progress_callback=progress_callback,
670
+ verbose=self.force_verbose or verbose,
671
+ )
672
+
673
+ async def delete(
674
+ self,
675
+ url: str,
676
+ headers: dict[str, str] = None,
677
+ timeout: tuple = None,
678
+ allow_redirect: bool = True,
679
+ proxy_url: str = "",
680
+ verify: bool = True,
681
+ stream_callback: StreamCallback = None,
682
+ progress_callback: ProgressCallback = None,
683
+ verbose: bool = False,
684
+ ):
685
+ """
686
+ Make a DELETE request
687
+
688
+ Example:
689
+ .. code-block:: python
690
+
691
+ >>> response = await client.delete("/api/data/1", headers={"Authorization": "Bearer token"})
692
+
693
+ Parameters:
694
+ url (``str``):
695
+ The URL to send the DELETE request to or path if ``base_url`` is specified in ``Client``
696
+
697
+ headers (``dict[str, str]``, *optional*):
698
+ Headers to include in the request. Default is ``None``
699
+
700
+ timeout (``tuple``, *optional*):
701
+ A tuple of ``(total_timeout, connect_timeout)`` in seconds to override the default timeout.
702
+ If ``None``, the default timeout specified in ``Client`` is used.
703
+
704
+ allow_redirect (``bool``, *optional*):
705
+ Whether to allow redirects. Default is ``True``
706
+
707
+ proxy_url (``str``, *optional*):
708
+ The proxy URL to use for the request
709
+
710
+ verify (``bool``, *optional*):
711
+ Whether to verify SSL certificates. Default is ``True``
712
+
713
+ stream_callback (:class:`redc.StreamCallback`, *optional*):
714
+ Callback for streaming response data. Default is ``None``
715
+
716
+ progress_callback (:class:`redc.ProgressCallback`, *optional*):
717
+ Callback for tracking upload and download progress. Default is ``None``
718
+
719
+ verbose (``bool``, *optional*):
720
+ Whether to enable verbose output for the request. Default is ``False``
721
+
722
+ Returns:
723
+ :class:`redc.Response`
724
+ """
725
+
726
+ return await self.request(
727
+ method="DELETE",
728
+ url=url,
729
+ headers=headers,
730
+ timeout=timeout,
731
+ allow_redirect=allow_redirect,
732
+ proxy_url=proxy_url,
733
+ verify=verify,
734
+ stream_callback=stream_callback,
735
+ progress_callback=progress_callback,
736
+ verbose=self.force_verbose or verbose,
737
+ )
738
+
739
+ async def options(
740
+ self,
741
+ url: str,
742
+ headers: dict[str, str] = None,
743
+ timeout: tuple = None,
744
+ allow_redirect: bool = True,
745
+ proxy_url: str = "",
746
+ verify: bool = True,
747
+ verbose: bool = False,
748
+ ):
749
+ """
750
+ Make an OPTIONS request
751
+
752
+ Example:
753
+ .. code-block:: python
754
+
755
+ >>> response = await client.options("/api/data", headers={"Authorization": "Bearer token"})
756
+
757
+ Parameters:
758
+ url (``str``):
759
+ The URL to send the OPTIONS request to or path if ``base_url`` is specified in ``Client``
760
+
761
+ headers (``dict[str, str]``, *optional*):
762
+ Headers to include in the request. Default is ``None``
763
+
764
+ timeout (``tuple``, *optional*):
765
+ A tuple of ``(total_timeout, connect_timeout)`` in seconds to override the default timeout.
766
+ If ``None``, the default timeout specified in ``Client`` is used.
767
+
768
+ allow_redirect (``bool``, *optional*):
769
+ Whether to allow redirects. Default is ``True``
770
+
771
+ proxy_url (``str``, *optional*):
772
+ The proxy URL to use for the request
773
+
774
+ verify (``bool``, *optional*):
775
+ Whether to verify SSL certificates. Default is ``True``
776
+
777
+ verbose (``bool``, *optional*):
778
+ Whether to enable verbose output for the request. Default is ``False``
779
+
780
+ Returns:
781
+ :class:`redc.Response`
782
+ """
783
+
784
+ return await self.request(
785
+ method="OPTIONS",
786
+ url=url,
787
+ headers=headers,
788
+ timeout=timeout,
789
+ allow_redirect=allow_redirect,
790
+ proxy_url=proxy_url,
791
+ verify=verify,
792
+ verbose=self.force_verbose or verbose,
793
+ )
794
+
795
+ async def close(self):
796
+ """
797
+ Close the RedC client and free up resources.
798
+
799
+ This method must be called when the client is no longer needed to avoid memory leaks
800
+ or unexpected behavior
801
+ """
802
+
803
+ return await self.__loop.run_in_executor(None, self.__redc_ext.close)
804
+
805
+ def __set_default_headers(self):
806
+ if "user-agent" not in self.__default_headers:
807
+ self.__default_headers["user-agent"] = f"redc/{redc.__version__}"
808
+
809
+ if "connection" not in self.__default_headers:
810
+ self.__default_headers["connection"] = "keep-alive"