Moves jupyter extension to both bonobo.contrib.jupyter (for the jupyter widget) and to bonobo.plugins (for the executor-side plugin).

This commit is contained in:
Romain Dorgueil
2017-11-12 09:08:05 +01:00
parent 4bea3f7dad
commit d1481fbfe8
42 changed files with 183 additions and 128 deletions

2
.gitignore vendored
View File

@ -23,8 +23,8 @@
.python-version .python-version
/.idea /.idea
/.release /.release
/bonobo/contrib/jupyter/js/node_modules/
/bonobo/examples/work_in_progress/ /bonobo/examples/work_in_progress/
/bonobo/ext/jupyter/js/node_modules/
/build/ /build/
/coverage.xml /coverage.xml
/dist/ /dist/

View File

@ -1,4 +1,4 @@
# Generated by Medikit 0.4.1 on 2017-11-04. # Generated by Medikit 0.4.1 on 2017-11-12.
# All changes will be overriden. # All changes will be overriden.
PACKAGE ?= bonobo PACKAGE ?= bonobo
@ -10,6 +10,7 @@ PYTHON_REQUIREMENTS_DEV_FILE ?= requirements-dev.txt
QUICK ?= QUICK ?=
PIP ?= $(PYTHON_DIRNAME)/pip PIP ?= $(PYTHON_DIRNAME)/pip
PIP_INSTALL_OPTIONS ?= PIP_INSTALL_OPTIONS ?=
VERSION ?= $(shell git describe 2>/dev/null || git rev-parse --short HEAD)
PYTEST ?= $(PYTHON_DIRNAME)/pytest PYTEST ?= $(PYTHON_DIRNAME)/pytest
PYTEST_OPTIONS ?= --capture=no --cov=$(PACKAGE) --cov-report html PYTEST_OPTIONS ?= --capture=no --cov=$(PACKAGE) --cov-report html
SPHINX_BUILD ?= $(PYTHON_DIRNAME)/sphinx-build SPHINX_BUILD ?= $(PYTHON_DIRNAME)/sphinx-build
@ -18,7 +19,6 @@ SPHINX_SOURCEDIR ?= docs
SPHINX_BUILDDIR ?= $(SPHINX_SOURCEDIR)/_build SPHINX_BUILDDIR ?= $(SPHINX_SOURCEDIR)/_build
YAPF ?= $(PYTHON) -m yapf YAPF ?= $(PYTHON) -m yapf
YAPF_OPTIONS ?= -rip YAPF_OPTIONS ?= -rip
VERSION ?= $(shell git describe 2>/dev/null || echo dev)
.PHONY: $(SPHINX_SOURCEDIR) clean format install install-dev test update update-requirements .PHONY: $(SPHINX_SOURCEDIR) clean format install install-dev test update update-requirements

View File

@ -18,9 +18,9 @@ python.setup(
data_files=[ data_files=[
( (
'share/jupyter/nbextensions/bonobo-jupyter', [ 'share/jupyter/nbextensions/bonobo-jupyter', [
'bonobo/ext/jupyter/static/extension.js', 'bonobo/contrib/jupyter/static/extension.js',
'bonobo/ext/jupyter/static/index.js', 'bonobo/contrib/jupyter/static/index.js',
'bonobo/ext/jupyter/static/index.js.map', 'bonobo/contrib/jupyter/static/index.js.map',
] ]
), ),
], ],
@ -41,23 +41,24 @@ python.setup(
python.add_requirements( python.add_requirements(
'fs >=2.0,<2.1', 'fs >=2.0,<2.1',
'jinja2 >=2.9,<2.10', 'graphviz >=0.8,<0.9',
'jinja2 >=2.9,<3',
'mondrian >=0.4,<0.5', 'mondrian >=0.4,<0.5',
'packaging >=16,<17', 'packaging >=16,<17',
'psutil >=5.4,<6.0', 'psutil >=5.4,<6',
'requests >=2.0,<3.0', 'requests >=2,<3',
'stevedore >=1.27,<1.28', 'stevedore >=1.27,<1.28',
'whistle >=1.0,<1.1', 'whistle >=1.0,<1.1',
dev=[ dev=[
'pytest-sugar >=0.8,<0.9', 'pytest-sugar >=0.9,<0.10',
'pytest-timeout >=1,<2', 'pytest-timeout >=1,<2',
], ],
docker=[ docker=[
'bonobo-docker >=0.5.0', 'bonobo-docker >=0.5.0',
], ],
jupyter=[ jupyter=[
'jupyter >=1.0,<1.1',
'ipywidgets >=6.0.0,<7', 'ipywidgets >=6.0.0,<7',
'jupyter >=1.0,<1.1',
], ],
sqlalchemy=[ sqlalchemy=[
'bonobo-sqlalchemy >=0.5.1', 'bonobo-sqlalchemy >=0.5.1',
@ -66,6 +67,6 @@ python.add_requirements(
# Following requirements are not enforced, because some dependencies enforce them so we don't want to break # Following requirements are not enforced, because some dependencies enforce them so we don't want to break
# the packaging in case it changes in dep. # the packaging in case it changes in dep.
python.add_requirements('colorama >=0.3', ) python.add_requirements('colorama >=0.3')
# vim: ft=python: # vim: ft=python:

View File

@ -74,7 +74,7 @@ def run(graph, *, plugins=None, services=None, strategy=None):
if _is_jupyter_notebook(): if _is_jupyter_notebook():
try: try:
from bonobo.ext.jupyter import JupyterOutputPlugin from bonobo.contrib.jupyter import JupyterOutputPlugin
except ImportError: except ImportError:
import logging import logging
logging.warning( logging.warning(

View File

@ -0,0 +1,15 @@
from bonobo.plugins.jupyter import JupyterOutputPlugin
def _jupyter_nbextension_paths():
return [{
'section': 'notebook',
'src': 'static',
'dest': 'bonobo-jupyter',
'require': 'bonobo-jupyter/extension'
}]
__all__ = [
'JupyterOutputPlugin',
]

1
bonobo/contrib/jupyter/js/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/node_modules

View File

@ -0,0 +1,19 @@
Bonobo within Jupyter
=====================
Install
-------
.. code-block:: shell-session
yarn install
Watch mode (for development)
----------------------------
.. code-block:: shell-session
yarn run webpack --watch

View File

@ -69,7 +69,7 @@ define(["jupyter-js-widgets"], function(__WEBPACK_EXTERNAL_MODULE_2__) { return
// When serialiazing entire widget state for embedding, only values different from the // When serialiazing entire widget state for embedding, only values different from the
// defaults will be specified. // defaults will be specified.
var BonoboModel = widgets.DOMWidgetModel.extend({ const BonoboModel = widgets.DOMWidgetModel.extend({
defaults: _.extend({}, widgets.DOMWidgetModel.prototype.defaults, { defaults: _.extend({}, widgets.DOMWidgetModel.prototype.defaults, {
_model_name: 'BonoboModel', _model_name: 'BonoboModel',
_view_name: 'BonoboView', _view_name: 'BonoboView',
@ -81,7 +81,7 @@ define(["jupyter-js-widgets"], function(__WEBPACK_EXTERNAL_MODULE_2__) { return
// Custom View. Renders the widget model. // Custom View. Renders the widget model.
var BonoboView = widgets.DOMWidgetView.extend({ const BonoboView = widgets.DOMWidgetView.extend({
render: function () { render: function () {
this.value_changed(); this.value_changed();
this.model.on('change:value', this.value_changed, this); this.model.on('change:value', this.value_changed, this);
@ -89,7 +89,9 @@ define(["jupyter-js-widgets"], function(__WEBPACK_EXTERNAL_MODULE_2__) { return
value_changed: function () { value_changed: function () {
this.$el.html( this.$el.html(
this.model.get('value').join('<br>') '<div class="rendered_html"><table style="margin: 0; border: 1px solid black;">' + this.model.get('value').map((key, i) => {
return `<tr><td>${key.status}</td><td>${key.name}</td><td>${key.stats}</td><td>${key.flags}</td></tr>`
}).join('\n') + '</table></div>'
); );
}, },
}); });

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,7 @@ var _ = require('underscore');
// When serialiazing entire widget state for embedding, only values different from the // When serialiazing entire widget state for embedding, only values different from the
// defaults will be specified. // defaults will be specified.
var BonoboModel = widgets.DOMWidgetModel.extend({ const BonoboModel = widgets.DOMWidgetModel.extend({
defaults: _.extend({}, widgets.DOMWidgetModel.prototype.defaults, { defaults: _.extend({}, widgets.DOMWidgetModel.prototype.defaults, {
_model_name: 'BonoboModel', _model_name: 'BonoboModel',
_view_name: 'BonoboView', _view_name: 'BonoboView',
@ -20,7 +20,7 @@ var BonoboModel = widgets.DOMWidgetModel.extend({
// Custom View. Renders the widget model. // Custom View. Renders the widget model.
var BonoboView = widgets.DOMWidgetView.extend({ const BonoboView = widgets.DOMWidgetView.extend({
render: function () { render: function () {
this.value_changed(); this.value_changed();
this.model.on('change:value', this.value_changed, this); this.model.on('change:value', this.value_changed, this);
@ -28,7 +28,9 @@ var BonoboView = widgets.DOMWidgetView.extend({
value_changed: function () { value_changed: function () {
this.$el.html( this.$el.html(
this.model.get('value').join('<br>') '<div class="rendered_html"><table style="margin: 0; border: 1px solid black;">' + this.model.get('value').map((key, i) => {
return `<tr><td>${key.status}</td><td>${key.name}</td><td>${key.stats}</td><td>${key.flags}</td></tr>`
}).join('\n') + '</table></div>'
); );
}, },
}); });

View File

@ -72,7 +72,7 @@ define(["jupyter-js-widgets"], function(__WEBPACK_EXTERNAL_MODULE_2__) { return
// When serialiazing entire widget state for embedding, only values different from the // When serialiazing entire widget state for embedding, only values different from the
// defaults will be specified. // defaults will be specified.
var BonoboModel = widgets.DOMWidgetModel.extend({ const BonoboModel = widgets.DOMWidgetModel.extend({
defaults: _.extend({}, widgets.DOMWidgetModel.prototype.defaults, { defaults: _.extend({}, widgets.DOMWidgetModel.prototype.defaults, {
_model_name: 'BonoboModel', _model_name: 'BonoboModel',
_view_name: 'BonoboView', _view_name: 'BonoboView',
@ -84,7 +84,7 @@ define(["jupyter-js-widgets"], function(__WEBPACK_EXTERNAL_MODULE_2__) { return
// Custom View. Renders the widget model. // Custom View. Renders the widget model.
var BonoboView = widgets.DOMWidgetView.extend({ const BonoboView = widgets.DOMWidgetView.extend({
render: function () { render: function () {
this.value_changed(); this.value_changed();
this.model.on('change:value', this.value_changed, this); this.model.on('change:value', this.value_changed, this);
@ -92,7 +92,9 @@ define(["jupyter-js-widgets"], function(__WEBPACK_EXTERNAL_MODULE_2__) { return
value_changed: function () { value_changed: function () {
this.$el.html( this.$el.html(
this.model.get('value').join('<br>') '<div class="rendered_html"><table style="margin: 0; border: 1px solid black;">' + this.model.get('value').map((key, i) => {
return `<tr><td>${key.status}</td><td>${key.name}</td><td>${key.stats}</td><td>${key.flags}</td></tr>`
}).join('\n') + '</table></div>'
); );
}, },
}); });

File diff suppressed because one or more lines are too long

View File

@ -159,6 +159,14 @@ class NodeExecutionContext(WithStatistics, LoopingExecutionContext):
# self._exec_count += 1 # self._exec_count += 1
pass pass
def as_dict(self):
return {
'status': self.status,
'name': self.name,
'stats': self.get_statistics_as_string(),
'flags': self.get_flags_as_string(),
}
def isflag(param): def isflag(param):
return isinstance(param, Token) and param in (NOT_MODIFIED, ) return isinstance(param, Token) and param in (NOT_MODIFIED, )

View File

@ -8,6 +8,7 @@ from bonobo.constants import BEGIN, END
from bonobo.execution.strategies.base import Strategy from bonobo.execution.strategies.base import Strategy
from bonobo.util import get_name from bonobo.util import get_name
logger = logging.getLogger(__name__)
class ExecutorStrategy(Strategy): class ExecutorStrategy(Strategy):
""" """
@ -30,8 +31,7 @@ class ExecutorStrategy(Strategy):
try: try:
context.start(self.get_starter(executor, futures)) context.start(self.get_starter(executor, futures))
except: except:
logging.getLogger(__name__ logger.critical('Exception caught while starting execution context.', exc_info=sys.exc_info())
).warning('KeyboardInterrupt received. Trying to terminate the nodes gracefully.')
while context.alive: while context.alive:
try: try:

View File

@ -1 +0,0 @@
""" Extensions, not required. """

View File

@ -1,10 +0,0 @@
from .plugin import JupyterOutputPlugin
def _jupyter_nbextension_paths():
return [{'section': 'notebook', 'src': 'static', 'dest': 'bonobo-jupyter', 'require': 'bonobo-jupyter/extension'}]
__all__ = [
'JupyterOutputPlugin',
]

View File

@ -1,19 +0,0 @@
Bonobo integration in Jupyter
Package Install
---------------
**Prerequisites**
- [node](http://nodejs.org/)
```bash
npm install --save bonobo-jupyter
```
Watch mode (for development)
----------------------------
```bash
./node_modules/.bin/webpack --watch
``

File diff suppressed because one or more lines are too long

View File

@ -1,26 +0,0 @@
import logging
from bonobo.ext.jupyter.widget import BonoboWidget
from bonobo.plugins import Plugin
try:
import IPython.core.display
except ImportError as e:
logging.exception(
'You must install Jupyter to use the bonobo Jupyter extension. Easiest way is to install the '
'optional "jupyter" dependencies with «pip install bonobo[jupyter]», but you can also install a '
'specific version by yourself.'
)
class JupyterOutputPlugin(Plugin):
def initialize(self):
self.widget = BonoboWidget()
IPython.core.display.display(self.widget)
def run(self):
self.widget.value = [
str(self.context.parent[i]) for i in self.context.parent.graph.topologically_sorted_indexes
]
finalize = run

File diff suppressed because one or more lines are too long

View File

@ -3,8 +3,11 @@ class Plugin:
A plugin is an extension to the core behavior of bonobo. If you're writing transformations, you should not need A plugin is an extension to the core behavior of bonobo. If you're writing transformations, you should not need
to use this interface. to use this interface.
For examples, you can read bonobo.ext.console.ConsoleOutputPlugin, or bonobo.ext.jupyter.JupyterOutputPlugin that For examples, you can read bonobo.plugins.console.ConsoleOutputPlugin, or bonobo.plugins.jupyter.JupyterOutputPlugin
respectively permits an interactive output on an ANSI console and a rich output in a jupyter notebook. that respectively permits an interactive output on an ANSI console and a rich output in a jupyter notebook. Note
that you most probably won't instanciate them by yourself at runtime, as it's the default behaviour of bonobo to use
them if your in a compatible context (aka an interactive terminal for the console plugin, or a jupyter notebook for
the notebook plugin.)
Warning: THE PLUGIN API IS PRE-ALPHA AND WILL EVOLVE BEFORE 1.0, DO NOT RELY ON IT BEING STABLE! Warning: THE PLUGIN API IS PRE-ALPHA AND WILL EVOLVE BEFORE 1.0, DO NOT RELY ON IT BEING STABLE!

35
bonobo/plugins/jupyter.py Normal file
View File

@ -0,0 +1,35 @@
import logging
from bonobo.contrib.jupyter.widget import BonoboWidget
from bonobo.execution import events
from bonobo.plugins import Plugin
try:
import IPython.core.display
except ImportError as e:
logging.exception(
'You must install Jupyter to use the bonobo Jupyter extension. Easiest way is to install the '
'optional "jupyter" dependencies with «pip install bonobo[jupyter]», but you can also install a '
'specific version by yourself.'
)
class JupyterOutputPlugin(Plugin):
def register(self, dispatcher):
dispatcher.add_listener(events.START, self.setup)
dispatcher.add_listener(events.TICK, self.tick)
dispatcher.add_listener(events.STOPPED, self.tick)
def unregister(self, dispatcher):
dispatcher.remove_listener(events.STOPPED, self.tick)
dispatcher.remove_listener(events.TICK, self.tick)
dispatcher.remove_listener(events.START, self.setup)
def setup(self, event):
self.widget = BonoboWidget()
IPython.core.display.display(self.widget)
def tick(self, event):
self.widget.value = [
event.context[i].as_dict() for i in event.context.graph.topologically_sorted_indexes
]

View File

@ -1,6 +1,9 @@
import html
import json import json
from copy import copy from copy import copy
from graphviz.dot import Digraph
from bonobo.constants import BEGIN from bonobo.constants import BEGIN
from bonobo.util import get_name from bonobo.util import get_name
@ -112,23 +115,31 @@ class Graph:
self._topologcally_sorted_indexes_cache = tuple(filter(lambda i: type(i) is int, reversed(order))) self._topologcally_sorted_indexes_cache = tuple(filter(lambda i: type(i) is int, reversed(order)))
return self._topologcally_sorted_indexes_cache return self._topologcally_sorted_indexes_cache
@property
def graphviz(self):
try:
return self._graphviz
except AttributeError:
g = Digraph()
g.attr(rankdir='LR')
g.node('BEGIN', shape='point')
for i in self.outputs_of(BEGIN):
g.edge('BEGIN', str(i))
for ix in self.topologically_sorted_indexes:
g.node(str(ix), label=get_name(self[ix]))
for iy in self.outputs_of(ix):
g.edge(str(ix), str(iy))
self._graphviz = g
return self._graphviz
def _repr_dot_(self): def _repr_dot_(self):
src = [ return str(self.graphviz)
'digraph {',
' rankdir = LR;',
' "BEGIN" [shape="point"];',
]
for i in self.outputs_of(BEGIN): def _repr_svg_(self):
src.append(' "BEGIN" -> ' + _get_graphviz_node_id(self, i) + ';') return self.graphviz._repr_svg_()
for ix in self.topologically_sorted_indexes: def _repr_html_(self):
for iy in self.outputs_of(ix): return '<div>{}</div><pre>{}</pre>'.format(self.graphviz._repr_svg_(), html.escape(repr(self)))
src.append(' {} -> {};'.format(_get_graphviz_node_id(self, ix), _get_graphviz_node_id(self, iy)))
src.append('}')
return '\n'.join(src)
def _resolve_index(self, mixed): def _resolve_index(self, mixed):
""" Find the index based on various strategies for a node, probably an input or output of chain. Supported inputs are indexes, node values or names. """ Find the index based on various strategies for a node, probably an input or output of chain. Supported inputs are indexes, node values or names.

View File

@ -1,7 +1,9 @@
<a href="{{ pathto(master_doc) }}" style="border: none"> <a href="{{ pathto(master_doc) }}" style="border: none">
<h1 style="text-align: center; margin: 0;"> <h1 style="text-align: center; margin: 0;">
<img class="logo" src="{{ pathto('_static/bonobo.png', 1) }}" title="Bonobo" style="width: 48px; height: 48px; vertical-align: bottom"/> <img class="logo" src="{{ pathto('_static/bonobo.png', 1) }}" title="Bonobo" style="width: 48px; height: 48px; vertical-align: bottom"/>
Bonobo <span class="brand">
Bonobo
</span>
</h1> </h1>
</a> </a>

View File

@ -193,5 +193,5 @@ rst_epilog = """
.. |longversion| replace:: v.{version} .. |longversion| replace:: v.{version}
""".format( """.format(
version = version, version=version,
) )

View File

@ -242,8 +242,8 @@ The console output contains two things.
a call, but the execution will move to the next row. a call, but the execution will move to the next row.
Moving forward Wrap up
:::::::::::::: :::::::
That's all for this first step. That's all for this first step.

View File

@ -1,18 +1,18 @@
-e .[dev] -e .[dev]
alabaster==0.7.10 alabaster==0.7.10
babel==2.5.1 babel==2.5.1
certifi==2017.7.27.1 certifi==2017.11.5
chardet==3.0.4 chardet==3.0.4
coverage==4.4.1 coverage==4.4.2
docutils==0.14 docutils==0.14
idna==2.6 idna==2.6
imagesize==0.7.1 imagesize==0.7.1
jinja2==2.9.6 jinja2==2.10
markupsafe==1.0 markupsafe==1.0
py==1.4.34 py==1.4.34
pygments==2.2.0 pygments==2.2.0
pytest-cov==2.5.1 pytest-cov==2.5.1
pytest-sugar==0.8.0 pytest-sugar==0.9.0
pytest-timeout==1.2.0 pytest-timeout==1.2.0
pytest==3.2.3 pytest==3.2.3
pytz==2017.3 pytz==2017.3

View File

@ -1,16 +1,16 @@
-e .[docker] -e .[docker]
appdirs==1.4.3 appdirs==1.4.3
bonobo-docker==0.5.0 bonobo-docker==0.5.0
certifi==2017.7.27.1 certifi==2017.11.5
chardet==3.0.4 chardet==3.0.4
colorama==0.3.9 colorama==0.3.9
docker-pycreds==0.2.1 docker-pycreds==0.2.1
docker==2.3.0 docker==2.3.0
fs==2.0.12 fs==2.0.16
idna==2.6 idna==2.6
packaging==16.8 packaging==16.8
pbr==3.1.1 pbr==3.1.1
psutil==5.4.0 psutil==5.4.1
pyparsing==2.2.0 pyparsing==2.2.0
pytz==2017.3 pytz==2017.3
requests==2.18.4 requests==2.18.4

View File

@ -3,32 +3,32 @@ appnope==0.1.0
bleach==2.1.1 bleach==2.1.1
decorator==4.1.2 decorator==4.1.2
entrypoints==0.2.3 entrypoints==0.2.3
html5lib==0.999999999 html5lib==1.0b10
ipykernel==4.6.1 ipykernel==4.6.1
ipython-genutils==0.2.0 ipython-genutils==0.2.0
ipython==6.2.1 ipython==6.2.1
ipywidgets==6.0.1 ipywidgets==6.0.1
jedi==0.11.0 jedi==0.11.0
jinja2==2.9.6 jinja2==2.10
jsonschema==2.6.0 jsonschema==2.6.0
jupyter-client==5.1.0 jupyter-client==5.1.0
jupyter-console==5.2.0 jupyter-console==5.2.0
jupyter-core==4.4.0 jupyter-core==4.4.0
jupyter==1.0.0 jupyter==1.0.0
markupsafe==1.0 markupsafe==1.0
mistune==0.8 mistune==0.8.1
nbconvert==5.3.1 nbconvert==5.3.1
nbformat==4.4.0 nbformat==4.4.0
notebook==5.2.1 notebook==5.2.1
pandocfilters==1.4.2 pandocfilters==1.4.2
parso==0.1.0 parso==0.1.0
pexpect==4.2.1 pexpect==4.3.0
pickleshare==0.7.4 pickleshare==0.7.4
prompt-toolkit==1.0.15 prompt-toolkit==1.0.15
ptyprocess==0.5.2 ptyprocess==0.5.2
pygments==2.2.0 pygments==2.2.0
python-dateutil==2.6.1 python-dateutil==2.6.1
pyzmq==16.0.3 pyzmq==17.0.0b3
qtconsole==4.3.1 qtconsole==4.3.1
simplegeneric==0.8.1 simplegeneric==0.8.1
six==1.11.0 six==1.11.0

View File

@ -1,14 +1,14 @@
-e .[sqlalchemy] -e .[sqlalchemy]
appdirs==1.4.3 appdirs==1.4.3
bonobo-sqlalchemy==0.5.1 bonobo-sqlalchemy==0.5.1
certifi==2017.7.27.1 certifi==2017.11.5
chardet==3.0.4 chardet==3.0.4
colorama==0.3.9 colorama==0.3.9
fs==2.0.12 fs==2.0.16
idna==2.6 idna==2.6
packaging==16.8 packaging==16.8
pbr==3.1.1 pbr==3.1.1
psutil==5.4.0 psutil==5.4.1
pyparsing==2.2.0 pyparsing==2.2.0
pytz==2017.3 pytz==2017.3
requests==2.18.4 requests==2.18.4

View File

@ -1,16 +1,17 @@
-e . -e .
appdirs==1.4.3 appdirs==1.4.3
certifi==2017.7.27.1 certifi==2017.11.5
chardet==3.0.4 chardet==3.0.4
colorama==0.3.9 colorama==0.3.9
fs==2.0.12 fs==2.0.16
graphviz==0.8.1
idna==2.6 idna==2.6
jinja2==2.9.6 jinja2==2.10
markupsafe==1.0 markupsafe==1.0
mondrian==0.4.0 mondrian==0.4.0
packaging==16.8 packaging==16.8
pbr==3.1.1 pbr==3.1.1
psutil==5.4.0 psutil==5.4.1
pyparsing==2.2.0 pyparsing==2.2.0
pytz==2017.3 pytz==2017.3
requests==2.18.4 requests==2.18.4

View File

@ -43,6 +43,14 @@ else:
setup( setup(
author='Romain Dorgueil', author='Romain Dorgueil',
author_email='romain@dorgueil.net', author_email='romain@dorgueil.net',
data_files=[
(
'share/jupyter/nbextensions/bonobo-jupyter', [
'bonobo/contrib/jupyter/static/extension.js', 'bonobo/contrib/jupyter/static/index.js',
'bonobo/contrib/jupyter/static/index.js.map'
]
)
],
description=('Bonobo, a simple, modern and atomic extract-transform-load toolkit for ' description=('Bonobo, a simple, modern and atomic extract-transform-load toolkit for '
'python 3.5+.'), 'python 3.5+.'),
license='Apache License, Version 2.0', license='Apache License, Version 2.0',
@ -53,14 +61,14 @@ setup(
packages=find_packages(exclude=['ez_setup', 'example', 'test']), packages=find_packages(exclude=['ez_setup', 'example', 'test']),
include_package_data=True, include_package_data=True,
install_requires=[ install_requires=[
'colorama (>= 0.3)', 'fs (>= 2.0, < 2.1)', 'jinja2 (>= 2.9, < 2.10)', 'mondrian (>= 0.4, < 0.5)', 'colorama (>= 0.3)', 'fs (>= 2.0, < 2.1)', 'graphviz (>= 0.8, < 0.9)', 'jinja2 (>= 2.9, < 3)',
'packaging (>= 16, < 17)', 'psutil (>= 5.4, < 6.0)', 'requests (>= 2.0, < 3.0)', 'stevedore (>= 1.27, < 1.28)', 'mondrian (>= 0.4, < 0.5)', 'packaging (>= 16, < 17)', 'psutil (>= 5.4, < 6)', 'requests (>= 2, < 3)',
'whistle (>= 1.0, < 1.1)' 'stevedore (>= 1.27, < 1.28)', 'whistle (>= 1.0, < 1.1)'
], ],
extras_require={ extras_require={
'dev': [ 'dev': [
'coverage (>= 4.4, < 5.0)', 'pytest (>= 3.1, < 4.0)', 'pytest-cov (>= 2.5, < 3.0)', 'coverage (>= 4.4, < 5.0)', 'pytest (>= 3.1, < 4.0)', 'pytest-cov (>= 2.5, < 3.0)',
'pytest-sugar (>= 0.8, < 0.9)', 'pytest-timeout (>= 1, < 2)', 'sphinx (>= 1.6, < 2.0)', 'yapf' 'pytest-sugar (>= 0.9, < 0.10)', 'pytest-timeout (>= 1, < 2)', 'sphinx (>= 1.6, < 2.0)', 'yapf'
], ],
'docker': ['bonobo-docker (>= 0.5.0)'], 'docker': ['bonobo-docker (>= 0.5.0)'],
'jupyter': ['ipywidgets (>= 6.0.0, < 7)', 'jupyter (>= 1.0, < 1.1)'], 'jupyter': ['ipywidgets (>= 6.0.0, < 7)', 'jupyter (>= 1.0, < 1.1)'],

View File

@ -6,8 +6,9 @@ from bonobo.util.environ import change_working_directory
from bonobo.util.testing import all_runners from bonobo.util.testing import all_runners
@pytest.mark.skipif(sys.version_info < (3, 6), @pytest.mark.skipif(
reason="python 3.5 does not preserve kwargs order and this cant pass for now") sys.version_info < (3, 6), reason="python 3.5 does not preserve kwargs order and this cant pass for now"
)
@all_runners @all_runners
def test_convert(runner, tmpdir): def test_convert(runner, tmpdir):
csv_content = 'id;name\n1;Romain' csv_content = 'id;name\n1;Romain'

View File

@ -1,6 +1,6 @@
from unittest.mock import patch from unittest.mock import patch
from bonobo.ext.opendatasoft import OpenDataSoftAPI from bonobo.contrib.opendatasoft import OpenDataSoftAPI
from bonobo.util.objects import ValueHolder from bonobo.util.objects import ValueHolder