Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@sugarlabs.org>2012-03-26 18:32:22 (GMT)
committer Aleksey Lim <alsroot@sugarlabs.org>2012-03-26 18:32:22 (GMT)
commita80894a68b0d999ad9080f720af95ff7c6880e13 (patch)
treefc99185f3edde9ccd1fb1af036a1c72dbe9c4998
parent92f6ac6ee10b66d6c8162d7e900de6ca142f75d4 (diff)
Make BLOBs related API more useful
-rw-r--r--HACKING6
-rw-r--r--TODO1
-rwxr-xr-xexamples/client.py46
-rw-r--r--sugar_network/_zerosugar/solution.py3
-rw-r--r--sugar_network/client.py93
-rw-r--r--sugar_network/resources.py7
6 files changed, 97 insertions, 59 deletions
diff --git a/HACKING b/HACKING
index 2dcbce6..cab54f8 100644
--- a/HACKING
+++ b/HACKING
@@ -13,8 +13,8 @@ Send patches
------------
Create your patches using ``git format`` command and send them to all
maintainers from the :doc:`AUTHORS <AUTHORS>` file with CCing to
-sugar-network@googlegroups.com. The easiest way it just using
-``git send-email`` command.
+sugar-network@googlegroups.com. The easiest way is using ``git send-email``
+command.
Gitorious forks
---------------
@@ -26,4 +26,4 @@ Gitorious forks and request them for merge to the trunk.
* http://blog.gitorious.org/2009/07/15/new-merge-request-functionality/
* http://blog.gitorious.org/2009/11/06/awesome-code-review/
-.. _sugar-lint: http://wiki.sugarlabs.org/go/Activity_Team/Sugar_Lint
+.. _sugar-lint: http://wiki.sugarlabs.org/go/Platform_Team/Sugar_Lint
diff --git a/TODO b/TODO
index 6965439..59c9da0 100644
--- a/TODO
+++ b/TODO
@@ -1,2 +1,3 @@
- import <bundle_id> data dir into data/
- reuse the same data dir for all SN names for the same context
+- treat "/" in user datain requests
diff --git a/examples/client.py b/examples/client.py
index 25efc52..6888e40 100755
--- a/examples/client.py
+++ b/examples/client.py
@@ -9,6 +9,7 @@ from cStringIO import StringIO
import restful_document
import sugar_network as client
import sugar_network_server as server
+from sugar_network import Context
def main():
@@ -17,11 +18,11 @@ def main():
image_url = 'http://sugarlabs.org/assets/logo_black_01.png'
print '-- Delete objects'
- for i in client.Context.find():
- client.Context.delete(i['guid'])
+ for i in Context.find():
+ Context.delete(i['guid'])
def context_new(title):
- context = client.Context()
+ context = Context()
context['type'] = 'activity'
context['title'] = title
context['summary'] = 'Description'
@@ -38,39 +39,40 @@ def main():
assert guids[2] and guids[2] != guids[1] and guids[2] != guids[0]
print '-- Browse using iterators'
- for i, obj in enumerate(client.Context.find()):
+ for i, obj in enumerate(Context.find()):
assert i == obj.offset
assert obj['guid'] == guids[i]
print '-- Browse by offset'
- query = client.Context.find()
+ query = Context.find()
for i in range(query.total):
assert query[i]['guid'] == guids[i]
print '-- Get objects directly'
- assert client.Context(guids[0])['title'] == titles[0]
- assert client.Context(guids[1])['title'] == titles[1]
- assert client.Context(guids[2])['title'] == titles[2]
-
- print '-- Set BLOB properties'
- with client.Artifact() as artifact:
- artifact['context'] = guids[0]
- artifact['type'] = 'screenshot'
- artifact['title'] = titles[0]
- artifact['description'] = titles[0]
- artifact.set_blob('preview', StringIO('screenshot-image'))
+ assert Context(guids[0])['title'] == titles[0]
+ assert Context(guids[1])['title'] == titles[1]
+ assert Context(guids[2])['title'] == titles[2]
+
+ print '-- Set BLOB property by stream'
+ Context(guids[0]).blobs['icon'] = StringIO('stream')
+
+ print '-- Set BLOB property by string'
+ Context(guids[1]).blobs['icon'] = 'string'
print '-- Set BLOB properties by url'
- artifact.set_blob_with_url('data', image_url)
+ Context(guids[2]).blobs['icon'].url = image_url
- print '-- Get BLOB properties'
+ print '-- Get BLOB property by portions'
stream = StringIO()
- for chunk in client.Artifact(artifact['guid']).get_blob('data'):
+ for chunk in Context(guids[2]).blobs['icon'].iter_content():
stream.write(chunk)
assert stream.getvalue() == urllib2.urlopen(image_url).read()
+ print '-- Get BLOB property by string'
+ assert Context(guids[1]).blobs['icon'].content == 'string'
+
print '-- Query by property value'
- for obj in client.Context.find(title='Title2'):
+ for obj in Context.find(title='Title2'):
assert obj['guid'] == guids[1]
assert obj['title'] == titles[1]
@@ -79,7 +81,7 @@ def main():
time.sleep(3)
print '-- Full text search query'
- query = client.Context.find(query='Title1 OR Title3')
+ query = Context.find(query='Title1 OR Title3')
assert query.total == 2
assert query[0]['guid'] == guids[0]
assert query[0]['title'] == titles[0]
@@ -93,7 +95,7 @@ if __name__ == '__main__':
server.stats_root.value = 'tmp/stats'
server.logdir.value = 'tmp/log'
server.index_flush_threshold.value = 1
- server_pid = restful_document.fork(server.resources())
+ server_pid = restful_document.fork(server.resources)
client.api_url.value = \
'http://%s:%s' % (server.host.value, server.port.value)
diff --git a/sugar_network/_zerosugar/solution.py b/sugar_network/_zerosugar/solution.py
index a6cd245..a81a5cd 100644
--- a/sugar_network/_zerosugar/solution.py
+++ b/sugar_network/_zerosugar/solution.py
@@ -132,7 +132,8 @@ class _Selection(object):
if not exists(path):
tmp_path = util.TempFilePath(dir=dirname(path))
with file(tmp_path, 'wb') as f:
- for chunk in Implementation(self.id).get_blob('bundle'):
+ impl = Implementation(self.id)
+ for chunk in impl.blobs['bundle'].iter_content():
f.write(chunk)
if not f.tell():
return
diff --git a/sugar_network/client.py b/sugar_network/client.py
index f9ee8c2..f65f79b 100644
--- a/sugar_network/client.py
+++ b/sugar_network/client.py
@@ -34,6 +34,10 @@ _logger = logging.getLogger('client')
_headers = {}
+def delete(resource, guid):
+ _request('DELETE', [resource, guid])
+
+
class ServerError(Exception):
def __init__(self, request_, error):
@@ -191,8 +195,7 @@ class Query(object):
if self._reply_properties:
params['reply'] = ','.join(self._reply_properties)
- reply = request('GET', self._path, params=params,
- headers={'Content-Type': 'application/json'})
+ reply = _request('GET', self._path, params=params)
self._total = reply['total']
result = [None] * len(reply['result'])
@@ -225,6 +228,11 @@ class Object(dict):
if 'guid' in self:
self._path = [resource, self['guid']]
+ @property
+ def blobs(self):
+ enforce(self._path is not None, _('Object needs to be posted first'))
+ return _Blobs(self._path)
+
def __enter__(self):
return self
@@ -235,8 +243,7 @@ class Object(dict):
result = self.get(prop)
if result is None:
if self._path and not self._got:
- reply = request('GET', self._path,
- headers={'Content-Type': 'application/json'})
+ reply = _request('GET', self._path)
reply.update(self)
self.update(reply)
self._got = True
@@ -259,7 +266,7 @@ class Object(dict):
for i in self._dirty:
data[i] = self[i]
if 'guid' in self:
- request('PUT', self._path, data=data,
+ _request('PUT', self._path, data=data,
headers={'Content-Type': 'application/json'})
else:
if 'author' in data:
@@ -268,22 +275,65 @@ class Object(dict):
else:
data['author'] = [sugar.guid()]
dict.__setitem__(self, 'author', [sugar.guid()])
- reply = request('POST', [self._resource], data=data,
+ reply = _request('POST', [self._resource], data=data,
headers={'Content-Type': 'application/json'})
self.update(reply)
- self._path = '/%s/%s' % (self._resource, self['guid'])
+ self._path = [self._resource, self['guid']]
self._dirty.clear()
- def get_blob(self, prop):
- enforce('guid' in self, _('Object needs to be posted first'))
- response = request('GET', [self._resource, self['guid'], prop],
- headers={'Content-Type': 'application/octet-stream'},
- allow_redirects=True)
+ def call(self, command, method='GET', **kwargs):
+ enforce(self._path is not None, _('Object needs to be posted first'))
+ kwargs['cmd'] = command
+ return _request(method, self._path, params=kwargs)
+
+
+class Blob(object):
+
+ def __init__(self, path):
+ self._path = path
+
+ @property
+ def content(self):
+ """Return entire BLOB value as a string."""
+ response = _request('GET', self._path, allow_redirects=True)
+ if hasattr(response, 'content'):
+ return response.content
+ else:
+ return response
+
+ @property
+ def path(self):
+ """Return file-system path to file that contain BLOB value."""
+ return '/home/me/Activities/cartoon-builder.activity/' \
+ 'activity/activity-cartoonbuilder.svg'
+
+ def iter_content(self):
+ """Return BLOB value by poritons.
+
+ :returns:
+ generator that returns BLOB value by chunks
+
+ """
+ response = _request('GET', self._path, allow_redirects=True)
length = int(response.headers.get('Content-Length', _CHUNK_SIZE))
return response.iter_content(chunk_size=min(length, _CHUNK_SIZE))
- def set_blob(self, prop, data):
- enforce('guid' in self, _('Object needs to be posted first'))
+ def _set_url(self, url):
+ _request('PUT', self._path, params={'url': url})
+
+ #: Set BLOB value by url
+ url = property(None, _set_url)
+
+
+class _Blobs(object):
+
+ def __init__(self, path):
+ self._path = path
+
+ def __getitem__(self, prop):
+ return Blob(self._path + [prop])
+
+ def __setitem__(self, prop, data):
headers = None
if type(data) is dict:
files = data
@@ -294,20 +344,11 @@ class Object(dict):
else:
files = None
headers = {'Content-Type': 'application/octet-stream'}
- request('PUT', [self._resource, self['guid'], prop], headers=headers,
+ _request('PUT', self._path + [prop], headers=headers,
data=data, files=files)
- def set_blob_with_url(self, prop, url):
- enforce('guid' in self, _('Object needs to be posted first'))
- request('PUT', [self._resource, self['guid'], prop],
- params={'url': url})
-
-
-def delete(resource, guid):
- request('DELETE', [resource, guid])
-
-def request(method, path, data=None, headers=None, **kwargs):
+def _request(method, path, data=None, headers=None, **kwargs):
path = '/'.join([i.strip('/') for i in [env.api_url.value] + path])
if not _headers:
@@ -357,7 +398,7 @@ def request(method, path, data=None, headers=None, **kwargs):
def _register():
- request('POST', ['user'],
+ _request('POST', ['user'],
headers={'Content-Type': 'application/json'},
data={
'nickname': sugar.nickname() or '',
diff --git a/sugar_network/resources.py b/sugar_network/resources.py
index 9c2e7bf..c9dc672 100644
--- a/sugar_network/resources.py
+++ b/sugar_network/resources.py
@@ -50,13 +50,6 @@ class Resource(client.Object):
enforce(query.total == 1, _('Found more than one object'))
client.Object.__init__(self, self.resource, query[0])
- def call(self, command, **kwargs):
- enforce('guid' in self, _('Object needs to be postet first'))
- kwargs['cmd'] = command
- return client.request('GET', [self.resource, self['guid']],
- headers={'Content-Type': 'application/json'},
- params=kwargs)
-
@classmethod
def find(cls, *args, **kwargs):
"""Query resource objects.