/
__init__.py
113 lines (92 loc) · 2.92 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# vim: tabstop=4 softtabstop=4 shiftwidth=4 textwidth=80 smarttab expandtab
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
'''
Built-in applications
'''
from .. import utils, marks
from collections import OrderedDict
import itertools
import operator
# registry
_apps = OrderedDict()
def app(*args, **kwargs):
'''Decorator to register switchy application classes.
Example usage:
@app
class CoolAppController(object):
pass
This will register the class as a switchy app.
The name of the app defaults to `class.__name__`.
The help for the app is taken from `class.__doc__`.
You can also provide an alternative name via a
decorator argument:
@app('CoolName')
class CoolAppController(object):
pass
or with a keyword arg:
@app(name='CoolName')
class CoolAppController(object):
pass
'''
name = kwargs.get('name')
if len(args) >= 1:
arg0 = args[0]
if type(arg0) is type:
return register(arg0, None)
name = arg0
# if len(args) > 1:
# tail = args[1:]
def inner(cls):
return register(cls, name=name)
return inner
def register(cls, name=None):
"""Register an app in the global registry
"""
if not marks.has_callbacks(cls):
raise ValueError(
"{} contains no defined handlers or callbacks?".format(cls)
)
app = _apps.setdefault(name or cls.__name__, cls)
if cls is not app:
raise ValueError("An app '{}' already exists with name '{}'"
.format(app, name))
return cls
def iterapps():
"""Iterable over all registered apps.
"""
return itertools.chain(_apps.values())
def groupbymod():
"""Return an iterable which delivers tuples (<modulename>, <apps_subiter>)
"""
return itertools.groupby(
_apps.items(),
utils.compose(
operator.attrgetter('__module__'),
operator.itemgetter(1)
)
)
def get(name):
"""Get a registered app by name or None if one isn't registered.
"""
return _apps.get(name)
def load(packages=(), imp_excs=('numpy',)):
"""Load by importing all built-in apps along with any apps found in the
provided `packages` list.
:param packages: package (names or actual modules)
:type package: str | module
:rtype: dict[str, types.ModuleType]
"""
apps_map = {}
# load built-ins + extras
for path, app in utils.iter_import_submods(
(__name__,) + packages,
imp_excs=imp_excs,
):
if isinstance(app, ImportError):
utils.log_to_stderr().warn("'{}' failed to load - {}\n".format(
path, app.message))
else:
apps_map[path] = app
return apps_map