import io
import panel as pn
pn.extension()
The FileInput
widget allows uploading one or more file from the frontend and makes the filename, file data and MIME type available in Python.
Discover more on using widgets to add interactivity to your applications in the how-to guides on interactivity. Alternatively, learn how to set up callbacks and (JS-)links between parameters or how to use them as part of declarative UIs with Param.
For details on other options for customizing the component see the layout and styling how-to guides.
accept
(str): A list of file input filters that restrict what files the user can pick fromdirectory
(str): If directories is upload instead of filesfilename
(str/list): The filename(s) of the uploaded file(s)mime_type
(str/list): The mime type(s) of the uploaded file(s)multiple
(boolean): Whether to allow uploading multiple filesvalue
(bytes/list): A bytes object containing the file data or if multiple
is set a list of bytes objects.file_input = pn.widgets.FileInput()
file_input
To read out the content of the file you can access the value
parameter, which holds a bytestring containing the file's contents. Additionally information about the file type is made available on the filetype
parameter expressed as a MIME type, e.g. image/png
or text/csv
.
file_input.value
The widget also has a save
method that allows saving the uploaded data to a file or BytesIO object.
# File
if file_input.value is not None:
file_input.save('test.png')
# BytesIO object
if file_input.value is not None:
out = io.BytesIO()
file_input.save(out)
The accept
parameter restricts what files the user can pick from. This consists of comma-separated list of standard HTML
file input filters. Values can be:
<file extension>
- Specific file extension(s) (e.g: .gif, .jpg, .png, .doc) are pickableaudio/*
- all sound files are pickablevideo/*
- all video files are pickableimage/*
- all image files are pickable<media type>
- A valid IANA Media Type, with no parameters.file_input = pn.widgets.FileInput(accept='.csv,.json')
file_input
To allow uploading multiple files we can also set multiple=True
or if you want to upload a whole directory directory=True
:
file_input = pn.widgets.FileInput(accept='.png', multiple=True)
file_input
When uploading one or more files the filename
, mime_type
and value
parameters will now be lists.
You can also clear the file input with the .clear()
method.
file_input.clear()
While the FileInput
widget doesn't set any limit on the size of a file that can be selected by a user, the infrastructure onto which Panel relies (web browsers, Bokeh, Tornado, notebooks, etc.) limits significantly what is actually possible. By default the FileInput
widget allows to upload data that is in the order of 10 MB. Even if it is possible to increase this limit by setting some parameters (described below), bear in mind that the FileInput
widget is not meant to upload large files.
Before increasing the file size limit it is worth explaining the process that happens when a file is selected.
The FileInput
widget is a Bokeh widget whose data is communicated from the front-end to the back-end via a protocol called Web Sockets. Bokeh didn't implement Web Sockets itself, instead it took advantage of an existing web framework that provided an implementation: Tornado.
In even more concrete terms, here's what happens when a file is selected in a server context (it's the exact same process when multiple files are loaded at once!):
Tornado
web socket connection to the back-endFileInput
widget instance when the properties of the Python/Bokeh widget are updated. The long string is converted by Panel into a bytes
object that is available with .value
.The steps described above almost all have potential or actual limits:
Tornado
imposes two limits on the data being transferred: (1) on the maximum size of a buffer and (2) on the maximum size of the websocket message. (1) is 100 MB by default (set by Tornado) and (2) is 20 MB by default (set by Bokeh).While there's nothing much that can be done about 1., 2. and 3. (except informing your users), the limits defined by Tornado and Bokeh can be overwritten.
In a server context your application must be executed with python your_app.py
(because panel serve
doesn't allow to configure all the options provided by Bokeh and Tornado):
# your_app.py
import panel as pn
app = ...
MAX_SIZE_MB = 150
pn.serve(
app,
# Increase the maximum websocket message size allowed by Bokeh
websocket_max_message_size=MAX_SIZE_MB*1024*1024,
# Increase the maximum buffer size allowed by Tornado
http_server_kwargs={'max_buffer_size': MAX_SIZE_MB*1024*1024}
)
In a Jupyter notebook (classic or lab) the limits of Tornado (Tornado's Web Sockets are already used by the Jupyter notebook for communication purposes) can be set in a configuration file. The default maximum buffer size is 512 MB and the default maximum websocked message size is 10 MB.
Classic Notebook:
Generate a configuration file with jupyter notebook --generate-config
and update it with:
c.NotebookApp.tornado_settings = {"websocket_max_message_size": 150 * 1024 * 1024}
c.NotebookApp.max_buffer_size = 150 * 1024 * 1024
Lab:
Generate a configuration file with jupyter lab --generate-config
and update it with:
c.ServerApp.tornado_settings = {'websocket_max_message_size': 150 * 1024 * 1024}
c.ServerApp.max_buffer_size = 150 * 1024 * 1024
base64
string. So if you set a maximum size of 100 MB for your application, you should indicate your users that the upload limit is a value that is less than 100 MB.[bokeh] Lost websocket 0 connection, 1009 (message too big)
) which means the application will become unresponsive and needs to be refreshed.The FileInput
widget exposes a number of options which can be changed from both Python and Javascript. Try out the effect of these parameters interactively:
pn.Row(file_input.controls(jslink=True), file_input)