diff options
author | Aleksey Lim <alsroot@sugarlabs.org> | 2012-09-25 05:25:13 (GMT) |
---|---|---|
committer | Aleksey Lim <alsroot@sugarlabs.org> | 2012-09-25 05:25:13 (GMT) |
commit | 82aa41773163b49c82a0b71c02e6f85eea1e352a (patch) | |
tree | 82097c94a77d9aea0051944299d7e51ad1b08be1 | |
parent | 40b9b03232f665d93e42bb72b9c93048413ea075 (diff) |
Support sub-calls
-rw-r--r-- | active_document/commands.py | 23 | ||||
-rw-r--r-- | active_document/document.py | 3 | ||||
-rw-r--r-- | active_document/volume.py | 10 | ||||
-rwxr-xr-x | tests/units/commands.py | 23 | ||||
-rwxr-xr-x | tests/units/volume.py | 33 |
5 files changed, 90 insertions, 2 deletions
diff --git a/active_document/commands.py b/active_document/commands.py index 1b303e9..cec88d4 100644 --- a/active_document/commands.py +++ b/active_document/commands.py @@ -93,6 +93,7 @@ class Request(dict): content_length = None access_level = env.ACCESS_REMOTE accept_language = None + commands = None def __init__(self, *args, **props): if args: @@ -103,6 +104,11 @@ class Request(dict): dict.__init__(self, props) self._pos = 0 + @property + def volume(self): + enforce(self.commands is not None) + return self.commands.volume + def __getitem__(self, key): enforce(key in self, 'Cannot find %r request argument', key) return self.get(key) @@ -118,6 +124,21 @@ class Request(dict): self._pos += len(result) return result + def call(self, method, content=None, content_stream=None, + content_length=None, **kwargs): + enforce(self.commands is not None) + + kwargs['method'] = method + request = type(self)(kwargs) + request.access_level = self.access_level + request.accept_language = self.accept_language + request.commands = self.commands + request.content = content + request.content_stream = content_stream + request.content_length = content_length + + return self.commands.call(request, Response()) + def __repr__(self): args = ['content_length=%r' % self.content_length, 'access_level=%r' % self.access_level, @@ -182,6 +203,8 @@ class CommandsProcessor(object): enforce(request.access_level & cmd.access_level, env.Forbidden, 'Operation is permitted on requester\'s level') + request.commands = self + for arg, cast in cmd.arguments.items(): if arg not in request: continue diff --git a/active_document/document.py b/active_document/document.py index 34e1090..9573ad4 100644 --- a/active_document/document.py +++ b/active_document/document.py @@ -28,10 +28,11 @@ class Document(dict): #: `Metadata` object that describes the document metadata = None - def __init__(self, guid, record, cached_props=None): + def __init__(self, guid, record, cached_props=None, request=None): dict.__init__(self, cached_props or {}) self.guid = guid self._record = record + self.request = request @active_property(slot=1000, prefix='IC', typecast=int, permissions=env.ACCESS_READ, default=0) diff --git a/active_document/volume.py b/active_document/volume.py index ebd6775..8583803 100644 --- a/active_document/volume.py +++ b/active_document/volume.py @@ -194,6 +194,7 @@ class VolumeCommands(CommandsProcessor): directory = self.volume[document] prop = directory.metadata[prop] doc = directory.get(guid) + doc.request = request prop.assert_access(env.ACCESS_READ) @@ -239,8 +240,14 @@ class VolumeCommands(CommandsProcessor): @contextmanager def _post(self, request, access): + enforce(isinstance(request.content, dict), 'Invalid value') + directory = self.volume[request['document']] - doc = directory.document_class(request.get('guid'), {}) + if 'guid' in request: + doc = directory.get(request['guid']) + else: + doc = directory.document_class(None, {}) + doc.request = request blobs = [] for name, value in request.content.items(): @@ -278,6 +285,7 @@ class VolumeCommands(CommandsProcessor): result = {} lang = request.accept_language or self._lang metadata = doc.metadata + doc.request = request for prop in request['reply']: result[prop] = metadata[prop].on_get(doc, doc.get(prop, lang)) return result diff --git a/tests/units/commands.py b/tests/units/commands.py index 0ba4c23..f5f753b 100755 --- a/tests/units/commands.py +++ b/tests/units/commands.py @@ -495,6 +495,29 @@ class CommandsTest(tests.Test): self.assertEqual(['pre', 'cmd', 'post'], request['probe']) self.assertEqual(['cmd', 'post'], response['probe']) + def test_SubCall(self): + + class TestCommandsProcessor(CommandsProcessor): + + @ad.volume_command(method='PROBE') + def command1(self, request): + return request.call('PROBE', cmd='command2') + + @ad.volume_command(method='PROBE') + def command2(self, request): + return {'access_level': request.access_level, 'accept_language': request.accept_language} + + cp = TestCommandsProcessor() + + request = ad.Request(method='PROBE') + request.access_level = -1 + request.accept_language = 'foo' + self.assertEqual({ + 'access_level': -1, + 'accept_language': 'foo', + }, + cp.call(request, ad.Response())) + def call(self, cp, method, document=None, guid=None, prop=None, access_level=env.ACCESS_REMOTE, **kwargs): diff --git a/tests/units/volume.py b/tests/units/volume.py index be706f9..0ef7c72 100755 --- a/tests/units/volume.py +++ b/tests/units/volume.py @@ -4,6 +4,7 @@ import os import sys import time +import json import shutil import hashlib from cStringIO import StringIO @@ -950,6 +951,38 @@ class VolumeTest(tests.Test): self.call('PUT', document='testdocument', guid=guid, prop='blob2', content='bar') self.assertEqual(' bar ', ''.join(self.call('GET', document='testdocument', guid=guid, prop='blob2'))) + def test_SubCall(self): + + class TestDocument(Document): + + @active_property(BlobProperty, mime_type='application/json') + def blob(self, value): + return value + + @blob.setter + def blob(self, value): + if type(value) is int: + value = [value] + meta = self.meta('blob') + if meta: + with file(meta['path']) as f: + value = json.load(f) + value + coroutine.spawn(self.post, value) + return value + + def post(self, value): + self.request.call('PUT', document='testdocument', guid=self.guid, prop='blob', content=value + [-1]) + + self.volume = SingleVolume(tests.tmpdir, [TestDocument]) + + guid = self.call('POST', document='testdocument', content={'blob': 0}) + coroutine.dispatch() + self.assertEqual('[0, -1]', ''.join(self.call('GET', document='testdocument', guid=guid, prop='blob'))) + + self.call('PUT', document='testdocument', guid=guid, prop='blob', content=2) + coroutine.dispatch() + self.assertEqual('[0, -1, 2, -1]', ''.join(self.call('GET', document='testdocument', guid=guid, prop='blob'))) + def call(self, method, document=None, guid=None, prop=None, accept_language=None, **kwargs): |