Create a ipywidget capable of uploading files (either a list of paths as strings and/or their binary contents)
Ideally a user would initialize this widget, display it, then on making a selection a list of file paths as strings would then be available to access through jupyter notebook.
I've start on this already but I'm currently working out some kinks see this gist. A janky but functional tkinter based solution can be found at this gist.
I plan to submit a PR of the first method soon as I can get it to work.
While have been thinking narrowly about just retrieving the file paths as string @jasongrout mentioned that file contents could be read directly from the widget by utilizing the file API along with a file reader. That way files can be uploaded even if the browser and kernel are on not the same machine!
So I'm filing this issue to hold my self accountable and actually create the PR and to get the discussion started.
All feedback is welcome.
A file upload widget sounds great! Should this be a core widget or a separate widget library? Either way, I think this would be a great contribution to the widget ecosystem.
I think that this would work well as a core widget b/c it leverages basic HTML/javascript properties without having to add any more outside javascript libraries. Also I think this widget should be easy for beginners to use. If it were maintained as a separate package then that makes it that much harder for them.
I find this https://github.com/peteut/ipython-file-upload
Thanks for pointing that out, @cloga.
@jasongrout are there any plans to add that or a similar widget to core jupyter widgets? I think this would be super useful as well
I think someone should just submit a PR (i.e., a PR for a widget that accepts a file upload and sets the value of the widget to the contents of the file). Sounds like a great widget to have!
I'll mark it as a good (advanced) first issue - create a widget that syncs back to the kernel the contents of a selected file. I would imagine such a widget has an html file input element, and it uses the file reader api to get the contents of the file, which it then syncs as the widget value.
@jasongrout I have started working on a PR, but I was unable to use traitlets.Bytes correctly. I am not sure how to set this in JS (except to pass a string, which does not work in all cases). Ideally these should be a List as this widget accepts multiple. I want to make multiple configurable from python, but always set selected values into to a list. Any objection to using file_uploader.values of type traitlets.List over file_uploader.value of type traitlets.Bytes always? This is not inline with the general APIs for the rest of the widgets which has a single value nor will it be efficient for large files, which is why I ask.
How often do you think people will need to upload multiple files to such a widget (as opposed to creating multiple file upload widgets)? To answer user-defined questions like this, it might be helpful to write down a couple of scenarios where this widget is useful.
Check out imagemodel, it has a serializer on the front-end, see image at
the backend, it has a deserializer. Hope that helps.
(from mobile phone)
On Fri, 31 Aug 2018, 23:15 Marc Udoff, notifications@github.com wrote:
@jasongrout https://github.com/jasongrout I have started working on a
PR, but I was unable to use traitlets.Bytes correctly. I am not sure how
to set this in JS (except to pass a string, which does not work in all
cases). Ideally these should be a List as this widget accepts multiple
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-multiple.
I want to make multiple configurable from python, but always set selected
values into to a list. Any objection to using file_uploader.values of
type traitlets.List over file_uploader.value of type traitlets.Bytes
always? This is not inline with the general APIs for the rest of the
widgets which has a single value nor will it be efficient for large files,
which is why I ask.—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/jupyter-widgets/ipywidgets/issues/1542#issuecomment-417791052,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABryPZsStxwlMyDTJ2hBJxKc29gOp9ydks5uWadUgaJpZM4OkVlk
.
How often do you think people will need to upload multiple files to such a widget (as opposed to creating multiple file upload widgets)?
Although I agree that a single file may be the best default and the most common case, I think this still is pretty useful. E.g. uploading a folder of pictures or CSVs for processing would be painful without this. For applications that I am interested in using this in, I would use it in multi mode and let the users of the shared notebook decide if they want to upload more than one file and "do the right thing" with their input. It's a less limiting experience.
https://github.com/jupyter-widgets/ipywidgets/pull/2211 has been created as a start.
There are a few issues we should conclude on in this thread:
I'll also note that I had problems getting the dev-install.py to work. It turns out that it did not create a symlink so my python code did work, but the JS code did not. This took a while to debug. Another thing I wish there was from a dev perspective, was a continuous build (i.e. a JS file watcher that built every time a file is changed).
@jasongrout @maartenbreddels Any thoughts on the previous update?
Hi Marc,
great work!
I would say, just use .value, and make it a Union, a Bytes | List(Bytes) trait, although I don't think maybe people are a fan of unions.
For non-base 64, please take a look at the Image widget:
https://github.com/jupyter-widgets/ipywidgets/blob/master/packages/controls/src/widget_image.ts
https://github.com/jupyter-widgets/ipywidgets/blob/7c97f2d3f87ef1c3c35e2d7df65e27186a10bd6d/ipywidgets/widgets/widget_media.py#L146
https://github.com/jupyter-widgets/ipywidgets/blob/7c97f2d3f87ef1c3c35e2d7df65e27186a10bd6d/packages/controls/src/widget_image.ts
If something does not work, check the WebSocket frames for 'lost' error messages.
Could there be a progress trait for (float between 0 and 1) that can be used to connect to the progress widget?
although I don't think maybe people are a fan of unions.
raises hand - I'm not particularly a fan of unions. I think I'd rather it was a list always, than have it be sometimes a list and sometimes a value.
I'll also note that I had problems getting the
dev-install.pyto work. It turns out that it did not create a symlink so my phone code did work, but the JS code did not.
Is this on windows? IIRC symlinks won't work on windows.
I think I'd rather it was a list always
I'd rather it was a TypedTuple, as List is just confusing for widgets.
Is this on windows? IIRC symlinks won't work on windows.
This was on osx
raises hand - I'm not particularly a fan of unions. I think I'd rather it was a list always, than have it be sometimes a list and sometimes a value.
The to clearer on this, Bytes will not work as we do need to send other data along with the contents (name, contents, type, and lastModified to start). We can send parallel arrays so that we can use Bytes as the transfer medium.
Do you have a problem if .value is List of objects always?
I'd rather it was a
TypedTuple, asListis just confusing for widgets.
Right, I forgot that that is our new recommendation.
Do you have a problem if .value is List of objects always?
I think having consistent typing is easier to reason about. I'm a little torn, though, since it would be convenient to link, say, an image source with a file upload value.
How often do you think a single file will be wanted vs multiple files?
This is going to be great! I vote for multiple files as an option please, I created an upload button widget for this purpose, but it has issues when a user selects too many files. I suspect it is an issue with the async event timing since I didn't know how to use promises at the time. Can't wait to see what you guys come up with and would be happy to help test it.
I also had envisioned having a drag drop upload widget that could be attached to box widget somehow.
-Randy
How often do you think a single file will be wanted vs multiple files?
As a user, I would be happy knowing my value was always a list than sometimes a list. I think multi file will be too common to ignore or make hard.
I have now added a loader div, but am unable to give progress percent. It turns out that for large files the time is dominated by sending it from the browser to the kernel, which we have no way of keeping a tab on. Therefore, the loader div is enabled by the browser and disabled when the python side thinks everything is loaded. You could observe f.loading if you wanted to know if it was processing or not.
I have also gone back to using two lists, one for metadata and one for content. The front end then merges these to set f.value. I can try to move it to a list of bytes again if people think that will be much better. I am waiting until we come to consensus for making any changes like that. Given that it is now hidden from the user (via private variables) we can also do this in another commit.
See the gif below for POC (there are small files, so you won't even notice the loading indicator)

My question is if we want:
A. two different widgets (allows for a common usecase of a single file, but you can use the multiple version for multiple files if you want), or
B. one widget that has a union, and handles multiple and single files (perhaps with a synced attribute, so you could switch between them if needed?), or
C. one that allows only multiple files (harder to deal with single files if that's all you want, e.g., upload and analyze only a single image at a time), or
D. one that does single files (your responsibility for putting multiple widgets on the page if you want multiple files)
Sounds like C and D are out - I think the single file usecase is common enough we should explicitly support it. I think I prefer A slightly if it doesn't result in too much code duplication because it's a little more straightforward and predictable. Thoughts?
The JS side can be exactly the same for A and B as the current design hides how data is transferred from the user anyway. Currently setting multi allows for multiple or not in the UI.
So it's a question of what we want to put in .value. I am very torn if we want .value to always be a List or in the single case just store a TypedTuple. I don't think its bad to just have two python classes where one is called MultiUploadWidget and the other UploadWidget. It adds to maintenance and figuring out what you want, but it does make the .value cleaner in the single case.
I'm torn about whether we want .value to be a union and .multiple to be an attribute, or if we want multiple/single to be two separate widgets to keep .value typing predictable. I don't think people will often want to switch between single/multiple, so that points me to having two separate widgets with simple predictable typing.
@jasongrout I went with two widgets as suggested above: FileUpload and MultiFileUpload. The former has a simpler .value while the latter uses a TypedTuple for .value and allows for .multiple to be set (defaults to true). The JS code is unchanged and MultiFileUpload depends on FileUpload.
Please review: https://github.com/jupyter-widgets/ipywidgets/pull/2211
It can sometimes be problematic to overload an attribute with a different expected type. E.g.:
class MyWidget(ipywidgets.Widget):
uploader = traitlets.Instance(FileUploader)
a = MyWidget(uploader=randomly_multiple_uploader())
a.value = dict() # Randomly gives a TypeError
Maybe consider:
value trait typed as TypedTuple onlyallow_multiple (or similar)self.value[0], or setting self.value = (value,)Either way, I would recommend creating a File traitlet(factory).
Brainstorming here: how about files giving a list, and value being the single file files[0] or None?
(Having two different attributes for the single/multiple case addresses my point about consistent typing...)
Brainstorming here: how about files giving a list, and value being the single file files[0] or None?
I don't love how easy it is to mess up usage of the widget in the multi upload case. This is a reach, but this would be like returning the min value in a range selector and knowing you had to use .range for access for the actual range.
I just published a custom ipywidgets ipyupload because they need it now in my company.
But I also think it should be a core widget.
In short, it syncs List(Bytest) for the file contents and List(Dict) for the files metadata. It can handle multiple uploads. The result is presented to the user as a dict in trait .value.
@oscar6echo I won't be able to look at this for a little while. If you want to change/update this to help move getting this widget included along that would be great!
I added a compress (optional) feature to ipyupload v0.1.2 to reduce transmitted data size from browser to kernel.
@mlucool why not if I have time - it would be an interesting exercise/challenge.
However I have quite a few questions:
TypedTuple instead of List as mentionned by @vidartf what are the constraints ? any example ? why is TypedTuple not available under the same namespace as List, Dict and the other containers.@oscar6echo I meant take what was in this commit and continue to extend it for better transport type and how things are accessible from python. i.e. incorporate some of the things you did here. Also you should bringing in any other features you think are useful
Does everybody agree with the way I implemented the file upload ? Including:
I think we should stick with the default browser implementation of an input box for now. A future should should include drag/drop though.
Ok, finally it was not as difficult as I feared. Thanks to the magical yarn build !
I created a new PR #2258 because the previous one #2211 is already late on versions and I thought it was simpler to just start over from scratch - git subtleties always elude me.
Basically it is an "import" of ipyupload. If you ask me, I find it quite convenient with its current options.
I use the browser default <input type="file">. Only I cover it with a <button> for design consistency with the other core widgets (which look good, I think). This technique seems recommended by CSS experts. I just simplified further with display:none.
Tested on Chrome, Firefox, Safari, Opera, and Min. I don't have Edge, and not sure IE is still relevant..?
Re docs, I added an example in the Widget_List.ipynb notebook, after the Controller widget.
Hi all,
This discussion is really interesting and I'd love to use the FileUpload widget.
It seems that the PR was ready but that the build failed.
@jasongrout, do you think this could be merged?
Anyway, I think this would be a great addition to ipywidgets interactions. Thank you everyone!
That's a great feature.
Looking forward to see this in the next release
@oscar6echo great work!
ipyupload widget works like a charm for Jupyter notebook, but in JupyterLab is returns _Error displaying widget_
Any ideas?

The JLab API has changed since I wrote this custom widget (it was working when I published it).
I don't know the current API... If I can find info, I will to update it.
@oscar6echo awesome, can't wait :D. now I'm using this as a work around:
import os
import ipywidgets as widgets
class FileBrowser(object):
def __init__(self):
self.path = os.getcwd()+ "/" #Data"
self._update_files()
def _update_files(self):
self.files = list()
self.dirs = list()
if(os.path.isdir(self.path)):
for f in os.listdir(self.path):
ff = self.path + "/" + f
if os.path.isdir(ff):
self.dirs.append(f)
else:
self.files.append(f)
def widget(self):
box = widgets.VBox()
self._update(box)
return box
def _update(self, box):
def on_click(b):
if b.description == '..':
self.path = os.path.split(self.path)[0]
else:
self.path = self.path + "/" + b.description
self._update_files()
self._update(box)
buttons = []
if self.files:
button = widgets.Button(description='..', background_color='#d0d0ff')
button.on_click(on_click)
buttons.append(button)
for f in self.dirs:
button = widgets.Button(description=f, background_color='#d0d0ff')
button.on_click(on_click)
buttons.append(button)
for f in self.files:
button = widgets.Button(description=f)
button.on_click(on_click)
buttons.append(button)
box.children = tuple(buttons)
f = FileBrowser()
f.widget()

It looks ridiculous I know, found it somewhere, I believe on stackoveflow. It draws buttons with names of the files to choose a file.
So yeah, please save our life :D
@oscar6echo Any good news about ETA of your wonderful ipyupload widget to work with JupyterLab?
@LukaPitamic it would depend on how you installed ipyupload.
If you installed ipyupload using pip or conda, you would need to run jupyter labextension install ipyupload and that would do the trick (you need nodejs installed on your computer for this to work).
If you installed ipyupload from sources using pip install . or pip install -e . you would need to run jupyter labextension install js from the root dir of your ipyupload clone.
If it still does not work, make sure to install the ipywidgets extension as well with: jupyter labextension install @jupyter-widgets/jupyterlab-manager
@martinRenou thx for explaining the install steps (and the great work on ipysheet which I used as a template).
@LukaPitamic I just re-tested locally (regular and dev installs) and it still does work on JLab. I thought I needed to update something in the code but no. In fact only documenting the install steps in the case of JLab was missing. Done in the README. Sorry to have kept you waiting for so long when there was so little to do !..
@martinRenou & @oscar6echo Thank you so much, it works like a charm! I still can't believe this is not a part of widgets list. I guess I'm not the only one missing it in original widgets library. @oscar6echo you're da man!!!! ;)
Is it possible to use this approach for a file or folder selection, and to set the name of the button and also get the path of the selected file or folder? And how are the meta data from images are read. Would be also interested in this. Would need this very much. Best regards!
@oscar6echo The best solution I found so far, thank you! and
@Liwellyen +1, a folder selection would be an amazing feature to have.
@oscar6echo Great work with the package & PR!
@jasongrout Could PR #2258 be reviewed to close loop on this feature request?
Thanks for the inspiration here, lots of good insights and pointers! I, too, was having some issues with some of the existing implementations, and had a go at this:

The approach is:
File widget with an initial naive but useful downloadable adownload, the default behavior is, well, to download... middle click will still open a new tab, but of course that repo might have it do... other things...FileBox which can accept and then show Files<input type="file"/>new_widget, but does work the other way (but doesn't update input.files)Drag-and-drop support is probably next.
I don't think folders are doable natively at present, but Ctrl+A in most native file pickers isn't that bad, unless you have folders-of-folders...
Happy to do a PR, and definitely feel like this is a big missing piece given how much better this has all gotten since the bad old days.
@oscar6echo I really tried some things now, but is it somehwo possible to change the text of the upload button? Best regards and thanks for your effort!
And i dont now why this happenend. But now after installing ipyupload the normal ipywidgets not working anymore in jupyterlab
@Liwellyen it would be possible to change the button text if it becomes a parameter but what sort of flexibility do you envisage ? can you describe a bit more ?
I'm very busy on other things now, but when things settle I can try customizing a bit further if there is a real need.
@oscar6echo Yeah I just want to change the name on the button. So its called something like: Chose File. But what is more important for my understanding and what I now realized the first time: The widget uploads the file to the browser?. Because I just need a file Browser where you can select files or folders and those a saved to a variable. After that I can progress with that paths like i want it. Is such a thing possible or maybe it exists already and I dont be aware of it.
Furthermore it seems, if I install ipyupload and use it with jupyterlab I get this error mesagge in my terminal for all ipywidgets:
[W 14:52:20.056 NotebookApp] 404 GET /nullnbextensions/ipyupload/vendors~@jupyter-widgets/controls~vega.3dd933b62461edbc58d8.js (192.168.2.30) 1.46ms referer=....
i use it on a remote server. In the normal jupyter notebook it works. If I deactivate the ipyupload jupyterlab extension all the others work again
Closing as fixed! Thanks @oscar6echo for the PR!
@Liwellyen Button text will be customizable in official version of widget, at least that's how I understood discussion on the PR.
Most helpful comment
Although I agree that a single file may be the best default and the most common case, I think this still is pretty useful. E.g. uploading a folder of pictures or CSVs for processing would be painful without this. For applications that I am interested in using this in, I would use it in multi mode and let the users of the shared notebook decide if they want to upload more than one file and "do the right thing" with their input. It's a less limiting experience.