Skip to content

Commit

Permalink
fix: backward compability file_drop
Browse files Browse the repository at this point in the history
  • Loading branch information
hkayabilisim committed Mar 19, 2024
1 parent aca8bb0 commit 7d44858
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 26 deletions.
48 changes: 38 additions & 10 deletions solara/components/file_drop.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import threading
import typing
from typing import Callable, Optional, cast, List
from typing import Callable, Optional, cast, List, Union, overload
from typing_extensions import Literal

import traitlets
from ipyvue import Template
Expand All @@ -26,24 +27,44 @@ class FileDropZone(FileInput):
items = traitlets.List(default_value=[]).tag(sync=True)
label = traitlets.Unicode().tag(sync=True)

@overload
@solara.component
def FileDrop(
label: str = ...,
on_total_progress: Optional[Callable[[float], None]] = ...,
on_file: Optional[Callable[[FileInfo], None]] = None,
lazy: bool = ...,
multiple: Literal[False] = ...,
): ...

@overload
@solara.component
def FileDrop(
label: str = ...,
on_total_progress: Optional[Callable[[float], None]] = ...,
on_file: Optional[Callable[[List[FileInfo]], None]] = None,
lazy: bool = ...,
multiple: Literal[True] = ...,
): ...

@solara.component
def FileDrop(
label="Drop file here",
on_total_progress: Optional[Callable[[float], None]] = None,
on_file: Optional[Callable[[List[FileInfo]], None]] = None,
on_file: Optional[Callable[[Union[FileInfo,List[FileInfo]]], None]] = None,
lazy: bool = True,
multiple: bool = False,
):
"""Region a user can drop a file or multiple files into for file uploading.
"""Region a user can drop file(s) into for file uploading.
If lazy=True, no file contents will be loaded into memory,
nor will any data be transferred by default.
A list of file objects is passed to the `on_file` callback, and data will be transferred
when needed.
If lazy=False, the file contents will be loaded into memory and passed to the `on_file` callback via the `FileInfo.data` attribute.
If multiple=False, a single `FileInfo` object is passed on the `on_file` callback.
If multiple=True, `on_file` receives a list of `FileInfo` objects. Directories are ignored.
If lazy=False, the file contents will be loaded into memory and passed to the `on_file` callback via the `.data` attribute.
The on_file callback takes the list of following argument type:
A file object is of the following argument type:
```python
class FileInfo(typing.TypedDict):
name: str # file name
Expand All @@ -55,9 +76,13 @@ class FileInfo(typing.TypedDict):
## Arguments
* `on_total_progress`: Will be called with the progress in % of the file(s) upload.
* `on_file`: Will be called with a `List[FileInfo]` objects, each of which contains the file `.name`, `.length` and a `.file_obj` object.
* `on_file`: Will be called with a `List[FileInfo]` or `FileInfo` when multiple=True or multiple=False, respectively.
Each `FileInfo` contains the file `.name`, `.length`, `.file_obj` object, and `.data` attributes.
* `lazy`: Whether to load the file contents into memory or not. If `False`,
the file contents will be loaded into memory and passed to the `on_file` callback via the `.data` attribute.
the file contents will be loaded into memory via the `.data` attribute of file object(s).
* `multiple`: Whether to allow uploading multiple files. By default (multiple=False), only a single file
(the first one if multiple files are dropped) is passed on to `on_file` callback function.
If `multiple=True`, the list of dropped files is passed to `on_file`.
"""
file_info, set_file_info = solara.use_state(None)
Expand Down Expand Up @@ -88,7 +113,10 @@ def handle_file(cancel: threading.Event):
wired_files[i]["data"] = wired_files[i]["file_obj"].read()
else:
wired_files[i]["data"] = None
on_file(wired_files)
if multiple:
on_file(wired_files)
else:
on_file(wired_files[0])

result: solara.Result = hooks.use_thread(handle_file, [wired_files])
if result.error:
Expand Down
21 changes: 12 additions & 9 deletions solara/components/file_drop.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
<template>
<div ref="dropzone" class="solara-file-drop" effectAllowed="move">
<div v-if="file_info && file_info.length">
<ul>
<li v-for="file in file_info">{{ file.name }} {{ file.size }} bytes</li>
</ul>
</div>
<div v-else>
<template v-if="file_info && file_info.length === 1">
{{ file_info[0].name }}
</template>
<template v-else-if="file_info && file_info.length > 1">
<div v-for="file in file_info">
{{ file.name }}
</div>
</template>
<template v-else>
{{ label }}
</div>
</template>
</div>
</template>

Expand All @@ -29,9 +32,9 @@ module.exports = {
this.native_file_info = nativeFiles
this.file_info = this.native_file_info.map(
({name, isFile, size}) => ({
({name, size}) => ({
name,
isFile: !!isFile, // Ensure this is a boolean
isFile: true,
size,
}));
});
Expand Down
25 changes: 19 additions & 6 deletions solara/website/pages/api/file_drop.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,37 @@
import solara
from solara.components.file_drop import FileInfo
from solara.website.utils import apidoc
from typing import List


@solara.component
def Page():
content, set_content = solara.use_state([])
filename, set_filename = solara.use_state([])
size, set_size = solara.use_state([])
multiple_upload, set_multiple_upload = solara.use_state(False)

def on_file(file: FileInfo):
set_filename([f["name"] for f in file])
set_size([f["size"] for f in file])
set_content([f["file_obj"].read(100) for f in file])
def process_input(input):
if isinstance(input, list):
process_multiple_files(input)
else:
process_single_file(input)

def process_multiple_files(files: List[FileInfo]):
set_filename([f["name"] for f in files])
set_size([f["size"] for f in files])
set_content([f["file_obj"].read(100) for f in files])

def process_single_file(file: FileInfo):
process_multiple_files([file])

with solara.Div() as main:
solara.Checkbox(label="Multiple upload", value=multiple_upload, on_value=set_multiple_upload)
solara.FileDrop(
label="Drag and drop a file or multiple files here to read the first 100 bytes",
on_file=on_file,
label="Drag and drop files(s) here to read the first 100 bytes",
on_file=process_input,
lazy=True, # We will only read the first 100 bytes
multiple=multiple_upload
)
if content:
solara.Info(f'Number of uploaded files: {len(filename)}')
Expand Down
2 changes: 1 addition & 1 deletion solara/website/pages/apps/scatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def load_sample():

@staticmethod
def load_from_file(file):
df = pd.read_csv(file[0]["file_obj"])
df = pd.read_csv(file["file_obj"])
State.x.value = str(df.columns[0])
State.y.value = str(df.columns[1])
State.size.value = str(df.columns[2])
Expand Down

0 comments on commit 7d44858

Please sign in to comment.