From 8e3113eff174c000c7a2380dfffbc3934991f95d Mon Sep 17 00:00:00 2001 From: Alessandro Molina Date: Mon, 19 Feb 2024 21:53:26 +0100 Subject: [PATCH] Remove usage of deprecated cgi.FieldStorage --- depot/io/interfaces.py | 7 ++++--- depot/io/utils.py | 15 ++++++++++----- depot/validators.py | 7 +++---- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/depot/io/interfaces.py b/depot/io/interfaces.py index 155b704..d0e85af 100644 --- a/depot/io/interfaces.py +++ b/depot/io/interfaces.py @@ -155,9 +155,10 @@ def get(self, file_or_id): # pragma: no cover def create(self, content, filename=None, content_type=None): # pragma: no cover """Saves a new file and returns the ID of the newly created file. - ``content`` parameter can either be ``bytes``, another ``file object`` - or a :class:`cgi.FieldStorage`. When ``filename`` and ``content_type`` - parameters are not provided they are deducted from the content itself. + ``content`` parameter can either be ``bytes``, another ``file object``, + ``multipart.MultipartPart`` or a :class:`cgi.FieldStorage`. + When ``filename`` and ``content_type`` parameters are not provided + they are deducted from the content itself. """ return diff --git a/depot/io/utils.py b/depot/io/utils.py index 06c2f93..f24446c 100644 --- a/depot/io/utils.py +++ b/depot/io/utils.py @@ -1,4 +1,3 @@ -import cgi import mimetypes import os from datetime import datetime @@ -20,13 +19,13 @@ def file_from_content(content): ``bytes`` to an actual file. """ f = content - if isinstance(content, cgi.FieldStorage): - f = content.file - elif isinstance(content, FileIntent): + if isinstance(content, FileIntent): f = content._fileobj elif isinstance(content, byte_string): f = SpooledTemporaryFile(INMEMORY_FILESIZE) f.write(content) + elif _is_fieldstorage_like(content): + f = content.file f.seek(0) return f @@ -90,7 +89,7 @@ def _resolve(self, fileobj, filename, content_type): return content, filename, content_type def _get_content_from_file_obj(self, fileobj): - if isinstance(fileobj, cgi.FieldStorage): + if _is_fieldstorage_like(fileobj): return fileobj.file return fileobj @@ -105,3 +104,9 @@ def _get_content_type_from_fileobj(self, fileobj): return fileobj.content_type elif getattr(fileobj, 'type', None) is not None: return fileobj.type + + +def _is_fieldstorage_like(obj): + # Detect cgi.FieldStorage and multipart modules + return (getattr(obj, 'filename', None) is not None and \ + getattr(obj, 'file', None) not in (None, False)) diff --git a/depot/validators.py b/depot/validators.py index 2e04656..caa13a9 100644 --- a/depot/validators.py +++ b/depot/validators.py @@ -1,5 +1,4 @@ -import cgi -from depot.io.utils import FileIntent +from depot.io.utils import FileIntent, _is_fieldstorage_like from depot.io.interfaces import FileStorage __all__ = ('TW2FileIntentValidator', ) @@ -16,7 +15,7 @@ class TW2FileIntentValidator(tw2.core.Validator): so that it preserves file details like filename and content type when uploaded. This is mostly required when working with Sprox that converts - the cgi.FieldStorage to a standard BLOB when + the cgi.FieldStorage or multipart to a standard BLOB when handling uploaded files, causing a loss of all file metadata. """ @@ -27,7 +26,7 @@ class TW2FileIntentValidator(tw2.core.Validator): } def _convert_to_python(self, value, state=None): - if isinstance(value, cgi.FieldStorage): + if is_fieldstorage_like(value): if self.required and not getattr(value, 'filename', None): raise tw2.core.ValidationError('required', self)