├── .eslintrc ├── .gitignore ├── ChangeLog ├── README.rst ├── dev-requirements.txt ├── fileupload ├── __init__.py ├── static │ ├── extension.js │ └── widget.js └── widget.py ├── requirements.txt ├── setup.cfg └── setup.py /.eslintrc: -------------------------------------------------------------------------------- 1 | globals: 2 | requirejs: true 3 | env: 4 | browser: true 5 | amd: true 6 | rules: 7 | no-unserscore-dangle: 8 | - 2 9 | quotes: 10 | - 2 11 | - single 12 | brace-style: 13 | - 2 14 | - stroustrup 15 | - allowSingleLine: true 16 | func-style: 17 | - 2 18 | - declaration 19 | consistent-this: 20 | - 0 21 | - self 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | 47 | # Translations 48 | *.mo 49 | *.pot 50 | 51 | # Django stuff: 52 | *.log 53 | 54 | # Sphinx documentation 55 | docs/_build/ 56 | 57 | # PyBuilder 58 | target/ 59 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | CHANGES 2 | ======= 3 | 4 | * clarify README.rst, fix setup.cfg 5 | 6 | 0.1.4 7 | ----- 8 | 9 | * Make button label a traitlet 10 | * fix typo 11 | 12 | 0.1.3 13 | ----- 14 | 15 | * add missing \`install\` instruction 16 | * cleanup 17 | * update installation instructions 18 | * add Jupyter extensions hooks 19 | * Update requirements.txt 20 | * Update README.rst 21 | * update README 22 | 23 | 0.1.1 24 | ----- 25 | 26 | * fixes #4 27 | 28 | 0.1 29 | --- 30 | 31 | * Add shields.io badges 32 | * update setup.cfg, add dev requirements 33 | * Set the universal flag 34 | * closes #3 35 | * Use PY2 compatible super call 36 | * migrate to \`notebook\` 4.0 37 | * \`data\` is now a bytes string 38 | * Update installation instruction 39 | * Install into user directory if system fails 40 | * use a label element 41 | * Use a fake button w/ a nested file input 42 | * add IPython dependency requirement 43 | * update README 44 | * add decode method 45 | * add view and model 46 | * initial commit, scaffold 47 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | IPython File Upload 2 | =================== 3 | 4 | .. image:: https://img.shields.io/pypi/v/fileupload.svg 5 | :target: https://pypi.python.org/pypi/fileupload/ 6 | :alt: Latest Version 7 | 8 | .. image:: https://img.shields.io/pypi/dm/fileupload.svg 9 | :target: https://pypi.python.org/pypi/fileupload/ 10 | :alt: Downloads 11 | 12 | .. image:: https://beta.mybinder.org/badge.svg 13 | :target: https://beta.mybinder.org/v2/gh/draperjames/fileupload2binder/master?filepath=index.ipynb 14 | :alt: Binder 15 | 16 | An IPython notebook widget to upload files, using FileReader_. 17 | 18 | Installation 19 | ------------ 20 | 21 | Install using pip:: 22 | 23 | pip install fileupload 24 | 25 | Install JavaScript:: 26 | 27 | jupyter nbextension install [--user] --py fileupload 28 | 29 | Enable the extension:: 30 | 31 | jupyter nbextension enable [--user] --py fileupload 32 | 33 | Usage 34 | ----- 35 | 36 | .. code-block:: python 37 | 38 | import io 39 | from IPython.display import display 40 | import fileupload 41 | 42 | def _upload(): 43 | 44 | _upload_widget = fileupload.FileUploadWidget() 45 | 46 | def _cb(change): 47 | decoded = io.StringIO(change['owner'].data.decode('utf-8')) 48 | filename = change['owner'].filename 49 | print('Uploaded `{}` ({:.2f} kB)'.format( 50 | filename, len(decoded.read()) / 2 **10)) 51 | 52 | _upload_widget.observe(_cb, names='data') 53 | display(_upload_widget) 54 | 55 | _upload() 56 | 57 | 58 | Base64 data is synced to the ``data_base64`` member, decoded data can be 59 | obtained from ``data``. 60 | The name of the uploaded file is stored in ``filename``. 61 | 62 | Changelog 63 | --------- 64 | 65 | Refer to Changelog_. 66 | 67 | .. _FileReader: https://developer.mozilla.org/en-US/docs/Web/API/FileReader 68 | .. _Changelog: ./ChangeLog 69 | -------------------------------------------------------------------------------- /dev-requirements.txt: -------------------------------------------------------------------------------- 1 | twine>=1.6.5 2 | -------------------------------------------------------------------------------- /fileupload/__init__.py: -------------------------------------------------------------------------------- 1 | from .widget import FileUploadWidget # noqa 2 | 3 | 4 | def _jupyter_nbextension_paths(): 5 | return [dict( 6 | section='notebook', 7 | src='static', 8 | dest='fileupload', 9 | require='fileupload/extension')] 10 | -------------------------------------------------------------------------------- /fileupload/static/extension.js: -------------------------------------------------------------------------------- 1 | if (window.require) { 2 | window.require.config({ 3 | map: { 4 | '*': { 5 | 'fileupload': 'nbextensions/fileupload/widget', 6 | 'jupyter-js-widgets': 'nbextensions/jupyter-js-widgets/extension' 7 | } 8 | } 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /fileupload/static/widget.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'jupyter-js-widgets' 4 | ], function ($, widgets) { 5 | 6 | 'use strict'; 7 | var _getId = (function () { 8 | 9 | var cnt = 0; 10 | return function () { 11 | 12 | cnt += 1; 13 | return 'fileupload_' + cnt; 14 | } 15 | })(); 16 | 17 | var FileUploadView = widgets.DOMWidgetView.extend({ 18 | 19 | render: function render () { 20 | 21 | FileUploadView.__super__.render.apply(this, arguments); 22 | var id = _getId(); 23 | var label = this.model.get('label'); 24 | this.model.on('change:label', this._handleLabelChange, this); 25 | var $label = $('