Opened 2 years ago

Last modified 2 years ago

#27150 new Cleanup/optimization

Document that a name should be provided when wrapping file-like objects that don't have one with File

Reported by: Sergei Zh Owned by: nobody
Component: Documentation Version: 1.10
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

django.core.files.base.File supports file-like objects (synonym to file object in python glossary) and in fact can't rely on additional name attribute, but in current implementation of __bool__ method it does:

    def __bool__(self):
        return bool(self.name)

For example, until tempfile.SpooledTemporaryFile isn't large enough to have been written to disk, his name attribute is None and if statement will return False.

import tempfile
from django.core.files.base import File
python_file_like_object = tempfile.SpooledTemporaryFile()
file_obj = File(python_file_like_object)  # name keyword is None by default
if file_object:  # Falsy, because python_file_like_object.name is None
    print("42")

The same behavior with streams (BytesIO, StringIO).
Maybe __bool__ method should rely on self.file attribute to avoid this behavior?

Change History (7)

comment:1 Changed 2 years ago by Baptiste Mispelon

Hi,

As far as I can tell, File.__bool__ is not documented but it does seem to be used internally and is somewhat tested (though maybe not directly): changing it to return False yields quite a few errors and failures in the test suite.

Because of this lack of documentation, it's hard to tell if the behavior you're describing is a bug.

I think it'd be worth it to:

1) Document File.__bool__ (both in the reference docs and in the docstring)
2) Figure out if we can improve it by handling underlying files with no names as you suggest.

What do you think?

comment:2 Changed 2 years ago by Sergei Zh

Hi.
Sure, it makes sense. I'll try to investigate failed tests ASAP. Think it's the best place to begin.

comment:3 Changed 2 years ago by Tim Graham

Component: Core (Other)Documentation
Summary: Wrong File object behavior if file object has no name attributeDocument that a name should be provided when wrapping file-like objects that don't have one with File
Triage Stage: UnreviewedAccepted
Type: BugCleanup/optimization

See #26495 for a case where this came up. Unless investigation yields otherwise, I think documenting that you should pass a name for file-like objects that don't have one is the best course of action. I'm not sure if raising an error for that case might be acceptable (there might be use cases where providing name isn't needed) but if so, they would likely be even more helpful.

comment:4 Changed 2 years ago by Sergei Zh

As I understood from #26495 python file-like objects works fine with requests library, because in CPython file objects use object.__bool__ and always returns True if no __bool__ and __len__.

I think documenting that you should pass a name for file-like objects that don't have one is the best course of action.

It's little bit strange for me to allow pass name=None to Storage.save, while disallow use empty name for file-like objects. Maybe we can restore default __bool__ behavior in Storage.save method?

content.__bool__ = lambda _: True

comment:5 Changed 2 years ago by Sergei Zh

I've realized it's wrong, we should delete __bool__ method, cause default implementation depends on __len__ method.

comment:6 Changed 2 years ago by Tim Graham

I haven't looked into the issue so I can't propose an alternative, however, I'm not sure that patching methods like that is a good practice. At least, I'm not aware of anywhere else in Django that uses that pattern.

comment:7 Changed 2 years ago by Sergei Zh

You are right, I guess the main reason - it doesn't work :)

Note: See TracTickets for help on using tickets.
Back to Top