Opened 4 years ago
Closed 4 years ago
#31833 closed Bug (invalid)
FileField with a custom validator leads to "I/O operation on closed file".
Reported by: | elmajax | Owned by: | Harpreet Sharma |
---|---|---|---|
Component: | Forms | Version: | 3.0 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
After posting a form with a unique FileField, "I/O operation on closed file" exception occurs. Code provoking the error is within the view. I doubled checked that form is properly validated from view and validator.
Strangely the validator class (file is processed differently) doesn't throw an "I/O operation on closed file" exception when file is converted with io.TextIOWrapper and processed (see validators.py code below) and work properly.
It seems that somehow file (in memory) is flushed right after being posted without any mean to process it further with form.is_valid().
Tested on Django 2.2.25 and 3.0.8.
forms.py
from .validators import CsvFileValidator class FileImportForm(forms.Form): headers = ["lastname","firstname","gender","title","entity","email","company","address","phone"] file = forms.FileField(label='CSV file',validators=[CsvFileValidator(headers)]) def clean_file(self): file = self.cleaned_data['file'] return file
views.py
@login_required def file_import(request): if request.method == 'POST': form = FileImportForm(request.POST,request.FILES) if form.is_valid(): if request.FILES['file']: file_post = request.FILES['file'] # Offending line below (I/O operation on closed file) file_content = file_post.read().decode('UTF-8') return redirect("/foo") else: form = FileImportForm() return render(request,"file_import.html", { 'form': form })
validators.py
import csv class CsvFileValidator(object): def __init__(self, headers): self.headers = headers def __call__(self,file): file_extension = os.path.splitext(file.name)[1] valid_extensions = [ ".csv", ".CSV"] if not file_extension.lower() in valid_extensions: msg = "Invalid file extension" logger.error(msg) raise ValidationError("{}".format(msg), code='invalid') try: csv_file = io.TextIOWrapper(file) csv_format = csv.Sniffer().sniff(csv_file.read(1024)) csv_file.seek(0,0) except csv.Error: msg = "Invalid CSV file" logger.error(msg) logger.debug("Exception msg : {}".format(msg)) raise ValidationError("{}".format(msg), code='invalid') csv_reader = csv.reader(csv_file.read().splitlines(), dialect=csv_format,delimiter=";") for r_index, row in enumerate(csv_reader): if r_index == 0: if sorted(self.headers) != sorted(row): msg = "Invalid or missing CSV headers" logger.error(msg) raise ValidationError("{}".format(msg), code='invalid') if not "".join(str(field) for field in row): continue msg = "Valid CSV file" logger.debug(msg) return True def __eq__(self,other): return ( isinstance(other, self.__class__) and self.headers == other.headers )
Change History (3)
comment:1 by , 4 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:2 by , 4 years ago
Summary: | Processing file from FileField in a valid form leads to "I/O operation on closed file" exception after posting → Processing file from FileField with a custom class-based validator in a valid form leads to "I/O operation on closed file" exception after posting |
---|
comment:3 by , 4 years ago
Resolution: | → invalid |
---|---|
Status: | assigned → closed |
Summary: | Processing file from FileField with a custom class-based validator in a valid form leads to "I/O operation on closed file" exception after posting → FileField with a custom validator leads to "I/O operation on closed file". |
Please don't use trac as a support channel. Everything works properly with a stub
CsvFileValidator
:so it's not an issue in Django but in your implementation.
Closing per TicketClosingReasons/UseSupportChannels.