flask-marshmallow icon indicating copy to clipboard operation
flask-marshmallow copied to clipboard

File(allow_none=True) is not possible

Open ddorian opened this issue 1 year ago • 11 comments

Hi team,

Is there interest in making File(allow_none=True)? This would allow to send None to file and it being validated as valid. The use case is to delete the file when editing a resource (set it to None to delete it). I can make pull request.

ddorian avatar Jun 11 '24 09:06 ddorian

I think adding allow_none to File makes sense for API consistency with other fields 👍 PR welcome!

sloria avatar Jun 11 '24 15:06 sloria

An issue would be when you upload files using multipart/form-data. There is no None/null value in that scenario possible. Maybe an empty string for that case?

ddorian avatar Jun 11 '24 15:06 ddorian

Oh, right, that's probably why File doesn't support allow_none in the first place 🤔 I'm not sure an empty string makes sense as a null value for this case.

@uncle-lv any thoughts on this?

sloria avatar Jun 12 '24 15:06 sloria

An issue would be when you upload files using multipart/form-data. There is no None/null value in that scenario possible. Maybe an empty string for that case?

Yes, we have handled it.

uncle-lv avatar Jun 15 '24 08:06 uncle-lv

There is an interesting thing.

If no file is uploaded, the content is empty:

-----------------------------267432055312135418634201536635
Content-Disposition: form-data; name="file"


-----------------------------267432055312135418634201536635--

If an empty file is uploaded(such as an empty text file), the content is also empty, but there is a filename:

-----------------------------497031844591475693105063701
Content-Disposition: form-data; name="file"; filename="empty.txt"
Content-Type: text/plain


-----------------------------497031844591475693105063701--

It seems that we cannot judge whether a file is uploaded by content. Maybe filename is a better choice?

uncle-lv avatar Jun 15 '24 09:06 uncle-lv

If no filename, data will be deserialized as a str whatever content-type is. If filename exists, data will be deserialized as a FileStorage whatever content-type is.

I think we can handle it according to the following rules: no filename and empty content(an empty str) → None/null(to be compatible with swagger) filename exists and empty content(an empty FileStorage) → Not None/null and a valid file

uncle-lv avatar Jun 17 '24 14:06 uncle-lv

@uncle-lv seems like a sensible proposal to me. is it straightforward to validate against filename within the field?

sloria avatar Jun 17 '24 17:06 sloria

@uncle-lv seems like a sensible proposal to me. is it straightforward to validate against filename within the field?

No need to validate filename. If no filename, the value will be a str, otherwise it'll be a FileStorage.

uncle-lv avatar Jun 17 '24 23:06 uncle-lv

oh i see. that certainly makes it simpler then.

PRs welcome!

sloria avatar Jun 18 '24 13:06 sloria

In the end-to-end case, it's difficult to whether determine the file is None or missing.

Browser(Firefox/Chrome) will send send empty data with empty filename when no file is selected in HTML.

-----------------------------267432055312135418634201536635
Content-Disposition: form-data; name="file"; filename=""
Content-Type: application/octet-stream


-----------------------------267432055312135418634201536635--

Swagger will send send empty data without filename when no file is selected.

-----------------------------267432055312135418634201536635
Content-Disposition: form-data; name="file"


-----------------------------267432055312135418634201536635--

Axios will send a string with value "null" when the file field of FormData is set null.

-----------------------------267432055312135418634201536635
Content-Disposition: form-data; name="file"

null
-----------------------------267432055312135418634201536635--

I have no idea to handle it.🤯

uncle-lv avatar Jun 25 '24 14:06 uncle-lv

My idea was to use it on a REST API, so I only needed to support 1 way.

Or you can support all ways if considering to be used from a browser.

ddorian avatar Jun 29 '24 08:06 ddorian