jsonrpc: Lookup methods using the objects map directly
This commit is contained in:
parent
5a05b4af9d
commit
7f987cb1e2
@ -37,10 +37,7 @@ class JsonRpcWrapper(object):
|
||||
hello -> lambda
|
||||
abc.def -> abc.def()
|
||||
|
||||
Only the public methods of the objects will be exposed. Attributes are not
|
||||
exposed by themself, but public methods on public attributes are exposed,
|
||||
using dotted paths from the exposed object to the method at the end of the
|
||||
path.
|
||||
Only the public methods of the mounted objects will be exposed.
|
||||
|
||||
If a method returns a :class:`pykka.Future`, the future will be completed
|
||||
and its value unwrapped before the JSON-RPC wrapper returns the response.
|
||||
@ -59,32 +56,10 @@ class JsonRpcWrapper(object):
|
||||
"""
|
||||
|
||||
def __init__(self, objects, decoders=None, encoders=None):
|
||||
self.obj = self._build_exported_object(objects)
|
||||
self.objects = objects
|
||||
self.decoder = get_combined_json_decoder(decoders or [])
|
||||
self.encoder = get_combined_json_encoder(encoders or [])
|
||||
|
||||
def _build_exported_object(self, objects):
|
||||
class EmptyObject(object):
|
||||
pass
|
||||
|
||||
if '' in objects:
|
||||
exported_object = objects['']
|
||||
else:
|
||||
exported_object = EmptyObject()
|
||||
|
||||
mounts = sorted(objects.keys(), key=lambda x: len(x))
|
||||
for mount in mounts:
|
||||
parent = exported_object
|
||||
path = mount.split('.')
|
||||
for part in path[:-1]:
|
||||
if not hasattr(parent, part):
|
||||
setattr(parent, part, EmptyObject())
|
||||
parent = getattr(parent, part)
|
||||
if path[-1]:
|
||||
setattr(parent, path[-1], objects[mount])
|
||||
|
||||
return exported_object
|
||||
|
||||
def handle_json(self, request):
|
||||
"""
|
||||
Handles an incoming request encoded as a JSON string.
|
||||
@ -205,15 +180,21 @@ class JsonRpcWrapper(object):
|
||||
raise JsonRpcInvalidRequestError(
|
||||
data='"params", if given, must be an array or an object')
|
||||
|
||||
def _get_method(self, name):
|
||||
def _get_method(self, method_path):
|
||||
if inspect.isroutine(self.objects.get(method_path, None)):
|
||||
# The mounted object is the callable
|
||||
return self.objects[method_path]
|
||||
|
||||
# The mounted object contains the callable
|
||||
if '.' in method_path:
|
||||
mount, method_name = method_path.rsplit('.', 1)
|
||||
else:
|
||||
mount, method_name = '', method_path
|
||||
try:
|
||||
path = name.split('.')
|
||||
this = self.obj
|
||||
for part in path:
|
||||
if part.startswith('_'):
|
||||
raise AttributeError
|
||||
this = getattr(this, part)
|
||||
return this
|
||||
if method_name.startswith('_'):
|
||||
raise AttributeError
|
||||
obj = self.objects[mount]
|
||||
return getattr(obj, method_name)
|
||||
except (AttributeError, KeyError):
|
||||
raise JsonRpcMethodNotFoundError()
|
||||
|
||||
@ -309,13 +290,9 @@ class JsonRpcInspector(object):
|
||||
'abc': Abc,
|
||||
})
|
||||
|
||||
Since this inspector is based on inspecting classes and not instances, it
|
||||
will not give you a complete picture of what is actually exported by
|
||||
:class:`JsonRpcWrapper`. In particular:
|
||||
|
||||
- it will not include methods added dynamically, and
|
||||
- it will not include public methods on attributes on the instances that
|
||||
are to be exposed.
|
||||
Since the inspector is based on inspecting classes and not instances, it
|
||||
will not include methods added dynamically. The wrapper works with
|
||||
instances, and it will thus export dynamically added methods as well.
|
||||
|
||||
:param objects: mapping between mounts and exposed functions or classes
|
||||
:type objects: dict
|
||||
|
||||
@ -45,6 +45,8 @@ class JsonRpcTestBase(unittest.TestCase):
|
||||
objects={
|
||||
'hello': lambda: 'Hello, world!',
|
||||
'core': self.core,
|
||||
'core.playback': self.core.playback,
|
||||
'core.tracklist': self.core.tracklist,
|
||||
'': Calculator(),
|
||||
},
|
||||
encoders=[models.ModelJSONEncoder],
|
||||
|
||||
Loading…
Reference in New Issue
Block a user