-
-
Notifications
You must be signed in to change notification settings - Fork 864
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
File was not opened in read | write mode with the S3Storage backend #976
Comments
Hey buddy, I kinda figured out what's happening. The doc does not say
I attempted this (not thoroughly tested), it seems to allow me to open file with read mode then write mode. You can extend def open(self, mode='rb'):
if mode != self._mode:
self.close()
self.__init__(self.name, mode, self._storage, self.buffer_size) Then create a storage class that uses this file class. |
Minimal steps to reproduce this issue: storage = S3Boto3Storage(...)
my_file = storage.open("test.txt", "w")
my_file.write("hi")
my_file.close()
my_file.open("r")
print(my_file.read()) exception: Traceback (most recent call last):
File "/.../main.py", line 0, in <module>
main()
File "/.../main.py", line 12, in main
print(my_file.read())
File "/.../lib/python3.8/site-packages/storages/backends/s3boto3.py", line 153, in read
raise AttributeError("File was not opened in read mode.")
AttributeError: File was not opened in read mode.
|
Hey @jschneier, love this lib and I've been using it since 2018! |
I'm fighting the django file system all the time, it's insane, I feel like I'm walking in circles. They have problem with this use-case even when using default FileStorage. Unfortunately here the issue persists, and @rabbit-aaron workaround doesn't seem to be working. inst.data.file.file._file # smells a bit? Looks weird doesn't it? I don't think I'm wrong when I say that most user code expects the file/storage system to be stateless, meaning it's not caching any state (mode, buffer). So when I open the file for reading, then close it, I naturally expect that all state is lost. So next time I open it, I get a fresh file, be it for reading or writing. Django doesn't do that and it's buggy. I think django-storages can do better. For any sane person, always use it like this: with inst.data.storage.open(inst.data.name, 'rb') as f:
... # do read stuff
with inst.data.storage.open(inst.data.name, 'wb') as f:
... # do write stuff |
Was bitten by this issue today. I fixed it by just deleting the I'm not sure if it's relevant, but in
When EDIT: ref: https://docs.djangoproject.com/en/4.1/ref/files/file/#django.core.files.File.open |
I think the correct fix here would be to override Not sure if we need the re-seeking? If not, we'd want to close the file then I suppose. So there is some nuance. I think failing that, @skrat has the correct approach. |
My attempt: #1227 |
I saw that this issue was reported at least twice in the past few years, but it probably was never properly described and thus got closed. It seems that once the file is open in either mode (read or write) you can't switch to the other.
First of all, it's not immediately obvious that you shouldn't be able to open it multiple times. E.g. given
and
m = MyModel,objects.first()
if you usem.some_field
for a read operation (e.g. to process the image) then it gets opened in read mode by default. But then there is no way to write back to it. I've tried it the following ways:This could work, though one has to be aware of the magic Django does with FileFields (without that you'd expect this to return a new file-like object, whereas open really influences the field, which kind of looks like a file). But it could work, it would just have to change mode (basically probably close the file, and reopen it, causing it to flush if the transition is
w -> r
). Django doesn't do it either, though. (It seeks to 0.)However, closing the file manually doesn't work either:
This causes the same exception. Indeed, the field is left in a bogus, state, it's probably not aware that it was closed (
m.some_field.closed
returnsFalse
even after doing am.some_field.close()
).read
still works, though it seems to reopen the file (at least probably reaches out to S3 as the call takes some time to return). This happens with theopen('w')
call (after closing the file) as well but the file is still stuck in read mode and doesn't allow writing.(I'm using an ImageField in the example because that's what I'm getting the error with, but I'm 99% sure it's the same with a plain FileField).
The only solution, for now, seems to be refreshing the model instance from the db, but that's slow and inconvenient. (Now I see that django actually doesn't allow re-opening a closed file, which is sad, but even then, closing the file should close the file and also conflicting file mode opens should be rejected. But that's likely a django bug.)
The text was updated successfully, but these errors were encountered: