##// END OF EJS Templates
support non-modules in @require...
MinRK -
Show More
@@ -5,18 +5,21 b' Authors:'
5 * Min RK
5 * Min RK
6 """
6 """
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2010-2011 The IPython Development Team
8 # Copyright (C) 2013 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 import sys
15
14 from types import ModuleType
16 from types import ModuleType
15
17
16 from IPython.parallel.client.asyncresult import AsyncResult
18 from IPython.parallel.client.asyncresult import AsyncResult
17 from IPython.parallel.error import UnmetDependency
19 from IPython.parallel.error import UnmetDependency
18 from IPython.parallel.util import interactive
20 from IPython.parallel.util import interactive
19 from IPython.utils import py3compat
21 from IPython.utils import py3compat
22 from IPython.utils.pickleutil import can, uncan
20
23
21 class depend(object):
24 class depend(object):
22 """Dependency decorator, for use with tasks.
25 """Dependency decorator, for use with tasks.
@@ -60,8 +63,9 b' class dependent(object):'
60 self.dkwargs = dkwargs
63 self.dkwargs = dkwargs
61
64
62 def __call__(self, *args, **kwargs):
65 def __call__(self, *args, **kwargs):
63 # if hasattr(self.f, 'func_globals') and hasattr(self.df, 'func_globals'):
66 user_ns = sys.modules['__main__'].__dict__
64 # self.df.func_globals = self.f.func_globals
67 for key, value in self.dkwargs.items():
68 self.dkwargs[key] = uncan(value, user_ns)
65 if self.df(*self.dargs, **self.dkwargs) is False:
69 if self.df(*self.dargs, **self.dkwargs) is False:
66 raise UnmetDependency()
70 raise UnmetDependency()
67 return self.f(*args, **kwargs)
71 return self.f(*args, **kwargs)
@@ -72,41 +76,62 b' class dependent(object):'
72 return self.func_name
76 return self.func_name
73
77
74 @interactive
78 @interactive
75 def _require(*names):
79 def _require(*modules, **mapping):
76 """Helper for @require decorator."""
80 """Helper for @require decorator."""
77 from IPython.parallel.error import UnmetDependency
81 from IPython.parallel.error import UnmetDependency
82 from IPython.utils.pickleutil import uncan
78 user_ns = globals()
83 user_ns = globals()
79 for name in names:
84 for name in modules:
80 if name in user_ns:
81 continue
82 try:
85 try:
83 exec 'import %s'%name in user_ns
86 exec 'import %s' % name in user_ns
84 except ImportError:
87 except ImportError:
85 raise UnmetDependency(name)
88 raise UnmetDependency(name)
89
90 for name, cobj in mapping.items():
91 user_ns[name] = uncan(cobj, user_ns)
86 return True
92 return True
87
93
88 def require(*mods):
94 def require(*objects, **mapping):
89 """Simple decorator for requiring names to be importable.
95 """Simple decorator for requiring local objects and modules to be available
96 when the decorated function is called on the engine.
97
98 Modules specified by name or passed directly will be imported
99 prior to calling the decorated function.
100
101 Objects other than modules will be pushed as a part of the task.
102 Functions can be passed positionally,
103 and will be pushed to the engine with their __name__.
104 Other objects can be passed by keyword arg.
90
105
91 Examples
106 Examples
92 --------
107 --------
93
108
94 In [1]: @require('numpy')
109 In [1]: @require('numpy')
95 ...: def norm(a):
110 ...: def norm(a):
96 ...: import numpy
97 ...: return numpy.linalg.norm(a,2)
111 ...: return numpy.linalg.norm(a,2)
112
113 In [2]: foo = lambda x: x*x
114 In [3]: @require(foo)
115 ...: def bar(a):
116 ...: return foo(1-a)
98 """
117 """
99 names = []
118 names = []
100 for mod in mods:
119 for obj in objects:
101 if isinstance(mod, ModuleType):
120 if isinstance(obj, ModuleType):
102 mod = mod.__name__
121 obj = obj.__name__
103
122
104 if isinstance(mod, basestring):
123 if isinstance(obj, basestring):
105 names.append(mod)
124 names.append(obj)
125 elif hasattr(obj, '__name__'):
126 mapping[obj.__name__] = obj
106 else:
127 else:
107 raise TypeError("names must be modules or module names, not %s"%type(mod))
128 raise TypeError("Objects other than modules and functions "
129 "must be passed by kwarg, but got: %s" % type(obj)
130 )
108
131
109 return depend(_require, *names)
132 for name, obj in mapping.items():
133 mapping[name] = can(obj)
134 return depend(_require, *names, **mapping)
110
135
111 class Dependency(set):
136 class Dependency(set):
112 """An object for representing a set of msg_id dependencies.
137 """An object for representing a set of msg_id dependencies.
General Comments 0
You need to be logged in to leave comments. Login now