13

Chciałbym utworzyć widget w Ipython Notebook 3.x lub 4.x (Jupyter, Python 3) do zdalnego wysyłania plików, który pozwala użytkownikowi wybrać wiele plików w przeglądarce plików przeglądarki podczas przesyłania. Niestety, nie mam pojęcia o stronie javascript.Jak zrobić widget do przesyłania wielu plików w Notatniku Ipython?

Znalazłem blueimp's widgets, jednak nie mam pojęcia, jak z nich korzystać w notatniku.

This jest jak jeden widżet Prześlij plik jest wykonany:

import base64 
from __future__ import print_function # py 2.7 compat. 
from IPython.html import widgets # Widget definitions. 
from IPython.utils.traitlets import Unicode # Traitlet needed to add synced attributes to the widget. 
class FileWidget(widgets.DOMWidget): 
    _view_name = Unicode('FilePickerView', sync=True) 
    value = Unicode(sync=True) 
    filename = Unicode(sync=True) 

    def __init__(self, **kwargs): 
     """Constructor""" 
     widgets.DOMWidget.__init__(self, **kwargs) # Call the base. 

     # Allow the user to register error callbacks with the following signatures: 
     # callback() 
     # callback(sender) 
     self.errors = widgets.CallbackDispatcher(accepted_nargs=[0, 1]) 

     # Listen for custom msgs 
     self.on_msg(self._handle_custom_msg) 

    def _handle_custom_msg(self, content): 
     """Handle a msg from the front-end. 

     Parameters 
     ---------- 
     content: dict 
      Content of the msg.""" 
     if 'event' in content and content['event'] == 'error': 
      self.errors() 
      self.errors(self) 
%%javascript 

require(["widgets/js/widget", "widgets/js/manager"], function(widget, manager){ 

    var FilePickerView = widget.DOMWidgetView.extend({ 
     render: function(){ 
      // Render the view. 
      this.setElement($('<input />') 
       .attr('type', 'file')); 
     }, 

     events: { 
      // List of events and their handlers. 
      'change': 'handle_file_change', 
     }, 

     handle_file_change: function(evt) { 
      // Handle when the user has changed the file. 

      // Retrieve the first (and only!) File from the FileList object 
      var file = evt.target.files[0]; 
      if (file) { 

       // Read the file's textual content and set value to those contents. 
       var that = this; 
       var file_reader = new FileReader(); 
       file_reader.onload = function(e) { 
        that.model.set('value', e.target.result); 
        that.touch(); 
       } 
       file_reader.readAsText(file); 
      } else { 

       // The file couldn't be opened. Send an error msg to the 
       // back-end. 
       this.send({ 'event': 'error' }); 
      } 

      // Set the filename of the file. 
      this.model.set('filename', file.name); 
      this.touch(); 
     }, 
    }); 

    // Register the FilePickerView with the widget manager. 
    manager.WidgetManager.register_widget_view('FilePickerView', FilePickerView); 
}); 
file_widget = FileWidget() 

# Register an event to echo the filename when it has been changed. 
def file_loading(): 
    print("Loading %s" % file_widget.filename) 
file_widget.on_trait_change(file_loading, 'filename') 

# Register an event to echo the filename and contents when a file 
# has been uploaded. 
def file_loaded(): 
    print("Loaded, file contents: %s" % file_widget.value) 
file_widget.on_trait_change(file_loaded, 'value') 

# Register an event to print an error message when a file could not 
# be opened. Since the error messages are not handled through 
# traitlets but instead handled through custom msgs, the registration 
# of the handler is different than the two examples above. Instead 
# the API provided by the CallbackDispatcher must be used. 
def file_failed(): 
    print("Could not load file contents of %s" % file_widget.filename) 
file_widget.errors.register_callback(file_failed) 

file_widget 
+0

Wiem, że na pulpicie nawigacyjnym jest przycisk przesyłania. Chciałbym go mieć w moim własnym notesie. – user1898037

Odpowiedz

2

Komentarze, sugestie i poprawki są mile widziane.

Zainspirował mnie sam Notatnik Jupyter (4.x) z funkcji NotebookList.prototype.handleFilesUpload pliku notebooklist.js. Po przeczytaniu na jakimś składni JavaScript, wymyśliłem następujące:

(. Należy pamiętać, że pliki są przesyłane w trybie tekstowym bez sprawdzenia)

import base64 # You need it if you define binary uploads 
from __future__ import print_function # py 2.7 compat. 
import ipywidgets as widgets # Widget definitions. 
from traitlets import List, Unicode # Traitlets needed to add synced attributes to the widget. 

class FileWidget(widgets.DOMWidget): 
    _view_name = Unicode('FilePickerView').tag(sync=True) 
    _view_module = Unicode('filepicker').tag(sync=True) 
    filenames = List([], sync=True) 
    # values = List(trait=Unicode, sync=True) 

    def __init__(self, **kwargs): 
     """Constructor""" 
     super().__init__(**kwargs) 

     # Allow the user to register error callbacks with the following signatures: 
     # callback() 
     # callback(sender) 
     self.errors = widgets.CallbackDispatcher(accepted_nargs=[0, 1]) 

     # Listen for custom msgs 
     self.on_msg(self._handle_custom_msg) 

    def _handle_custom_msg(self, content): 
     """Handle a msg from the front-end. 

     Parameters 
     ---------- 
     content: dict 
      Content of the msg.""" 
     if 'event' in content and content['event'] == 'error': 
      self.errors() 
      self.errors(self) 
%%javascript 
requirejs.undef('filepicker'); 

define('filepicker', ["jupyter-js-widgets"], function(widgets) { 

    var FilePickerView = widgets.DOMWidgetView.extend({ 
     render: function(){ 
      // Render the view using HTML5 multiple file input support. 
      this.setElement($('<input class="fileinput" multiple="multiple" name="datafile" />') 
       .attr('type', 'file')); 
     }, 

     events: { 
      // List of events and their handlers. 
      'change': 'handle_file_change', 
     }, 

     handle_file_change: function(evt) { 
      // Handle when the user has changed the file. 

      // Save context (or namespace or whatever this is) 
      var that = this; 

      // Retrieve the FileList object 
      var files = evt.originalEvent.target.files; 
      var filenames = []; 
      var file_readers = []; 
      console.log("Reading files:"); 

      for (var i = 0; i < files.length; i++) { 
       var file = files[i]; 
       console.log("Filename: " + file.name); 
       console.log("Type: " + file.type); 
       console.log("Size: " + file.size + " bytes"); 
       filenames.push(file.name); 

       // Read the file's textual content and set value_i to those contents. 
       file_readers.push(new FileReader()); 
       file_readers[i].onload = (function(file, i) { 
        return function(e) { 
         that.model.set('value_' + i, e.target.result); 
         that.touch(); 
         console.log("file_" + i + " loaded: " + file.name); 
        }; 
       })(file, i); 

       file_readers[i].readAsText(file); 
      } 

      // Set the filenames of the files. 
      this.model.set('filenames', filenames); 
      this.touch(); 
     }, 
    }); 

    // Register the FilePickerView with the widget manager. 
    return { 
     FilePickerView: FilePickerView 
    }; 
}); 
file_widget = FileWidget() 

def file_loaded(change): 
    '''Register an event to save contents when a file has been uploaded.''' 
    print(change['new']) 
    i = int(change['name'].split('_')[1]) 
    fname = file_widget.filenames[i] 
    print('file_loaded: {}'.format(fname)) 

def file_loading(change): 
    '''Update self.model when user requests a list of files to be uploaded''' 
    print(change['new']) 
    num = len(change['new']) 
    traits = [('value_{}'.format(i), Unicode(sync=True)) for i in range(num)] 
    file_widget.add_traits(**dict(traits)) 
    for i in range(num): 
     file_widget.observe(file_loaded, 'value_{}'.format(i)) 
file_widget.observe(file_loading, names='filenames') 

def file_failed(): 
    print("Could not load some file contents.") 
file_widget.errors.register_callback(file_failed) 


file_widget 

guzik z Powinien pojawić się tekst Browse... określający liczbę wybranych plików. Ponieważ instrukcje print są zawarte w funkcjach file_loading i file_loaded, powinieneś zobaczyć nazwy plików i zawartość plików na wyjściu. Nazwy plików i typy plików są również wyświetlane w dzienniku konsoli.

2

Ten problem https://github.com/ipython/ipython/issues/8383 odpowiedzi na swoje pytanie częściowo. Istnieje już przycisk przesyłania w jupyter 4.0 na ekranie Dashboard. Ten przycisk przesyłania obsługuje wybieranie wielu plików.

Zauważ, że aktualne linki znajdują się tutaj wysyłania widget:

https://github.com/ipython/ipywidgets/blob/master/docs/source/examples/File%20Upload%20Widget.ipynb

Jest tam również rozszerzenie dostępne do pobrania i szybki montaż w swoich notebookach:

https://github.com/peteut/ipython-file-upload

pip install fileupload 

lub

pip install git+https://github.com/peteut/ipython-file-upload 

Należy zauważyć, że rozszerzenie zostało potwierdzone do pracy na Linuksie tylko w zależności od autora.

+1

Dzięki, jestem tego świadomy. Chciałbym mieć widżet w moim notesie. – user1898037

+0

Dzięki za aktualizację. Podane łącza pokazują pojedyncze mechanizmy przesyłania plików. Szukam widżetu do przesyłania wielu plików lub wskazówek dotyczących widżetu przesyłania wielu plików. Pytanie już pokazuje rozwiązanie dla pojedynczego widżetu przesyłania plików. – user1898037

Powiązane problemy