Panel FileInput Not updating Param parameter value

I have a simple param.Parameterized class that should parse a binary file when the param.FileSelector parameter changes.

class VMSTrajectoryLog(param.Parameterized):
    """
        An object representing the features of a Varian Trajectory Log file 
    """
    
    bin_file = param.FileSelector(doc="The trajectory log '*.bin' file.",
                                  # allow_None=True,
                                  # default=None
                                  )
    txt_file = param.FileSelector(doc="The trajectory log '*.txt' file.",
                                  # allow_None=True,
                                  # default=None
                                  )
    header = param.ClassSelector(class_=VMSTrajectoryLogHeader, doc="VMSTrajectoryLogHeader object.")

    @param.depends('bin_file', watch=True)
    def _parse_bin(self):
        print("Parsing Trajectory Log File") # <=== Just for Jupyter testing
        
        if type(self.bin_file) == str:
            # print("It was a str")
            self._bin_file = open(self.bin_file, "rb")
        else:
            # print("It was a file")
            self._bin_file = io.BytesIO(self.bin_file)

        ### PARSING CODDE BELOW ###

During some testing in Jupyter lab if I use the panel.widgets.FileIput widget to pop up a dialog via a button to select a file the ‘bin_file’ parameter remains None and is not updated via the param.depends function with watch=True. If I don’t use the panel.widgets.FileInput widget and simply use the standard widget where you have to type the full path as text it locates the file and parses the file without issue as you would expect.

Any ideas as to what could be going on would be appreciated. If I make even the most basic example in Jupyter Lab it appears to work but for some reason this seems to be broken or I’m missing something staring me right in the face.

Hi @tallhamer !

It depends on what you want to do I think. Do you want the users to (1) choose among a list of files or to (2) choose any file that they want? For (1) you should set the path parameter of a FileSelector that is a glob pattern that will populate the objects parameter with a list of files matching the pattern. If you already know the list of files you want to expose you could just use a Selector. For (2) indeed the FileInput widget seems to be appropriate, however it doesn’t match with the FileSelector Parameter (since you’re not choosing among a finite set of objects). The value attribute of a FileInput is a bytes object (or a list of bytes if you allow to load multiple files). Since there’s no bytes Parameter in Param (not yet but there’s one open PR that adds one), you can just map it to a param.Parameter type. This would look something like the following:

class P(param.Parameterized):
    
    s = param.Parameter()
    
    @param.depends('s', watch=True)
    def _react_on_s(self):
        print('new file')
    
    def view(self):
        return pn.Param(self.param, widgets={'s': pn.widgets.FileInput})

p = P()
p.view()

Now if you go down the FileInput way, it might make more sense not to create the widget through the pn.Param interface, since creating it yourself would allow to access its other useful attributes (filename, mime_type).

Your simple example seems to suffer from the same issue as my example within my jupyter lab environment.

I am in fact looking at option 2 and had already tried changing it to param.Parameter. What makes it even stranger is that I have an old jupyter notebook from another project with the same exact usage pattern and it functions just fine within the same jupyter lab environment while the above does not.

This appears to be an issue in Jupyter Lab and Jupyter Notebooks.

If I run the interface with pn.serve(view) and select the file from a new server instance both the default interface where you type in the full path to the file and the interface using the pn.widgets.FileInput widget to select the file appear to function properly.

I haven’t been able to reproduce the problem you mention @tallhamer. Would you mind sharing an example that reproduces it?

I think I have narrowed it down to an issue with the file size. I seem to be suffering from some type of issue related to the below GitHub Issue (FileInput widget is limited by the size of the tornado `max_buffer_size1 · Issue #1559 · holoviz/panel · GitHub)

FileInput widget is limited by the size of the tornado `max_buffer_size1 #1559

The tornado client has a default max buffer size of 100MB . This limits the files that are loaded into the FileInput widget.

The buffer size can be increased by setting this size on the bokeh server:

from bokeh.server.server import Server
server = Server( ... , websocket_max_message_size=1000000000,)

I can’t say I understand how to fix this using the recommended approach on the bokeh server but I will just have to figure it out.

My testing was grabing these log files off of a server that was randomly generating them. If I select a log file using the FileInput that was < 10Mb it seems to work until I encounter a file larger than that threshold. A larger file seems to quietly crash the Jupyter Lab server and it gives a warning when trying to print the file to the notebook

IOPub data rate exceeded.
The Jupyter server will temporarily stop sending output
to the client in order to avoid crashing it.
To change this limit, set the config variable
--ServerApp.iopub_data_rate_limit.

Current values:
ServerApp.iopub_data_rate_limit=1000000.0 (bytes/sec)
ServerApp.rate_limit_window=3.0 (secs)

If I select a smaller file first the code works as expected. If I follow that by selecting a larger file the file appears to not get updated by the FileInput selection (i.e. retains the last file selected) which is why the watching code never runs.

Ok thanks for digging into that @tallhamer ! It looks like the FileInput docs would require a section that mentions this kind of potential issues and how to solve them if possible.