FileDownload Widget: How to handle the case of returning empty string/None?

Hello,
I am trying to download a file from a particular location using the FileDownload Widget.
Required file will be downloaded only when conditions are met. In this case, a basic check is done i.e if the value in text input is not empty then file will be downloaded (no issue here perfectly downloaded), but the case where the condition is not met then no download is required. When no path or empty str or None is returned I get an exception. How do I handle this case ?? Adding code block within try except did not help :frowning:
Here is the code:

import panel as pn
pn.extension(notifications = True)

def returnPath():
    # If my condition is satisfied return path to download required file.
    # If not send nothing and do nothing.
        # This step of returning an empty string/None gives an exception. 
    # Adding this entire code block within try/except did not help.
    # Basically file must be downloaded only when conditions are satisfied.
    # Just as an example textInput widget is considered here :) .

    # empty path or empty string or None
    dummyPath = ''
    if inp_wid.value:
        # actual path
        actualPath = r"my_file_path\my_file.txt"
        return actualPath
    pn.state.notifications.info("Input value not provided", duration=2000)
    return dummyPath

fileDownload_wid = pn.widgets.FileDownload(callback = pn.bind(returnPath), filename='my_file.txt', button_type='primary', auto=True)
inp_wid = pn.widgets.TextInput(name='Input')
buttonRow = pn.Row(fileDownload_wid, inp_wid)
buttonRow.servable()

Did you see this question and code sample? Does that help? What exception message are you getting?

Hi @coderambling
I get the below exception when I set the path to be None:

ValueError: Cannot transfer unknown object of type NoneType

I get the below exception when I set the path to an empty String:

FileNotFoundError: File " " not found.

FileDownload button with a callback function works perfectly when your function returns a file path, but what if we don’t want the path to be returned, not every case requires a actual return value. Since call back function must return file-path or a file type obj, when an empty string or None is returned you start getting exceptions :frowning:
Any suggestions/work-around in handling this case will be of great help. Thanks in advance… :v:

You could probably do something like fileDownload_wid.disabled = pn.bind(has_input, inp_wid.param.value)

Hi @ahuang11,
Thanks for replying.
Please correct me if my understanding is wrong. has_input here is a function that returns True or False. So has_input() will check the inp_wid value, if its empty return True (disable the fileDownload widget), else you return a False (enable the fileDownload widget), set the file path.
I tried this approach and got this error.

ValueError: Boolean parameter ‘disabled’ must be True or False, not <function _param_bind..wrapped at 0x000001…>.

However using pn.bind this way will not give me any error and works perfectly, for eg:

input_wid = pn.widgets.TextIput(name='Input')
download_wid  = pn.widgets.FileDownload(filename='dummy.txt', disabled=pn.bind(check_func, inp_wid.value))

Thank you…

hi @ahuang11 .
Another use-case which I was just trying out. What would be the approach if there is a tabulator being used and file gets downloaded only when rows are selected ???

import panel as pn
import pandas as pd
def check_selection():
        print("Reaching...")
        selected_indices = tabulator.selection
        if selected_indices:
            # If rows are selected, update the filename for the FileDownload widget
            selected_data = df.iloc[selected_indices]
            selected_data.to_csv('selected_data.csv', index=False)
            return 'selected_data.csv'
        else:
            # If no rows are selected, return None
            return None

data = {
            'Name': ['John', 'Alice', 'Bob', 'Emma'],
            'Age': [30, 25, 40, 35],
            'City': ['New York', 'London', 'Paris', 'Tokyo']
        }
df = pd.DataFrame(data)
tabulator = pn.widgets.Tabulator(df,selectable='checkbox', show_index=False)
download_button = pn.widgets.FileDownload(filename='selected_data.csv', button_type='success', label='Download Selected')
# call back function for fileDownload widget.
download_button.callback = pn.bind(check_selection)
wid_row = pn.Row(tabulator, download_button)
wid_row.servable()

Again the same problem, exception is raised when callback function returns a None value. The callback function expects a file path as a return value. Why can’t a callback function accept None type value or an empty string as return value …???

Edit: Setting a watcher for tabulator will work, we can do something like,

def check_func(event):
     if event.obj.selection:
           print("Rows selected, activating button")
           download_button.disabled = False
           return 
     print("No rows selected, de-activating button")
     download_button.disabled = True

# set watcher for tabulator
tabulator.param.watch(check_func, ['selections'])

pn.bind(check_func, inp_wid.value)

I don’t think this will trigger on update.

Do you mean an automatic trigger without any key-press …??
This approach requires a key-press (‘Enter’ key) to disable/enable the button.

inp_wid.value is like a hardcoded value if I’m not mistaken.

text = pn.widgets.TextInput()

text.value  # 👈 The current value of the widget
text.param.value  # 👈 A reference to the "value" Parameter, used in Panel to bind to the "value"

You are right…!!!
Mistake from my end
Did a quick check. input_wid.value does not trigger the function. input_wid.param.value does.
Also what do you think about the tabulator use-case, do you suggest any other better approach ??