-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathgateways.py
More file actions
123 lines (103 loc) · 4.26 KB
/
gateways.py
File metadata and controls
123 lines (103 loc) · 4.26 KB
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
114
115
116
117
118
119
120
121
122
123
'''
Create namespace convenience methods for all discovered ops.
Assumes we're running in an environment with scyjava configured to have a classpath with some SciJava Ops implementations (i.e. org.scijava:scijava-ops-engine plus implementations)
Classes:
OpNamespace
OpGateway
Variables:
env - OpEnvironment used to populate the OpGateway and OpNamespaces
ops - OpGateway entry point
'''
from scyjava import jimport
from types import MethodType
OpEnvironment = jimport('org.scijava.ops.api.OpEnvironment')
env = OpEnvironment.build()
op_names={str(name) for info in env.infos() for name in info.names()}
class OpNamespace:
'''
Represents intermediate ops categories. For example, "math.add" and "math.sub" are in both in the "math" namespace.
'''
def __init__(self, env, ns):
self.env = env
self.ns = ns
def help(self, op_name=None):
'''
Convenience wrapper for OpEnvironment.help(), for information about available ops. Prints all returned information, line-by-line.
'''
print(*self.env.help(op_name), sep = "\n")
class OpGateway(OpNamespace):
'''
Global base specialization of OpNamespace. Contains all other namespaces, in addition to all ops in the "global" namespace.
'''
def __init__(self, env):
super().__init__(env, 'global')
def nary(env, fqop, arity):
'''
Helper method to convert a numerical arity to the corresponding OpEnvironment method
Parameters:
env (OpEnvironment): the environment being used
fqop (str): the fully-qualified op name
arity (int): the desired arity of the op
Returns:
The appropriate OpBuilder.Arity instance for invoking the given op with the indicated number of parameters
'''
arities=[env.op, env.op, env.op, env.op, env.op, env.op, env.op, env.op, env.op, env.op, env.op, env.arity11, env.arity12, env.arity13, env.arity14, env.arity15, env.arity16]
return arities[arity](fqop)
def add_op(c, op_name):
'''
Helper method patch in a given op name as its corresponding function call within the given class
Parameters:
c (class): the OpNamespace/OpGateway to add a new function with the given op_name that calls the op
op_name (str): the actual name of the op we're adding
'''
if hasattr(c, op_name):
return
def f(self, *args, **kwargs):
'''
Instance method to attach to our OpNamespace/OpGateway that does the actual op call
'''
fqop = op_name if self.ns == 'global' else self.ns + "." + op_name
run = kwargs.get('run', True)
b = nary(self.env, fqop, len(args)).input(*args)
# inplace
# ops.filter.gauss(image, 5, inplace=0)
if (inplace:=kwargs.get('inplace', None)) is not None:
return b.mutate(inplace) if run else b.inplace(inplace)
# computer
# ops.filter.gauss(image, 5, out=result)
if (out:=kwargs.get('out', None)) is not None:
b=b.output(out)
return b.compute() if run else b.computer()
# function
# gauss_op = ops.filter.gauss(image, 5)
# result = ops.filter.gauss(image, 5)
return b.apply() if run else b.function()
if c == OpGateway:
# op_name is a global.
setattr(c, op_name, f)
else:
m=MethodType(f, c)
setattr(c, op_name, m)
def add_namespace(c, ns, op_name):
'''
Helper method to add an op call with nested OpNamespace instances if needed
Parameters:
c (class): the OpNamespace/OpGateway to add the given op and namespace
ns(str): the namespace to nest the given op within
op_name (str): the actual name of the op we're adding
'''
if not hasattr(c, ns):
setattr(c, ns, OpNamespace(env, ns))
add_op(getattr(c, ns), op_name)
# Entry point to do the namespace population.
# This modifies the OpGateway class to add a call for each op, with intermediate accessors by namespace
for op in op_names:
dot = op.find('.')
if dot >= 0:
ns=op[:dot]
op_name=op[dot+1:]
add_namespace(OpGateway, ns, op_name)
else:
add_op(OpGateway, op)
# Make an instance of our modified OpGateway class as a global for external use
ops = OpGateway(env)