Skip to content

Commit 5b29b5f

Browse files
committed
Merge branch 'services_init' into 17_positional_options
Conflicts: .coveragerc
2 parents 159389e + bbd258c commit 5b29b5f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+487
-289
lines changed

.codacy.yml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
exclude_paths:
3+
- bonobo/examples/
4+
- bonobo/ext/

.coveragerc

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
branch = True
33
omit =
44
bonobo/examples/**
5+
bonobo/ext/**
56

67
[report]
78
# Regexes for lines to exclude from consideration

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
/.idea
2626
/.release
2727
/bonobo.iml
28+
/bonobo/examples/work_in_progress/
2829
/bonobo/ext/jupyter/js/node_modules/
2930
/build/
3031
/coverage.xml

Makefile

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# This file has been auto-generated.
22
# All changes will be lost, see Projectfile.
33
#
4-
# Updated at 2017-04-30 10:12:39.793759
4+
# Updated at 2017-05-01 08:35:15.162008
55

66
PYTHON ?= $(shell which python)
77
PYTHON_BASENAME ?= $(shell basename $(PYTHON))
@@ -10,6 +10,7 @@ PYTHON_REQUIREMENTS_DEV_FILE ?= requirements-dev.txt
1010
QUICK ?=
1111
VIRTUAL_ENV ?= .virtualenv-$(PYTHON_BASENAME)
1212
PIP ?= $(VIRTUAL_ENV)/bin/pip
13+
PIP_INSTALL_OPTIONS ?=
1314
PYTEST ?= $(VIRTUAL_ENV)/bin/pytest
1415
PYTEST_OPTIONS ?= --capture=no --cov=bonobo --cov-report html
1516
SPHINX_OPTS ?=
@@ -24,13 +25,13 @@ YAPF_OPTIONS ?= -rip
2425
# Installs the local project dependencies.
2526
install: $(VIRTUAL_ENV)
2627
if [ -z "$(QUICK)" ]; then \
27-
$(PIP) install -U pip wheel -r $(PYTHON_REQUIREMENTS_FILE) ; \
28+
$(PIP) install -U pip wheel $(PIP_INSTALL_OPTIONS) -r $(PYTHON_REQUIREMENTS_FILE) ; \
2829
fi
2930

3031
# Installs the local project dependencies, including development-only libraries.
3132
install-dev: $(VIRTUAL_ENV)
3233
if [ -z "$(QUICK)" ]; then \
33-
$(PIP) install -U pip wheel -r $(PYTHON_REQUIREMENTS_DEV_FILE) ; \
34+
$(PIP) install -U pip wheel $(PIP_INSTALL_OPTIONS) -r $(PYTHON_REQUIREMENTS_DEV_FILE) ; \
3435
fi
3536

3637
# Cleans up the local mess.

appveyor.yml

+9-7
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ environment:
2424
PYTHON_VERSION: "3.6.1"
2525
PYTHON_ARCH: "64"
2626

27+
build: false
28+
2729
install:
2830
# If there is a newer build queued for the same PR, cancel this one.
2931
# The AppVeyor 'rollout builds' option is supposed to serve the same
@@ -61,18 +63,18 @@ install:
6163
# compiled extensions and are not provided as pre-built wheel packages,
6264
# pip will build them from source using the MSVC compiler matching the
6365
# target Python version and architecture
64-
- "%CMD_IN_ENV% pip install -e ."
66+
- "%CMD_IN_ENV% pip install -e .[dev]"
6567

6668
test_script:
6769
# Run the project tests
6870
- "%CMD_IN_ENV% pytest --capture=no --cov=bonobo --cov-report html"
6971

70-
after_test:
71-
# If tests are successful, create binary packages for the project.
72-
- "%CMD_IN_ENV% python setup.py bdist_wheel"
73-
- "%CMD_IN_ENV% python setup.py bdist_wininst"
74-
- "%CMD_IN_ENV% python setup.py bdist_msi"
75-
- ps: "ls dist"
72+
#after_test:
73+
# If tests are successful, create binary packages for the project.
74+
# - "%CMD_IN_ENV% python setup.py bdist_wheel"
75+
# - "%CMD_IN_ENV% python setup.py bdist_wininst"
76+
# - "%CMD_IN_ENV% python setup.py bdist_msi"
77+
# - ps: "ls dist"
7678

7779
artifacts:
7880
# Archive the generated packages in the ci.appveyor.com build report.

bonobo/__init__.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
assert (sys.version_info >= (3, 5)), 'Python 3.5+ is required to use Bonobo.'
1212
from bonobo._api import *
1313
from bonobo._api import __all__
14+
from bonobo._version import __version__
15+
16+
__all__ = ['__version__'] + __all__
17+
__version__ = __version__
1418

15-
__all__ = __all__
1619
del sys

bonobo/_api.py

+94-52
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,105 @@
1-
from bonobo._version import __version__
2-
3-
__all__ = [
4-
'__version__',
5-
]
1+
import warnings
62

3+
from bonobo.basics import Limit, PrettyPrint, Tee, count, identity, noop, pprint
4+
from bonobo.strategies import create_strategy
75
from bonobo.structs import Bag, Graph
6+
from bonobo.util.objects import get_name
7+
from bonobo.io import CsvReader, CsvWriter, FileReader, FileWriter, JsonReader, JsonWriter
88

9-
__all__ += ['Bag', 'Graph']
9+
__all__ = []
1010

11-
# Filesystem. This is a shortcut from the excellent filesystem2 library, that we make available there for convenience.
12-
from fs import open_fs as _open_fs
1311

14-
open_fs = lambda url, *args, **kwargs: _open_fs(str(url), *args, **kwargs)
15-
__all__ += ['open_fs']
12+
def register_api(x, __all__=__all__):
13+
__all__.append(get_name(x))
14+
return x
1615

17-
# Basic transformations.
18-
from bonobo.basics import *
19-
from bonobo.basics import __all__ as _all_basics
2016

21-
__all__ += _all_basics
17+
def register_api_group(*args):
18+
for attr in args:
19+
register_api(attr)
2220

23-
# Execution strategies.
24-
from bonobo.strategies import create_strategy
2521

26-
__all__ += ['create_strategy']
22+
@register_api
23+
def run(graph, *chain, strategy=None, plugins=None, services=None):
24+
"""
25+
Main entry point of bonobo. It takes a graph and creates all the necessary plumbery around to execute it.
26+
27+
The only necessary argument is a :class:`Graph` instance, containing the logic you actually want to execute.
28+
29+
By default, this graph will be executed using the "threadpool" strategy: each graph node will be wrapped in a
30+
thread, and executed in a loop until there is no more input to this node.
31+
32+
You can provide plugins factory objects in the plugins list, this function will add the necessary plugins for
33+
interactive console execution and jupyter notebook execution if it detects correctly that it runs in this context.
34+
35+
You'll probably want to provide a services dictionary mapping service names to service instances.
36+
37+
:param Graph graph: The :class:`Graph` to execute.
38+
:param str strategy: The :class:`bonobo.strategies.base.Strategy` to use.
39+
:param list plugins: The list of plugins to enhance execution.
40+
:param dict services: The implementations of services this graph will use.
41+
:return bonobo.execution.graph.GraphExecutionContext:
42+
"""
43+
if len(chain):
44+
warnings.warn('DEPRECATED. You should pass a Graph instance instead of a chain.')
45+
from bonobo import Graph
46+
graph = Graph(graph, *chain)
2747

28-
# Extract and loads from stdlib.
29-
from bonobo.io import *
30-
from bonobo.io import __all__ as _all_io
48+
strategy = create_strategy(strategy)
49+
plugins = plugins or []
3150

32-
__all__ += _all_io
51+
if _is_interactive_console():
52+
from bonobo.ext.console import ConsoleOutputPlugin
53+
if ConsoleOutputPlugin not in plugins:
54+
plugins.append(ConsoleOutputPlugin)
3355

56+
if _is_jupyter_notebook():
57+
from bonobo.ext.jupyter import JupyterOutputPlugin
58+
if JupyterOutputPlugin not in plugins:
59+
plugins.append(JupyterOutputPlugin)
3460

35-
# XXX This may be belonging to the bonobo.examples package.
36-
def get_examples_path(*pathsegments):
37-
import os
38-
import pathlib
39-
return str(pathlib.Path(os.path.dirname(__file__), 'examples', *pathsegments))
61+
return strategy.execute(graph, plugins=plugins, services=services)
4062

4163

42-
def open_examples_fs(*pathsegments):
43-
return open_fs(get_examples_path(*pathsegments))
64+
# bonobo.structs
65+
register_api_group(Bag, Graph)
66+
67+
# bonobo.strategies
68+
register_api(create_strategy)
69+
70+
71+
# Shortcut to filesystem2's open_fs, that we make available there for convenience.
72+
@register_api
73+
def open_fs(fs_url, *args, **kwargs):
74+
"""
75+
Wraps :func:`fs.open_fs` function with a few candies.
76+
77+
:param str fs_url: A filesystem URL
78+
:param parse_result: A parsed filesystem URL.
79+
:type parse_result: :class:`ParseResult`
80+
:param bool writeable: True if the filesystem must be writeable.
81+
:param bool create: True if the filesystem should be created if it does not exist.
82+
:param str cwd: The current working directory (generally only relevant for OS filesystems).
83+
:param str default_protocol: The protocol to use if one is not supplied in the FS URL (defaults to ``"osfs"``).
84+
:returns: :class:`~fs.base.FS` object
85+
"""
86+
from fs import open_fs as _open_fs
87+
return _open_fs(str(fs_url), *args, **kwargs)
4488

45-
__all__.append(get_examples_path.__name__)
46-
__all__.append(open_examples_fs.__name__)
89+
90+
# bonobo.basics
91+
register_api_group(
92+
Limit,
93+
PrettyPrint,
94+
Tee,
95+
count,
96+
identity,
97+
noop,
98+
pprint,
99+
)
100+
101+
# bonobo.io
102+
register_api_group(CsvReader, CsvWriter, FileReader, FileWriter, JsonReader, JsonWriter)
47103

48104

49105
def _is_interactive_console():
@@ -58,27 +114,13 @@ def _is_jupyter_notebook():
58114
return False
59115

60116

61-
# @api
62-
def run(graph, *chain, strategy=None, plugins=None, services=None):
63-
if len(chain):
64-
warnings.warn('DEPRECATED. You should pass a Graph instance instead of a chain.')
65-
from bonobo import Graph
66-
graph = Graph(graph, *chain)
67-
68-
strategy = create_strategy(strategy)
69-
plugins = []
70-
71-
if _is_interactive_console():
72-
from bonobo.ext.console import ConsoleOutputPlugin
73-
if ConsoleOutputPlugin not in plugins:
74-
plugins.append(ConsoleOutputPlugin)
75-
76-
if _is_jupyter_notebook():
77-
from bonobo.ext.jupyter import JupyterOutputPlugin
78-
if JupyterOutputPlugin not in plugins:
79-
plugins.append(JupyterOutputPlugin)
80-
81-
return strategy.execute(graph, plugins=plugins, services=services)
117+
@register_api
118+
def get_examples_path(*pathsegments):
119+
import os
120+
import pathlib
121+
return str(pathlib.Path(os.path.dirname(__file__), 'examples', *pathsegments))
82122

83123

84-
__all__.append(run.__name__)
124+
@register_api
125+
def open_examples_fs(*pathsegments):
126+
return open_fs(get_examples_path(*pathsegments))

bonobo/basics.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from colorama import Fore, Style
55

66
from bonobo.config.processors import contextual
7-
from bonobo.constants import NOT_MODIFIED
87
from bonobo.structs.bags import Bag
98
from bonobo.util.objects import ValueHolder
109
from bonobo.util.term import CLEAR_EOL
@@ -25,6 +24,7 @@ def identity(x):
2524

2625

2726
def Limit(n=10):
27+
from bonobo.constants import NOT_MODIFIED
2828
i = 0
2929

3030
def _limit(*args, **kwargs):
@@ -38,6 +38,8 @@ def _limit(*args, **kwargs):
3838

3939

4040
def Tee(f):
41+
from bonobo.constants import NOT_MODIFIED
42+
4143
@functools.wraps(f)
4244
def wrapped(*args, **kwargs):
4345
nonlocal f
@@ -63,6 +65,8 @@ def _count_counter(self, context):
6365

6466

6567
def PrettyPrint(title_keys=('title', 'name', 'id'), print_values=True, sort=True):
68+
from bonobo.constants import NOT_MODIFIED
69+
6670
def _pprint(*args, **kwargs):
6771
nonlocal title_keys, sort, print_values
6872

@@ -98,4 +102,5 @@ def _pprint(*args, **kwargs):
98102

99103

100104
def noop(*args, **kwargs): # pylint: disable=unused-argument
105+
from bonobo.constants import NOT_MODIFIED
101106
return NOT_MODIFIED

bonobo/commands/init.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@
33

44
def execute():
55
try:
6-
import edgy.project
6+
from edgy.project.__main__ import handle_init
77
except ImportError as exc:
88
raise ImportError(
99
'You must install "edgy.project" to use this command.\n\n $ pip install edgy.project\n'
1010
) from exc
1111

12-
from edgy.project.__main__ import handle_init
13-
1412
return handle_init(os.path.join(os.getcwd(), 'Projectfile'))
1513

1614

bonobo/commands/run.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def get_default_services(filename, services=None):
2020
}
2121
try:
2222
exec(code, context)
23-
except Exception as exc:
23+
except Exception:
2424
raise
2525
return {
2626
**context[DEFAULT_SERVICES_ATTR](),
@@ -55,7 +55,7 @@ def execute(file, quiet=False):
5555
'but it is something that will be implemented in the future.\n\nExpected: 1, got: {}.'
5656
).format(len(graphs))
5757

58-
name, graph = list(graphs.items())[0]
58+
graph = list(graphs.values())[0]
5959

6060
# todo if console and not quiet, then add the console plugin
6161
# todo when better console plugin, add it if console and just disable display

bonobo/config/configurables.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,4 @@ def __init__(self, *args, **kwargs):
8383
)
8484

8585
for name, value in kwargs.items():
86-
setattr(self, name, kwargs[name])
86+
setattr(self, name, value)

bonobo/config/processors.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ def contextual(cls_or_func):
5252
setattr(cls_or_func, _CONTEXT_PROCESSORS_ATTR, [])
5353

5454
_processors = getattr(cls_or_func, _CONTEXT_PROCESSORS_ATTR)
55-
for name, value in cls_or_func.__dict__.items():
56-
if isinstance(value, ContextProcessor):
57-
_processors.append(value)
55+
for processor in cls_or_func.__dict__.values():
56+
if isinstance(processor, ContextProcessor):
57+
_processors.append(processor)
5858

5959
# This is needed for python 3.5, python 3.6 should be fine, but it's considered an implementation detail.
6060
_processors.sort(key=lambda proc: proc._creation_counter)

bonobo/examples/.style.yapf

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[style]
2+
based_on_style = pep8
3+
column_limit = 74
4+
dedent_closing_brackets = true

bonobo/examples/datasets/coffeeshops.py

+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
"""
2+
Extracts a list of parisian bars where you can buy a coffee for a reasonable price, and store them in a flat text file.
3+
4+
.. graphviz::
5+
6+
digraph {
7+
rankdir = LR;
8+
stylesheet = "../_static/graphs.css";
9+
10+
BEGIN [shape="point"];
11+
BEGIN -> "ODS()" -> "transform" -> "FileWriter()";
12+
}
13+
14+
"""
15+
116
import bonobo
217
from bonobo.commands.run import get_default_services
318
from bonobo.ext.opendatasoft import OpenDataSoftAPI

0 commit comments

Comments
 (0)