Merge lp:~jderose/microfiber/att into lp:microfiber

Proposed by Jason Gerard DeRose
Status: Merged
Merged at revision: 157
Proposed branch: lp:~jderose/microfiber/att
Merge into: lp:microfiber
Diff against target: 162 lines (+89/-7)
2 files modified
microfiber.py (+35/-1)
test_microfiber.py (+54/-6)
To merge this branch: bzr merge lp:~jderose/microfiber/att
Reviewer Review Type Date Requested Status
David Jordan Approve
Review via email: mp+134280@code.launchpad.net

Description of the change

For details and rational, see bug:

  https://bugs.launchpad.net/microfiber/+bug/1078656

Changes:

  * Adds `Attachment(content_type, data)` namedtuple

  * `CouchBase.get_att()` now returns an `Attachment` namedtuple rather than a vanilla tuple

  * Adds `encode_attachment(attachment)` function

  * Adds experimental `CouchBase.put_att2()` method to evaluate possible breaking `CouchBase.put_att()` API change

To post a comment you must log in.
Revision history for this message
David Jordan (dmj726) wrote :

Looks good, approved.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'microfiber.py'
2--- microfiber.py 2012-11-06 21:07:38 +0000
3+++ microfiber.py 2012-11-14 10:46:21 +0000
4@@ -58,6 +58,7 @@
5 from queue import Queue
6 import math
7 import platform
8+from collections import namedtuple
9
10 # Monkey patch python3.2 to add ssl.OP_NO_COMPRESSION available in python3.3:
11 if not hasattr(ssl, 'OP_NO_COMPRESSION'):
12@@ -110,6 +111,8 @@
13 )
14 DEFAULT_URL = HTTP_IPv4_URL
15
16+Attachment = namedtuple('Attachment', 'content_type data')
17+
18
19 class BulkConflict(Exception):
20 """
21@@ -307,6 +310,25 @@
22 return dumps(obj).encode('utf-8')
23
24
25+def encode_attachment(attachment):
26+ """
27+ Encode *attachment* for use in ``doc['_attachments']``.
28+
29+ For example:
30+
31+ >>> attachment = Attachment('image/png', b'PNG data')
32+ >>> dumps(encode_attachment(attachment))
33+ '{"content_type":"image/png","data":"UE5HIGRhdGE="}'
34+
35+ :param attachment: an `Attachment` namedtuple
36+ """
37+ assert isinstance(attachment, Attachment)
38+ return {
39+ 'content_type': attachment.content_type,
40+ 'data': b64encode(attachment.data).decode('utf-8'),
41+ }
42+
43+
44 def _queryiter(options):
45 """
46 Return appropriately encoded (key, value) pairs sorted by key.
47@@ -804,6 +826,17 @@
48 {'Content-Type': mime}
49 )
50
51+ def put_att2(self, attachment, *parts, **options):
52+ """
53+ Experiment for possible CouchBase.put_att() API change.
54+
55+ WARNING: regardless how the experiment turns out, this method will be
56+ removed!
57+ """
58+ return self.recv_json('PUT', parts, options, attachment.data,
59+ {'Content-Type': attachment.content_type}
60+ )
61+
62 def get_att(self, *parts, **options):
63 """
64 GET an attachment.
65@@ -823,8 +856,9 @@
66 :param options: optional keyword arguments to include in query
67 """
68 response = self.request('GET', parts, options)
69+ content_type = response.getheader('Content-Type')
70 data = response.read()
71- return (response.getheader('Content-Type'), data)
72+ return Attachment(content_type, data)
73
74
75 class Server(CouchBase):
76
77=== modified file 'test_microfiber.py'
78--- test_microfiber.py 2012-11-06 21:07:38 +0000
79+++ test_microfiber.py 2012-11-14 10:46:21 +0000
80@@ -250,6 +250,17 @@
81 # Test when obj is pre-encoded bytes
82 self.assertEqual(microfiber._json_body(json_bytes), json_bytes)
83
84+ def test_encode_attachment(self):
85+ data = os.urandom(1776)
86+ att = microfiber.Attachment('image/jpeg', data)
87+ self.assertEqual(
88+ microfiber.encode_attachment(att),
89+ {
90+ 'content_type': 'image/jpeg',
91+ 'data': b64encode(data).decode('utf-8'),
92+ }
93+ )
94+
95 def test_queryiter(self):
96 f = microfiber._queryiter
97 d = dict(foo=True, bar=False, baz=None, aye=10, zee=17.5, key='app')
98@@ -1966,10 +1977,10 @@
99 self.assertEqual(att['data'], b64encode(data).decode('utf-8'))
100
101 # GET the attachment
102- self.assertEqual(
103- inst.get_att(self.db, 'doc1', 'att'),
104- (mime, data)
105- )
106+ att = inst.get_att(self.db, 'doc1', 'att')
107+ self.assertIsInstance(att, microfiber.Attachment)
108+ self.assertEqual(att.content_type, mime)
109+ self.assertEqual(att.data, data)
110
111 # Create new doc with inline attachment:
112 new = {
113@@ -2005,11 +2016,48 @@
114 )
115
116 # GET the attachment:
117+ att = inst.get_att(self.db, 'doc1', 'att')
118+ self.assertIsInstance(att, microfiber.Attachment)
119+ self.assertEqual(att.content_type, mime)
120+ self.assertEqual(att.data, data)
121+
122+ def test_put_att2(self):
123+ inst = microfiber.CouchBase(self.env)
124+
125+ # Create database
126+ self.assertEqual(inst.put(None, 'foo'), {'ok': True})
127+
128+ data = os.urandom(1776)
129+ att = microfiber.Attachment('image/png', data)
130+ digest = b64encode(md5(data).digest()).decode('utf-8')
131+
132+ # PUT attachment
133+ r = inst.put_att2(att, 'foo', 'bar', 'baz')
134+ self.assertEqual(set(r), set(['id', 'rev', 'ok']))
135+ self.assertEqual(r['id'], 'bar')
136+ self.assertEqual(r['ok'], True)
137+ self.assertTrue(r['rev'].startswith('1-'))
138+
139+ # GET the doc with attachments=true
140+ doc = inst.get('foo', 'bar', attachments=True)
141+ self.assertEqual(set(doc), set(['_id', '_rev', '_attachments']))
142+ self.assertEqual(doc['_id'], 'bar')
143+ self.assertEqual(doc['_rev'], r['rev'])
144 self.assertEqual(
145- inst.get_att(self.db, 'doc2', 'att'),
146- (mime, data)
147+ doc['_attachments'],
148+ {
149+ 'baz': {
150+ 'content_type': 'image/png',
151+ 'data': b64encode(data).decode('ascii'),
152+ 'revpos': 1,
153+ 'digest': 'md5-{}'.format(digest),
154+ },
155+ }
156 )
157
158+ # Test the round-trip
159+ self.assertEqual(inst.get_att('foo', 'bar', 'baz'), att)
160+
161 def test_put_post(self):
162 inst = self.klass(self.env)
163

Subscribers

People subscribed via source and target branches