Hi Nick,

`io.TextIOWrapper` objects close their wrapped file when they are garbage
collected (e.g. `__del__()`). This is similar to how `File` objects close 
their
underlying file descriptor when collected.

In the case of your `clean()` method the `file` object can be garbaged 
collected
as soon as the method ends as you don't hold any more references to `reader`
(which is the only object refererencing `file`).

If you want to prevent the underlying file from being closed you'll have to
manually disconnect the `file` object from its stream by using 
`detach()`[1].

Make sure to call it in all cases, even when throwing the `ValidationError`.

Cheers,
Simon

[1] 
https://docs.python.org/3/library/io.html?highlight=textiowrapper#io.BufferedIOBase.detach

Le lundi 13 juin 2016 10:52:36 UTC-4, Nick Sarbicki a écrit :
>
> I've got an odd bug in my system, and while I'm not 100% convinced it is a 
> Django bug, I don't think it is due to me either so thought I'd ask here 
> for some clarification.
>
> Essentially if you upload a file to a form. If that forms clean() method 
> reads that file (in my case it gathers data and makes sure it is valid), 
> and the clean fails, a ValueError is always raised.
>
> ValueError at /
>
> I/O operation on closed file.
>
>
> As far as django is concerned this is happening in the template at:
>
> 31            {% if form.non_field_errors %}
> 32                <div class="alert-danger">{{ 
> form.non_field_errors|striptags 
> }}</div>
> 33                <br>
> 34            {% endif %}
>
>
> Admittedly, I am wrapping this in a TextIOWrapper.
>
> Example below is a good example of what I'm doing:
>
>
>     def clean(self):
>
>         cleaned_data = super(ReportScheduleForm, self).clean()
>
>         file = TextIOWrapper(self.cleaned_data['uploaded_file'].file, 
> encoding='utf-8')
>
>         self.cleaned_data['ids'] = []
>         try:
>             reader = csv.DictReader(file)
>         except KeyError:
>             # File doesn't exist, which will raise its own error.
>             pass
>
>         try:
>             for row in reader:
>                 if row['col_name']:
>                     self.cleaned_data['ids'].append(row['col_name'])
>         except KeyError:
>             raise ValidationError('The file must be a csv with a column 
> title col_name.')
>
>
> What I gather is happening is that this clean function is run on the POST 
> request. During this call the file is read through and errors, during which 
> it is *closed*. After when trying to display the non_field_errors the 
> file is still closed and therefore raises the error.
>
> Is this a bug? Should the file be forced to close at this point? Or am I 
> missing something important?
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/26f0b0c0-f3da-4b8d-b2dc-df5898c46698%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to