SimonBiggs / scriptedforms

Quickly create live-update GUIs for Python packages using Markdown and simple HTML elements.
Apache License 2.0
508 stars 34 forks source link

Is there a FilePicker? #267

Open scimax opened 6 years ago

scimax commented 6 years ago

I was testing the details.md and playing around with the interactive elements. What I couldn't find is a way to get a filepath via a filepicker. I think one could get something like that by using the dropdown variables but it probably requires a lot of effort to write the python backend such that it's possible to navigate through the whole file hierarchy.

SimonBiggs commented 6 years ago

I haven't made one no. Primarily I have been trying to expose elements that have been created over at https://material.angular.io/components/categories (which doesn't have a file picker).

However, making a file picker for easy use on my end shouldn't be difficult.

Something like <variable-file>? Really all I would need to do is expose the following HTML API as a markdown element:

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file

What do you think?

SimonBiggs commented 6 years ago

Ahh unfortunately that won't work. :(

https://stackoverflow.com/questions/15201071/how-to-get-full-path-of-selected-file-on-change-of-input-type-file-using-jav

SimonBiggs commented 6 years ago

I'll think further about it. Let me know if you have any ideas for a nice simple implementation.

SimonBiggs commented 6 years ago

@scimax Have a look at the following discussion:

https://groups.google.com/forum/#!topic/jupyter/EmsrRq3bs3M

A solution to the problem mentioned there will solve your issue too. Ideally a file picker would not be stuck inside of ScriptedForms, but instead made with something like ipywidgets and then used within ScriptedForms.

I haven't put much work into making sure all elements of ipywidgets work seamlessly with ScriptedForms, but I want it to, and this is a good use case to focus on to make that the case.

@jasongrout do you know of anyone who has made a filepicker with ipywidgets and has had it be able to return an absolute file path? As in not load the file through html and javascript, but instead use the python kernel to find the file and have the output be the filepath, not the file object.

jasongrout commented 6 years ago

I don't know of work like that, but it sounds useful!

SimonBiggs commented 6 years ago

All right :). Time for me to sharpen my ipywidget skills :)

SimonBiggs commented 6 years ago

@jasongrout I'm guessing a good way about it would be to build upon the design of the JupyterLab file browser and try and package it as an ipywidget. Except I'll have to swap out the backend. Instead of dealing with the the JupyterLab content manager I'll have to have a way that it can browse to any directory.

I guess in a way this is related to the following issue:

https://github.com/jupyterlab/jupyterlab/issues/2532

Would maybe a better option be to work on making it so that there is a configuration option which allows the current file picker to browse any directory? It wouldn't be the default, but it would be an option. And then when I wrap up the file browser as an ipywidget I just pass the "browse anywhere" flag.

@jasongrout what do you think?

scimax commented 6 years ago

Sounds like an interesting approach! A friend of mine used ipywidgets a lot. I will ask him whether he tried to make a filepicker. So far I never tried that.

jasongrout commented 6 years ago

Would maybe a better option be to work on making it so that there is a configuration option which allows the current file picker to browse any directory?

The server (or rather, the default contents manager in the server) does not expose the filesystem above the startup directory - that's a builtin security constraint of the notebook server's contents manager. To get around this security restraint, you'd need to use a custom contents manager in the notebook server.

SimonBiggs commented 6 years ago

Thanks @jasongrout for your help :).

@scimax let me know how you go :) First thing I guess would be to decide if it would be best to use the JupyterLab filebrowser javascript library as a starting point for a front end, or some other js library.

I'll have a look around. If you're friend is keen on working on it too let me know, we should probably make a separate repo and give it a try.

SimonBiggs commented 6 years ago

I might take a second look at writing a custom contents manager.

SimonBiggs commented 6 years ago

This looks like a good start:

https://gist.github.com/DrDub/6efba6e522302e43d055

scimax commented 6 years ago

This looks like a good start: https://gist.github.com/DrDub/6efba6e522302e43d055

Nice! I tried it and it works quite well, but the appearance could be improved a little bit ;)

SimonBiggs commented 6 years ago

It also doesn't currently work within ScriptedForms... So I need to fix that (see https://gitter.im/jupyterlab/jupyterlab?at=5afc1ddcb84be71db90f64b8).

I think I'll make ipywidgets a first class citizen of ScriptedForms. And given the likely common need for a file-picker I think I will essentially create a "shortcut" to an ipywidget file-picker built in directly to ScriptedForms.

The user should just write <variable-filepath>a_variable_name</variable-filepath> and a filepicker should display, which causes a_variable_name to match the absolute path chosen within the picker.

Under the hood it will actually just write in a code block creating the ipywidget.

I'll make sure to make the looks fit in with the rest of ScriptedForms also ;).

SimonBiggs commented 6 years ago

Or maybe I need another 'namespace' for widgets. Maybe <widget-filepicker>a_variable_name</widget-filepicker> hmm... more thought required on that.

SimonBiggs commented 6 years ago

@scimax for your purposes, would it be okay if a file was chosen from the client's computer? And instead of returning a filepath, if instead the file contents was passed through to python?

Would that achieve what you are after?

SimonBiggs commented 6 years ago

@scimax so I have just released scriptedforms-0.9.3.dev0. Install it by running pip uninstall scriptedforms then pip install scriptedforms --pre --no-cache.

I have created a new variable element called <variable-file>. It's designed around the idea of getting the content from the client computer and sending the file content to the server's kernel.

It's not amazing. I haven't done any work on styling, and I won't do that until I can actually get it working how I want it. I set it all up and then was a little sad to see that it can't handle large file sizes. Files that are 10's of kB work, but 10's of MB crashed the kernel :(. But anyway, it's a start. I might have to create a server extension to send the file to the server by custom means.

Do let me know if something along the lines of this however meets your needs.

To use the new variable element create a file that looks like the following:

# Variable File Concept

<section-live>

<variable-file>file_contents</variable-file>

```python
print(file_contents)
```

</section-live>
SimonBiggs commented 6 years ago

I could use a method similar to the following:

https://github.com/jupyterlab/jupyterlab/pull/4224/files#diff-bd689aa63ace50086e2e227f152abcc1R406

Have the file upload to a defined directory say, ".scriptedforms-data/file-uploads". Then have the variable value be the path of that newly created file.

scimax commented 6 years ago

@SimonBiggs Thank you very much for your effort. I just tried it with some text file which works fine. But I think a more general approach would be better. When I tried to load an numpy array file .npy I got a ValueError. Which is not surprising to me. Actually, I don't have a direct application. I was discussing with a collegue about one of his projects. He processes some data for optimization and, as he was asked to make the tool available for users, he is looking for a user frontend. There are basically only two steps for the users. Select a file and submit it.

Now we were trying to evaluate different kinds of techniques to make it as simple as possible. As I really liked the idea of combining markdown formatting with python code, we were also looking into scriptedforms. (Other ideas: just tkinter, wxpython, electron app)

scimax commented 6 years ago

Have the file upload to a defined directory say, ".scriptedforms-data/file-uploads". Then have the variable value be the path of that newly created file.

I think that's better! If the file is treated as temporary, read-only file, it could be simply deleted when the scriptedforms app is terminated.