Get file path from upload component

filename does not include path for ‘security reasons’. Is there a way to get the path? I’m parsing a XML using xml.etree.ElementTree. This requires a file with path as input.

1 Like

I tried to find a way to get full file path for some time. Apparently, I’ve found, that even JS inside browser’s window doesn’t know the full path. Browser just hides it and doesn’t expose it to any code or API. So, I suppose, there’s no way to break this wall.

I ended up with old-fashioned TextInput, where user shoud copy-paste path from somewhere else. I know, it looks ugly, but it’s working.

1 Like

I am thinking of a work around - what if I used the dash upload component to grab the filename and contents and then saved the file, using that info, to the server in a pre-determined location. Then I could hard code the file path to server side folder, and call the XML parser function with that filepath and filename.

Anyone see any problems with this?

In many cases, you don’t actually need the filename - The contents of the file are contained through the contents property of the dcc.Upload component. And note that if your app is deployed on a server, you won’t be able to read a file given by the “filename” as that file won’t exist on the server.
If you need to refer to a saved file, then you can just save the contents property to the disk and make up the filename yourself.

If your app is reading files on a local machine, i.e. if you aren’t deploying your app to a server, then an alternative to using the dcc.Upload component would be to display a list of files in a dcc.Dropdown component and allow the user to select a filename.

1 Like

Thanks Chris!

How would one save contents of the XML? I looked through all the commands at: https://dash.plot.ly/dash-core-components/upload

I don’t see anything related to saving contents to disk. Thanks, Nathan

There aren’t any dash-specific functions for this, you’ll just use the standard python methods with the contents variable (which is a string).

1 Like

Nice, thanks for the lead. I’ll get after it and report back. Keep up the good work, Chris - great product.

1 Like

I ended up just using contents directly; no need to worry about path:

def parse_contents(contents, filename, sessionId):
decoded = base64.b64decode(content_string)
stringToXML = ET.ElementTree(ET.fromstring(decoded))
root = tree.getroot()
for a in root:
#parse XML levels…

2 Likes

Anyone know why this worked for weeks and suddenly now does not?

I get error “incorrect padding” on line: decoded = base64.urlsafe_b64decode(contents)

contents is an xml file

@gtg489p I think you are missing some lines?

Maybe you should write following:

def parse_contents(contents, filename, sessionId):
          content_type, content_string = contents.split(',')
         decoded = base64.b64decode(content_string)
         stringToXML = ET.ElementTree(ET.fromstring(decoded))

Hi Chris. Thanks so much for the work you have done. Dash really is amazing.

We are running into a problem where we need the user to select a directory, and require the path to that directory passed to us. Our instance of dash will be deployed locally, so security is not an issue. Any ideas since this is blocked in the Uploader component?

Thanks again,

Dan

1 Like

You cannot access the filesystem directly from the browser for security purpose, there’s no way around that.

What you could do is list the directories from the server and let the user choose from it.

Thanks Phillipe. That is what we are going to have to do.Much appreciated!

Is there anther possibility for a file or folder browser with dash?

Indeed. There seems to be this protective issue, that I truly do not understand, but must have a logical explanation for its existance.

I really need to know the full paths and names of the files I want to open in my Dash App, because I need to write other files that are the result of operations I perform on the input (data) file, in the same place and with specific names derived from the data file.

I have a work-around solution where I read a small text file that I can edit, which contains one of several paths folders I have my data stored. This text file sits in the directory where my App.py script lives. I can have several of them for different data sets.

With the Upload component, the user can select one of them.

The path(s) in the text file is (are) read and then fed to a short function that a collaborator and I wrote and that takes that / those path(s) and searches all the sub-folders down hill and retrieves the full paths + names of the data files I am interested in. It looks like this:

def filesInFolderTree (startPath, extension = '.dat'):

    dirPath = Path (startPath)

    listOfFileNames = [ os.path.join (root, name) \
                        for root, dirs, files in os.walk (dirPath) \
                        for name in sorted(files) \
                        if name.endswith (extension) \
                      ]

    return listOfFileNames

With this listOfFileNames I now create and populate three Dropdown menus. I could have just one, but it would result in a very very long list. So I split it up in three. The user can select the content of the first (folder), which conditions and populates the options of the second (also folder). Then the user choses from the options in the second, which populates the options in the thirds dropdown with the files that are in that folder structure.

It works, but it is still a work-around, and I much rather see a more clean solution.

Hi @chriddyp, I have been able to save the contents in the server only. Is there a way to save them on the client side?

As @chriddyp mentioned, the contents is base64 encoded, by splitting to get the encoded part

x = uploaded_file_contents[0].split(',')[1:2] # as received from the callback
base64string = x[0]

and use base64 decode, u can save it locally or offer a hyperlink for the client to download it.

with open(<filename>.<fileformat>, 'wb') as theFile:
      theFile.write(base64.b64decode(base64string))

Hey @MaartenEMC it seems like there is still no better solution. May you show the entire code and elaborate what you mean with the small text files? I appreciate your help :slight_smile:

1 Like

Is there a way to retrieve a folder path from a dcc component ? Without the need to copy-paste the full path in a TextInput
Thank you.

One work around. I created a button using html.Button. Then I created a callback function which is connected to this button.
Inside the call back function, I used Tkinter.askopenfilename() and return the file path.

now I can read local files without uploading them

1 Like