diff --git a/ipyvuetify/extra/file_input.py b/ipyvuetify/extra/file_input.py
index 30fb52b5..f76a41de 100644
--- a/ipyvuetify/extra/file_input.py
+++ b/ipyvuetify/extra/file_input.py
@@ -3,10 +3,13 @@
import io
import os
import sys
+import warnings
import IPython
import nest_asyncio
import traitlets
+from ipywidgets import dlink, widget_serialization
+from traitlets import Any, Bool, Dict, Float, Int, List, Unicode, Union
import ipyvuetify as v
@@ -52,7 +55,7 @@ def __init__(self, widget, file_index, timeout=30):
self.timeout = timeout
self.valid = True
self.offset = 0
- self.size = widget.file_info[file_index]["size"]
+ self.size = widget.v_model[file_index]["size"]
self.chunk_queue = []
@@ -148,26 +151,178 @@ def readall(self):
class FileInput(v.VuetifyTemplate):
- template = traitlets.Unicode(load_template("file_input.vue")).tag(sync=True)
- data = traitlets.Unicode("{myfiles: undefined}").tag(sync=True)
-
- file_info = traitlets.List().tag(sync=True)
- version = traitlets.Int(0).tag(sync=True)
- multiple = traitlets.Bool(True).tag(sync=True)
- disabled = traitlets.Bool(False).tag(sync=True)
- directory = traitlets.Bool(False).tag(sync=True)
- accept = traitlets.Unicode().tag(sync=True)
- total_progress = traitlets.Int(0).tag(sync=True)
- show_progress = traitlets.Bool(True).tag(sync=True)
- progress_indeterminate = traitlets.Bool(False).tag(sync=True)
+ append_icon = Unicode(None, allow_none=True).tag(sync=True)
+
+ append_outer_icon = Unicode(None, allow_none=True).tag(sync=True)
+
+ autofocus = Bool(None, allow_none=True).tag(sync=True)
+
+ background_color = Unicode(None, allow_none=True).tag(sync=True)
+
+ chips = Bool(None, allow_none=True).tag(sync=True)
+
+ clear_icon = Unicode(None, allow_none=True).tag(sync=True)
+
+ clearable = Bool(None, allow_none=True).tag(sync=True)
+
+ color = Unicode(None, allow_none=True).tag(sync=True)
+
+ counter = Union([Bool(), Float(), Unicode()], default_value=None, allow_none=True).tag(sync=True)
+
+ counter_size_string = Unicode(None, allow_none=True).tag(sync=True)
+
+ counter_string = Unicode(None, allow_none=True).tag(sync=True)
+
+ dark = Bool(None, allow_none=True).tag(sync=True)
+
+ dense = Bool(None, allow_none=True).tag(sync=True)
+
+ disabled = Bool(None, allow_none=True).tag(sync=True)
+
+ error = Bool(None, allow_none=True).tag(sync=True)
+
+ error_count = Union([Float(), Unicode()], default_value=None, allow_none=True).tag(sync=True)
+
+ error_messages = Union([Unicode(), List(Any())], default_value=None, allow_none=True).tag(sync=True)
+
+ filled = Bool(None, allow_none=True).tag(sync=True)
+
+ flat = Bool(None, allow_none=True).tag(sync=True)
+
+ full_width = Bool(None, allow_none=True).tag(sync=True)
+
+ height = Union([Float(), Unicode()], default_value=None, allow_none=True).tag(sync=True)
+
+ hide_details = Union([Bool(), Unicode()], default_value=None, allow_none=True).tag(sync=True)
+
+ # Missing Vuetify prop: hide-input
+
+ hint = Unicode(None, allow_none=True).tag(sync=True)
+
+ id = Unicode(None, allow_none=True).tag(sync=True)
+
+ label = Unicode(None, allow_none=True).tag(sync=True)
+
+ light = Bool(None, allow_none=True).tag(sync=True)
+
+ loader_height = Union([Float(), Unicode()], default_value=None, allow_none=True).tag(sync=True)
+
+ loading = Union([Bool(), Unicode()], default_value=None, allow_none=True).tag(sync=True)
+
+ messages = Union([Unicode(), List(Any())], default_value=None, allow_none=True).tag(sync=True)
+
+ multiple = Bool(None, allow_none=True).tag(sync=True)
+
+ outlined = Bool(None, allow_none=True).tag(sync=True)
+
+ persistent_hint = Bool(None, allow_none=True).tag(sync=True)
+
+ # Missing Vuetify prop: persistent-placeholder
+
+ placeholder = Unicode(None, allow_none=True).tag(sync=True)
+
+ prefix = Unicode(None, allow_none=True).tag(sync=True)
+
+ prepend_icon = Unicode(None, allow_none=True).tag(sync=True)
+
+ prepend_inner_icon = Unicode(None, allow_none=True).tag(sync=True)
+
+ readonly = Bool(None, allow_none=True).tag(sync=True)
+
+ reverse = Bool(None, allow_none=True).tag(sync=True)
+
+ rounded = Bool(None, allow_none=True).tag(sync=True)
+
+ rules = List(Any(), default_value=None, allow_none=True).tag(sync=True)
+
+ shaped = Bool(None, allow_none=True).tag(sync=True)
+
+ show_size = Union([Bool(), Float()], default_value=None, allow_none=True).tag(sync=True)
+
+ single_line = Bool(None, allow_none=True).tag(sync=True)
+
+ small_chips = Bool(None, allow_none=True).tag(sync=True)
+
+ solo = Bool(None, allow_none=True).tag(sync=True)
+
+ solo_inverted = Bool(None, allow_none=True).tag(sync=True)
+
+ success = Bool(None, allow_none=True).tag(sync=True)
+
+ success_messages = Union([Unicode(), List(Any())], default_value=None, allow_none=True).tag(sync=True)
+
+ suffix = Unicode(None, allow_none=True).tag(sync=True)
+
+ truncate_length = Union([Float(), Unicode()], default_value=None, allow_none=True).tag(sync=True)
+
+ type = Unicode(None, allow_none=True).tag(sync=True)
+
+ validate_on_blur = Bool(None, allow_none=True).tag(sync=True)
+
+ value = Any(None, allow_none=True).tag(sync=True)
+
+ # VueWidget props
+
+ v_model = List(Dict(), allow_none=True).tag(sync=True)
+
+ style_ = Unicode(None, allow_none=True).tag(sync=True)
+
+ class_ = Unicode(None, allow_none=True).tag(sync=True)
+
+ attributes = Dict(None, allow_none=True).tag(sync=True)
+
+ v_slots = List(Dict()).tag(sync=True, **widget_serialization)
+
+ v_on = Unicode(None, allow_none=True).tag(sync=True)
+
+ # Component-specific props
+
+ template = Unicode(load_template("file_input.vue")).tag(sync=True)
+
+ version = Int(0).tag(sync=True)
+
+ total_progress = Int(0).tag(sync=True)
+
+ progress_indeterminate = Bool(False).tag(sync=True)
+
+ file_info = List(Dict(), allow_none=True) # Deprecated, use v_model instead
total_progress_inner = 0
total_size_inner = 0
- def __init__(self, **kwargs):
+ def __init__(self, *args, **kwargs):
self.chunk_listeners = {}
self.stats = []
- super().__init__(**kwargs)
+
+ # Keep default behaviour
+ kwargs.setdefault("multiple", True)
+ kwargs.setdefault("clearable", True)
+
+ attributes = kwargs.setdefault("attributes", {})
+ if "accept" in kwargs:
+ warnings.warn("accept argument is deprecated, use attributes dictionary instead", DeprecationWarning)
+ attributes["accept"] = kwargs["accept"]
+ del kwargs["accept"]
+ if "directory" in kwargs:
+ warnings.warn("directory argument is deprecated, use attributes dictionary instead", DeprecationWarning)
+ attributes["directory"] = kwargs["directory"]
+ del kwargs["directory"]
+ if "show_progress" in kwargs:
+ warnings.warn(
+ "show_progress argument is deprecated, use v_slots to change the progress slot", DeprecationWarning
+ )
+ del kwargs["show_progress"]
+ if "file_info" in kwargs:
+ warnings.warn("file_info cannot be set on FileInput")
+ del kwargs["file_info"]
+ if "v_model" in kwargs:
+ warnings.warn("v_model cannot be set on FileInput")
+ del kwargs["v_model"]
+
+ # Maintain backwards compatibility for the file_info
+ dlink((self, "v_model"), (self, "file_info"))
+
+ super().__init__(*args, **kwargs)
if not hasattr(IPython.get_ipython(), "kernel"):
return
@@ -175,8 +330,26 @@ def __init__(self, **kwargs):
if kernel.implementation == "ipython":
nest_asyncio.apply()
- @traitlets.observe("file_info")
- def _file_info_changed(self, _):
+ # @property
+ # def file_info(self):
+ # warnings.warn("file_info is deprecated, use v_model instead", DeprecationWarning)
+ # return self.v_model
+
+ # @file_info.setter
+ # def file_info(self, _):
+ # warnings.warn("file_info is deprecated and cannot be set on FileInput")
+
+ @property
+ def show_progress(self):
+ warnings.warn("show_progress is deprecated, use v_slots to change the progress slot", DeprecationWarning)
+ return True
+
+ @show_progress.setter
+ def show_progress(self, _):
+ warnings.warn("show_progress is deprecated, use v_slots to change the progress slot", DeprecationWarning)
+
+ @traitlets.observe("v_model")
+ def _v_model_changed(self, _):
self.version += 1
self.reset_stats()
@@ -190,8 +363,8 @@ def update_stats(self, file_index, bytes_read):
def get_files(self, timeout=30):
files = []
- for index, file in enumerate(self.file_info):
- file = copy.deepcopy(self.file_info[index])
+ for index, file in enumerate(self.v_model):
+ file = copy.deepcopy(self.v_model[index])
file["file_obj"] = ClientSideFile(self, index, timeout=timeout)
files.append(file)
return files
@@ -201,10 +374,10 @@ def clear(self):
self.send({"method": "clear", "args": []})
def reset_stats(self):
- self.stats = [0 for _ in self.file_info]
+ self.stats = [0 for _ in self.v_model]
self.total_progress = 0
self.total_progress_inner = 0
- self.total_size_inner = sum([f["size"] for f in self.file_info])
+ self.total_size_inner = sum([f["size"] for f in self.v_model])
def vue_upload(self, content, buffers):
listener_id = content["id"]
diff --git a/ipyvuetify/extra/file_input.vue b/ipyvuetify/extra/file_input.vue
index 6d8a8401..3648f8f5 100644
--- a/ipyvuetify/extra/file_input.vue
+++ b/ipyvuetify/extra/file_input.vue
@@ -1,25 +1,22 @@
-
-
-
-
+
+
+
+
+
+
+
+