Repository: bokeh/bokeh

Issue:
[FEATURE] Add multi-file selection to FileInput widget
**The ISSUE**:
The current version (bokeh 1.4, branch master) of the FileInput widget of bokeh only allows a single file to be selected by the user.
The underlying <input type='file'> item in the browser comes with the option/property "multiple" in JS or HTML5, which is hard-coded to "False" in the bokeh-code.

**The Problem**:
For data analysis project in my laboratory I need to upload many tenth of files at a time, which is not manageable by single upload. 
Hence the request (**and a related PR**) to add a working "multiple"-property and the respective option of multi-file selection to the FileInput widget.

**Solution**:
Adapt/extend the code of the currently implemented FileInput to support a "multiple"-property with the (switchable) capability to support the multi-file selection and provide the returned results as arrays instead of scalar values.

**Background**:
The issue was [pre-discussed here in community support](https://discourse.bokeh.org/t/why-is-bokeh-fileinput-limited-to-single-selection/4778) and [here in the develeopment-forum](https://discourse.bokeh.org/t/callback-triggering-broken-after-change-from-string-to-array-in-fileinput-widget/4797).

**possible Alternative**:
The implementation of a seperate widget (MultiFileInput) was considered but rejected because of the inconsistency with usual HTML or JS input widgets of similar functionality.

 



Discussion:

Resolving patch:
diff --git a/bokeh/models/widgets/inputs.py b/bokeh/models/widgets/inputs.py
--- a/bokeh/models/widgets/inputs.py
+++ b/bokeh/models/widgets/inputs.py
@@ -89,26 +89,49 @@ def coerce_value(cls, val):
 #-----------------------------------------------------------------------------
 
 class FileInput(Widget):
-    ''' Present a file-chooser dialog to users and return the contents of a
-    selected file.
-
+    ''' Present a file-chooser dialog to users and return the contents of the
+    selected files.
     '''
 
-    value = String(default="", readonly=True, help="""
-    A base64-encoded string of the contents of the selected file.
-    """)
+    value = Either(String, List(String), default='', readonly=True, help='''
+    The base64-enconded contents of the file or files that were loaded.
 
-    mime_type = String(default="", readonly=True, help="""
-    The mime type of the selected file.
-    """)
+    If `mulitiple` is set to False (default), this value is a single string with the contents
+    of the single file that was chosen.
+
+    If `multiple` is True, this value is a list of strings, each containing the contents of
+    one of the multiple files that were chosen.
+
+    The sequence of files is given by the list of filenames (see below)
+    ''')
+
+    mime_type = Either(String, List(String), default='', readonly=True, help='''
+    The mime-type of the file or files that were loaded.
+
+    If `mulitiple` is set to False (default), this value is a single string with the
+    mime-type of the single file that was chosen.
+
+    If `multiple` is True, this value is a list of strings, each containing the
+    mime-type of one of the multiple files that were chosen.
 
-    filename = String(default="", readonly=True, help="""
-    The filename of the selected file.
+    The sequence of files is given by the list of filename (see below)
+    ''')
+
+    filename = Either(String, List(String), default='', readonly=True, help='''
+    The name(s) of the file or files that were loaded.
+
+    If `mulitiple` is set to False (default), this value is a single string with the
+    name of the single file that was chosen.
+
+    If `multiple` is True, this value is a list of strings, each containing the
+    name of one of the multiple files that were chosen.
+
+    This list provides the sequence of files for the respective lists in value and mime-type
 
     .. note::
         The full file path is not included since browsers will not provide
         access to that information for security reasons.
-    """)
+    ''')
 
     accept = String(default="", help="""
     Comma-separated list of standard HTML file input filters that restrict what
@@ -132,6 +155,11 @@ class FileInput(Widget):
     .. _IANA Media Type: https://www.iana.org/assignments/media-types/media-types.xhtml
     """)
 
+    multiple = Bool(default=False, help="""
+    set multiple=False (default) for single file selection, set multiple=True if
+    selection of more than one file at a time should be possible.
+    """)
+
 
 class TextInput(InputWidget):
     ''' Single-line input widget.


Test patch: