Gedis
Gedis is a RPC framework that provide automatic generation of client side code at runtime. Which means you only need to define the server interface and the client will automatically receive the code it needs to talk to the server at connection time.
Gedis Actor
The Gedis
actors should inherts from the BaseActor
class and all function should define the type annotations of its parameters
from jumpscale.servers.gedis.baseactor import BaseActor
class Example(BaseActor):
def add_two_ints(self, x: int, y: int) -> int:
"""Adds two ints
Arguments:
x {int} -- first int
y {int} -- second int
Returns:
int -- the sum of the two ints
"""
return x + y
def concate_two_strings(self, x: str, y: str) -> str:
"""Concate two strings
Arguments:
x {str} -- first string
y {str} -- second string
Returns:
str -- the concate of the two strings
"""
return x + y
Actor = Example
Starting the server and loading actors
JS-NG> server = j.servers.gedis.get("main")
JS-NG> server.actor_add("example", "/sandbox/code/github/threefoldtech/js-ng/jumpscale/servers/gedis/example_actor.py")
JS-NG> server.start()
Getting a client and calling actors
JS-NG> cl = j.clients.gedis.get("main")
JS-NG> cl.actors.example.add_two_ints(1, 2)
3
in case the actor method is missing the type annotation of one of its parameters, the server will return an error for example
jumpscale.core.exceptions.exceptions.Runtime: argument x in method add_two_ints doesn't have type annotation
Type annotations and Actors
We make use of type annotations for many things in gedis framework, including types and parameters validations, self documenting actors
Here is an example actor
from jumpscale.servers.gedis.baseactor import BaseActor
from typing import Sequence
from jumpscale.loader import j
import inspect, sys
class TestObject:
def __init__(self):
self.attr = None
def to_dict(self):
return self.__dict__
def from_dict(self, ddict):
self.__dict__ = ddict
class Example(BaseActor):
def add_two_ints(self, x: int, y: int) -> int:
"""Adds two ints
Arguments:
x {int} -- first int
y {int} -- second int
Returns:
int -- the sum of the two ints
"""
return x + y
def concate_two_strings(self, x: str, y: str) -> str:
"""Concate two strings
Arguments:
x {str} -- first string
y {str} -- second string
Returns:
str -- the concate of the two strings
"""
return x + y
def get_testobject(self, myobj: TestObject, new_value: int) -> TestObject:
"""returns an object of type Test object with update attribute attr to `new_value`
Arguments:
myobj {TestObject} -- the object to be modified
Returns:
TestObject -- modified object
"""
myobj.attr = new_value
return myobj
Actor = Example
This actor has add_two_ints
, concate_two_strings
, and modify_objet
methods. The first two are pretty basic
Let's do a walkthrough and check the invocation, and the errors
JS-NG> ACTOR_PATH = "/home/xmonader/wspace/threefoldtech/js-ng/jumpscale/servers/gedis/example_actor.py"
JS-NG> cl = j.clients.gedis.get("test")
JS-NG> cl.actors.system.register_actor("test_actor", ACTOR_PATH)
True
At this point we can do cl.reload
to add test_actor
into the client domain
JS-NG> cl.reload()
Getting actor documentation and information from
JS-NG> cl.actors.test_actor.info()
{'module': '/home/xmonader/wspace/threefoldtech/js-ng/jumpscale/servers/gedis', 'path': '/home/xmonader/wspace/threefoldtech/js-ng/jumpscale/servers/gedis/example_actor.py', 'methods': {'add_two_ints': {'args': [['x', 'int'], ['y', 'int']], 'doc': 'Adds two ints\n \n Arguments:\n x {int} -- first int\n y {int} -- second int\n \n Returns:\n int -- the sum of the two ints\n ', 'response_type': None}, 'concate_two_strings': {'args': [['x', 'str'], ['y', 'str']], 'doc': 'Concate two strings\n \n Arguments:\n x {str} -- first string\n y {str} -- second string\n \n Returns:\n str -- the concate of the two strings\n ', 'response_type': None}, 'info': {'args': [], 'doc': '', 'response_type': None}, 'get_testobject': {'args': [['myobj', 'TestObject'], ['new_value', 'int']], 'doc': 'returns an object of type Test object with update attribute attr to `new_value`\n \n Arguments:\n myobj {TestObject} -- the object to be modified\n \n Returns:\n TestObject -- modified object\n ', 'response_type': 'TestObject'}}}
Using the actor methods
JS-NG> cl.actors.test_actor.add_two_ints(4, 5)
9
What if we pass a wrong type?
JS-NG> cl.actors.test_actor.add_two_ints(4, "11")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/xmonader/wspace/threefoldtech/js-ng/jumpscale/clients/gedis/gedis.py", line 57, in method
response = self._gedis_client.execute(actor_name, actor_method, *args, **kwargs)
│ │ │ │ └ {}
│ │ │ └ (4, '11')
│ │ └ 'add_two_ints'
│ └ 'test_actor'
└ <jumpscale.clients.gedis.gedis.ActorProxy object at 0x7fb434817390>
File "/home/xmonader/wspace/threefoldtech/js-ng/jumpscale/clients/gedis/gedis.py", line 161, in execute
raise RemoteException(response_json['error'])
│ └ {'success': False, 'error': 'parameter (y) supposed to be of type (int), but found (str)', 'result': None}
└ <class 'jumpscale.clients.gedis.gedis.RemoteException'>
jumpscale.clients.gedis.gedis.RemoteException: parameter (y) supposed to be of type (int), but found (str)
parameter (y) supposed to be of type (int), but found (str)
What if we pass more than the specified arguments?
JS-NG> cl.actors.test_actor.add_two_ints(4, 2, 6)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/xmonader/wspace/threefoldtech/js-ng/jumpscale/clients/gedis/gedis.py", line 57, in method
response = self._gedis_client.execute(actor_name, actor_method, *args, **kwargs)
│ │ │ │ └ {}
│ │ │ └ (4, 2, 6)
│ │ └ 'add_two_ints'
│ └ 'test_actor'
└ <jumpscale.clients.gedis.gedis.ActorProxy object at 0x7fb434817390>
File "/home/xmonader/wspace/threefoldtech/js-ng/jumpscale/clients/gedis/gedis.py", line 161, in execute
raise RemoteException(response_json['error'])
│ └ {'success': False, 'error': 'Traceback (most recent call last):\n File "/home/xmonader/wspace/threefoldtech/js-ng/jumpscale/servers/g...
└ <class 'jumpscale.clients.gedis.gedis.RemoteException'>
jumpscale.clients.gedis.gedis.RemoteException: Traceback (most recent call last):
File "/home/xmonader/wspace/threefoldtech/js-ng/jumpscale/servers/gedis/server.py", line 210, in _exceute
args, kwargs = self._validate_method_arguments(method, args, kwargs)
│ │ │ │ │ └ {}
│ │ │ │ └ [4, 2, 6]
│ │ │ └ <bound method Example.add_two_ints of </home/xmonader/wspace/threefoldtech/js-ng/jumpscale/servers/gedis.Example object at 0x7f75132cf...
│ │ └ GedisServer(_Base__instance_name='test', _Base__parent=None, ___actors={}, __enable_system_actor=True, __host='127.0.0.1', __por...
│ └ {}
└ [4, 2, 6]
File "/home/xmonader/wspace/threefoldtech/js-ng/jumpscale/servers/gedis/server.py", line 188, in _validate_method_arguments
bound_arguments = signature.bind(*args, **kwargs)
│ │ └ {}
│ └ [4, 2, 6]
└ <Signature (x: int, y: int) -> int>
File "/home/linuxbrew/.linuxbrew/opt/python/lib/python3.7/inspect.py", line 3015, in bind
return args[0]._bind(args[1:], kwargs)
│ │ └ {}
│ └ (<Signature (x: int, y: int) -> int>, 4, 2, 6)
└ (<Signature (x: int, y: int) -> int>, 4, 2, 6)
File "/home/linuxbrew/.linuxbrew/opt/python/lib/python3.7/inspect.py", line 2936, in _bind
raise TypeError('too many positional arguments') from None
TypeError: too many positional arguments
Complex types
Let's assume that we have a complex type like
class TestObject:
def __init__(self):
self.attr = None
def to_dict(self):
return self.__dict__
def from_dict(self, ddict):
self.__dict__ = ddict
Any object with to_dict
and from_dict
is ok to use in actor methods for the serialization on the wire.
def get_testobject(self, myobj: TestObject, new_value: int) -> TestObject:
"""Modify atrribute attr of the given object
Arguments:
myobj {TestObject} -- the object to be modified
Returns:
TestObject -- modified object
"""
myobj.attr = new_value
return myobj
Let's test it
JS-NG> class TestObject:
2 def __init__(self):
3 self.attr = None
4
5 def to_dict(self):
6 return self.__dict__
7
8 def from_dict(self, ddict):
9 self.__dict__ = ddict
JS-NG> obj = TestObject()
JS-NG> res = cl.actors.test_actor.get_testobject(obj, 6)
JS-NG> res.attr
6
JS-NG> obj.attr
JS-NG>