1616
1717DEFAULT_TIMEOUT : Final = 300.0
1818
19+ _FieldValue = str | bytes | tuple [str , str | bytes ] | tuple [str , str | bytes , str ]
20+
1921
2022class AuthABC (metaclass = abc .ABCMeta ):
2123 """
@@ -181,6 +183,7 @@ def create(
181183 uri : str ,
182184 data : dict ,
183185 params : dict [Any , Any ] | None = None ,
186+ files : dict [str , _FieldValue ] | None = None ,
184187 ) -> dict [Any , Any ] | bytes :
185188 """
186189 Makes a basic Create request to the API, and returns the response.
@@ -189,6 +192,10 @@ def create(
189192 that is serialised to JSON or bytes and strings that will be sent
190193 without serialisation.
191194
195+ When files is provided, the request is sent as multipart/form-data
196+ using urllib3's fields parameter. This takes precedence over data
197+ serialisation.
198+
192199 For POST requests parameters are encoded into the URL.
193200 https://urllib3.readthedocs.io/en/stable/user-guide.html#query-parameters
194201
@@ -200,6 +207,10 @@ def create(
200207 Payload to be sent to the API
201208 params : dict, optional
202209 Parameters to be added to the URI
210+ files : dict, optional
211+ Multipart form fields passed as urllib3 fields. Values can be
212+ plain strings/bytes for form data, (filename, data) tuples, or
213+ (filename, data, content_type) tuples for file uploads.
203214
204215 Returns
205216 -------
@@ -211,15 +222,7 @@ def create(
211222 logger .info (f"API Create Operation to { url } " )
212223
213224 self ._check_auth ()
214- if self .serialize :
215- response = self .manager .request (
216- method , url + safe_params , headers = self .request_headers , json = data
217- )
218- else :
219- response = self .manager .request (
220- method , url + safe_params , body = data , headers = self .request_headers
221- )
222-
225+ response = self ._request_with_data (method , url + safe_params , data , files )
223226 return self ._process_resp (method , response )
224227
225228 def read (
@@ -259,6 +262,7 @@ def update(
259262 data : dict [Any , Any ] | str ,
260263 params : dict [Any , Any ] | None = None ,
261264 replace : bool = False ,
265+ files : dict [str , _FieldValue ] | None = None ,
262266 ) -> dict [Any , Any ] | bytes :
263267 """
264268 Makes a basic Update request to the API, and returns the response.
@@ -267,6 +271,10 @@ def update(
267271 can be either a dictionary that is serialised to JSON or bytes and
268272 strings that will be sent without serialisation.
269273
274+ When files is provided, the request is sent as multipart/form-data
275+ using urllib3's fields parameter. This takes precedence over data
276+ serialisation.
277+
270278 For PUT requests parameters are encoded into the URL.
271279 https://urllib3.readthedocs.io/en/stable/user-guide.html#query-parameters
272280
@@ -280,6 +288,10 @@ def update(
280288 Parameters to be added to the URI
281289 replace : bool, optional
282290 Requests a full replacement of the entire entity. Uses PUT Method.
291+ files : dict, optional
292+ Multipart form fields passed as urllib3 fields. Values can be
293+ plain strings/bytes for form data, (filename, data) tuples, or
294+ (filename, data, content_type) tuples for file uploads.
283295
284296 Returns
285297 -------
@@ -291,15 +303,7 @@ def update(
291303 logger .info (f"API Update Operation to { url } " )
292304
293305 self ._check_auth ()
294- if self .serialize :
295- response = self .manager .request (
296- method , url + safe_params , headers = self .request_headers , json = data
297- )
298- else :
299- response = self .manager .request (
300- method , url + safe_params , body = data , headers = self .request_headers
301- )
302-
306+ response = self ._request_with_data (method , url + safe_params , data , files )
303307 return self ._process_resp (method , response )
304308
305309 def delete (
@@ -329,6 +333,29 @@ def delete(
329333 )
330334 return self ._process_resp (method , response )
331335
336+ def _request_with_data (
337+ self ,
338+ method : str ,
339+ url : str ,
340+ data : Any ,
341+ files : dict [str , _FieldValue ] | None ,
342+ ) -> urllib3 .response .BaseHTTPResponse :
343+ """
344+ Dispatches an HTTP request with a body payload. Multipart fields take
345+ precedence, then JSON serialisation, then raw body.
346+ """
347+ if files is not None :
348+ return self .manager .request (
349+ method , url , fields = files , headers = self .request_headers
350+ )
351+ if self .serialize :
352+ return self .manager .request (
353+ method , url , headers = self .request_headers , json = data
354+ )
355+ return self .manager .request (
356+ method , url , body = data , headers = self .request_headers
357+ )
358+
332359 def _process_resp (
333360 self ,
334361 method : str ,
0 commit comments