Skip to content

Commit 8942475

Browse files
authored
Merge pull request #8 from arduino/msgpackrpc_api_update
lib/msgpackrpc: Require a name when binding callables.
2 parents 277efd5 + 932c256 commit 8942475

File tree

2 files changed

+55
-26
lines changed

2 files changed

+55
-26
lines changed

lib/msgpackrpc/example.py

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,38 @@
88
import gc
99

1010

11-
class Adder:
12-
def __init__(self):
13-
pass
14-
15-
def add(self, a, b):
16-
logging.info(f"add({a}, {b}) is called")
17-
return a + b
11+
def add(a, b):
12+
logging.info(f"add({a}, {b}) is called")
13+
return a + b
1814

1915

2016
def sub(a, b):
2117
logging.info(f"sub({a}, {b}) is called")
2218
return a - b
2319

2420

21+
class Foo:
22+
def __init__(self, name):
23+
self.name = name
24+
25+
def add(self, a, b):
26+
logging.info(f"{self.name}.add({a}, {b}) is called")
27+
return a + b
28+
29+
def sub(self, a, b):
30+
logging.info(f"{self.name}.sub({a}, {b}) is called")
31+
return a - b
32+
33+
34+
class Adder:
35+
def __init__(self):
36+
pass
37+
38+
def __call__(self, a, b):
39+
logging.info(f"Adder({a}, {b}) is called")
40+
return a + b
41+
42+
2543
if __name__ == "__main__":
2644
# Configure the logger.
2745
# All message equal to or higher than the logger level are printed.
@@ -34,9 +52,19 @@ def sub(a, b):
3452
# Create an RPC object
3553
rpc = msgpackrpc.MsgPackRPC()
3654

37-
# Register objects or functions to be called by the remote processor.
38-
rpc.bind(Adder())
39-
rpc.bind(sub)
55+
# Register remote functions.
56+
rpc.bind("sub", sub)
57+
rpc.bind("add", add)
58+
59+
# Register a callable object.
60+
rpc.bind("adder", Adder())
61+
62+
# Register full objects. The following binds all public methods of an object to their
63+
# respective qualified names. For instance, `foo1`'s methods will be bound to `foo1.add`
64+
# and `foo1.sub`. Alternatively, bound methods can be registered individually, by calling
65+
# bind on each method. For example, `rpc.bind("foo.add", foo.add)`.
66+
rpc.bind("foo1", Foo("foo1"))
67+
rpc.bind("foo2", Foo("foo2"))
4068

4169
# Start the remote processor and wait for it to be ready to communicate.
4270
rpc.start(firmware=0x08180000, timeout=1000, num_channels=2)

lib/msgpackrpc/msgpackrpc.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def __init__(self, streaming=False):
9898
self.msgid = 0
9999
self.msgbuf = {}
100100
self.msgio = MsgPackIO() if streaming else None
101-
self.servers = []
101+
self.callables = {}
102102

103103
def _bind_callback(self, src, name):
104104
if log_level_enabled(logging.INFO):
@@ -135,30 +135,31 @@ def _send_msg(self, msgid, msgtype, fname, fargs, **kwargs):
135135
return Future(msgid, self.msgbuf, fname, fargs)
136136

137137
def _dispatch(self, msgid, fname, fargs):
138-
func = None
139138
retobj = None
140139
error = None
141-
for obj in self.servers:
142-
if callable(obj) and obj.__name__ == fname:
143-
func = obj
144-
elif hasattr(obj, fname):
145-
func = getattr(obj, fname)
146-
if func is not None:
147-
break
148-
149-
if func is not None:
150-
retobj = func(*fargs)
140+
141+
if fname in self.callables:
142+
retobj = self.callables[fname](*fargs)
151143
else:
152144
error = "Unbound function called %s" % (fname)
153145

154146
self._send_msg(msgid, _MSG_TYPE_RESPONSE, error, retobj)
155147

156-
def bind(self, obj):
148+
def bind(self, name, obj):
157149
"""
158-
Register an object or a function to be called by the remote processor.
159-
obj: An object whose methods can be called by remote processors, or a function.
150+
Bind a callable or an object to a name.
151+
name: The name to which the callable or object is bound.
152+
obj: A callable or an object to bind to the name. If an object is passed, all of its
153+
public methods will be bound to their respective qualified names.
160154
"""
161-
self.servers.append(obj)
155+
if callable(obj):
156+
# Bind a single callable to its name.
157+
self.callables[name] = obj
158+
else:
159+
# Bind all public methods of an object to their respective qualified names.
160+
for k, v in obj.__class__.__dict__.items():
161+
if callable(v) and not k.startswith("_"):
162+
self.callables[name + "." + k] = getattr(obj, k)
162163

163164
def start(self, firmware=None, num_channels=2, timeout=3000):
164165
"""

0 commit comments

Comments
 (0)