Merge lp:~djfroofy/txaws/newagent-767205 into lp:txaws

Proposed by Drew Smathers
Status: Merged
Approved by: Duncan McGreggor
Approved revision: 144
Merged at revision: 144
Proposed branch: lp:~djfroofy/txaws/newagent-767205
Merge into: lp:txaws
Prerequisite: lp:~djfroofy/txaws/modernize-924459
Diff against target: 564 lines (+137/-52)
3 files modified
txaws/client/base.py (+3/-1)
txaws/s3/client.py (+49/-25)
txaws/s3/tests/test_client.py (+85/-26)
To merge this branch: bzr merge lp:~djfroofy/txaws/newagent-767205
Reviewer Review Type Date Requested Status
Duncan McGreggor Approve
Drew Smathers Needs Resubmitting
Robert Collins Abstain
Review via email: mp+93312@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) :
review: Abstain
Revision history for this message
Duncan McGreggor (oubiwann) wrote :

This change looks good to me at first glance (reading the diff on the merge proposal; I haven't branched the code yet). In particular, the amz_headers functionality is much-needed.

Drew, I don't see anything about the new web client usage, only headers and body producer. Is that coming in a future change?

At the risk of being a total pain in the ass, here's what I would recommend:

1) split out the headers changes into a new branch, and attach it to bug #972432.
2) create a new bug for the body producer/receiver factory feature, split that code out, and attach it to there in its own branch.
3) do the work on the new agent in this branch and this ticket (bug #767205).

review: Needs Fixing
Revision history for this message
Daira Hopwood (daira) wrote :

Thanks, will review tomorrow.

Revision history for this message
Daira Hopwood (daira) wrote :

Sorry for the delay. Looks good to me.

Just a minor style nit: some of the code indents parameters to after the '(', and some only by 4 spaces. E.g.
{{{
def __init__(self, creds=None, endpoint=None, query_factory=None,
             parser=None, receiver_factory=None):
}}}
vs
{{{
def __init__(self, creds=None, endpoint=None, query_factory=None,
    receiver_factory=None):
}}}
The former is more readable.

Revision history for this message
Zooko Wilcox-O'Hearn (zooko) wrote :

Okay, if david-sarah reviewed it and said "Looks good to me", then the branch ought to be merged. Who has authority do that?

Revision history for this message
Duncan McGreggor (oubiwann) wrote :

On Thu, Apr 12, 2012 at 5:02 PM, Zooko Wilcox-O'Hearn <email address hidden> wrote:
> Okay, if david-sarah reviewed it and said "Looks good to me", then the branch ought to be merged. Who has authority do that?

I'll take a look...

d

Revision history for this message
Duncan McGreggor (oubiwann) wrote :

On Fri, Apr 13, 2012 at 12:43 AM, Duncan McGreggor <email address hidden> wrote:
> On Thu, Apr 12, 2012 at 5:02 PM, Zooko Wilcox-O'Hearn <email address hidden> wrote:
>> Okay, if david-sarah reviewed it and said "Looks good to me", then the branch ought to be merged. Who has authority do that?
>
> I'll take a look...

Okay, I just took a look. Looks like a review comment I left earlier
(needs fixing) hasn't been addressed by the author (unless I'm missing
something?).

Once that's either done or discussed, we can move this puppy forward :-)

Revision history for this message
Drew Smathers (djfroofy) wrote :

> This change looks good to me at first glance (reading the diff on the merge
> proposal; I haven't branched the code yet). In particular, the amz_headers
> functionality is much-needed.
>
> Drew, I don't see anything about the new web client usage, only headers and
> body producer. Is that coming in a future change?
>

Ok, so I had to remember myself while staring at the diff. The code for agent is in the prerequisite branch: lp:~djfroofy/txaws/modernize-924459

> At the risk of being a total pain in the ass, here's what I would recommend:
>

No, no worries.

> 1) split out the headers changes into a new branch, and attach it to bug
> #972432.

#972432 must be a duplicate of #640098; the amz_headers argument has been merged already. To summarize what this diff is adding: Support for plugging in Body Producers and Receivers in s3.client (this is made possible by: lp:~djfroofy/txaws/modernize-924459).

There are actually no changes related to headers in this patch. Rather, I'm adding receiver_factory as __init__() argument to S3Client and body_producer as argument to regular S3 api calls.

Cutting to the point, I think #972432 needs to be reviewed first.

> 2) create a new bug for the body producer/receiver factory feature, split that
> code out, and attach it to there in its own branch.

That was in the scope of #972432

> 3) do the work on the new agent in this branch and this ticket (bug #767205).

Again: #972432 is where that functionality is.

Revision history for this message
Drew Smathers (djfroofy) wrote :

> Sorry for the delay. Looks good to me.
>
> Just a minor style nit: some of the code indents parameters to after the '(',
> and some only by 4 spaces. E.g.
> {{{
> def __init__(self, creds=None, endpoint=None, query_factory=None,
> parser=None, receiver_factory=None):
> }}}
> vs
> {{{
> def __init__(self, creds=None, endpoint=None, query_factory=None,
> receiver_factory=None):
> }}}
> The former is more readable.

Yes, I agree and will address this.

lp:~djfroofy/txaws/newagent-767205 updated
144. By Drew Smathers

param indentation style fix [f=767205]

Revision history for this message
Drew Smathers (djfroofy) wrote :

Ok style fixes pushed to branch.

review: Needs Resubmitting
Revision history for this message
Duncan McGreggor (oubiwann) wrote :

On Sat, Apr 14, 2012 at 12:28 PM, Drew Smathers
<email address hidden> wrote:
>> This change looks good to me at first glance (reading the diff on the merge
>> proposal; I haven't branched the code yet). In particular, the amz_headers
>> functionality is much-needed.
>>
>> Drew, I don't see anything about the new web client usage, only headers and
>> body producer. Is that coming in a future change?
>>
>
> Ok, so I had to remember myself while staring at the diff. The code for agent is in the prerequisite branch: lp:~djfroofy/txaws/modernize-924459
>
>
>> At the risk of being a total pain in the ass, here's what I would recommend:
>>
>
> No, no worries.
>
>> 1) split out the headers changes into a new branch, and attach it to bug
>> #972432.
>
> #972432 must be a duplicate of #640098; the amz_headers argument has been merged already.  To summarize what this diff is adding: Support for plugging in Body Producers and Receivers in s3.client (this is made possible by: lp:~djfroofy/txaws/modernize-924459).
>
> There are actually no changes related to headers in this patch. Rather, I'm adding receiver_factory as __init__() argument to S3Client and body_producer as argument to regular S3 api calls.
>
> Cutting to the point, I think #972432 needs to be reviewed first.
>
>> 2) create a new bug for the body producer/receiver factory feature, split that
>> code out, and attach it to there in its own branch.
>
> That was in the scope of #972432
>
>> 3) do the work on the new agent in this branch and this ticket (bug #767205).
>
> Again: #972432 is where that functionality is.
> --
> https://code.launchpad.net/~djfroofy/txaws/newagent-767205/+merge/93312
> You are reviewing the proposed merge of lp:~djfroofy/txaws/newagent-767205 into lp:txaws.

Thanks for catching me up, Drew -- this is good stuff.

I'm going to be in the air tomorrow, on the way to the OpenStack
design summit and conference, but will branch all the code and check
out the associated tickets, to make sure I haven't missed anything.

Regardless, it looks like we've got a pending merge on our hands. This
code should land in trunk within a day or two...

Thanks again!

Revision history for this message
Duncan McGreggor (oubiwann) wrote :

On Sat, Apr 14, 2012 at 12:28 PM, Drew Smathers
<email address hidden> wrote:
>>
>> 1) split out the headers changes into a new branch, and attach it to bug
>> #972432.
>
> #972432 must be a duplicate of #640098; the amz_headers argument has been merged already.  To summarize what this diff is adding: Support for plugging in Body Producers and Receivers in s3.client (this is made possible by: lp:~djfroofy/txaws/modernize-924459).
>
> There are actually no changes related to headers in this patch. Rather, I'm adding receiver_factory as __init__() argument to S3Client and body_producer as argument to regular S3 api calls.
>
> Cutting to the point, I think #972432 needs to be reviewed first.

Do you mean bug #924459? (since bug #972432 is a duplicate of bug #640098 ...)

>> 2) create a new bug for the body producer/receiver factory feature, split that
>> code out, and attach it to there in its own branch.
>
> That was in the scope of #972432

It looks like you mean bug #640098?

More soon...

Revision history for this message
Drew Smathers (djfroofy) wrote :

> On Sat, Apr 14, 2012 at 12:28 PM, Drew Smathers
> <email address hidden> wrote:
> >>
> >> 1) split out the headers changes into a new branch, and attach it to bug
> >> #972432.
> >
> > #972432 must be a duplicate of #640098; the amz_headers argument has been
> merged already.  To summarize what this diff is adding: Support for plugging
> in Body Producers and Receivers in s3.client (this is made possible by:
> lp:~djfroofy/txaws/modernize-924459).
> >
> > There are actually no changes related to headers in this patch. Rather, I'm
> adding receiver_factory as __init__() argument to S3Client and body_producer
> as argument to regular S3 api calls.
> >
> > Cutting to the point, I think #972432 needs to be reviewed first.
>
> Do you mean bug #924459? (since bug #972432 is a duplicate of bug #640098 ...)
>
> >> 2) create a new bug for the body producer/receiver factory feature, split
> that
> >> code out, and attach it to there in its own branch.
> >
> > That was in the scope of #972432
>
> It looks like you mean bug #640098?

No, another typo, but I meant bug #924459. This has underlying support for the producer/receiver factory supports. This current ticket then just exposes that underlying support in s3 APIs.

Revision history for this message
Drew Smathers (djfroofy) wrote :

> On Sat, Apr 14, 2012 at 12:28 PM, Drew Smathers
> <email address hidden> wrote:
> >>
> >> 1) split out the headers changes into a new branch, and attach it to bug
> >> #972432.
> >
> > #972432 must be a duplicate of #640098; the amz_headers argument has been
> merged already.  To summarize what this diff is adding: Support for plugging
> in Body Producers and Receivers in s3.client (this is made possible by:
> lp:~djfroofy/txaws/modernize-924459).
> >
> > There are actually no changes related to headers in this patch. Rather, I'm
> adding receiver_factory as __init__() argument to S3Client and body_producer
> as argument to regular S3 api calls.
> >
> > Cutting to the point, I think #972432 needs to be reviewed first.
>
> Do you mean bug #924459? (since bug #972432 is a duplicate of bug #640098 ...)
>

Yes, this was a typo.

Revision history for this message
Duncan McGreggor (oubiwann) wrote :

Merge away!

review: Approve
Revision history for this message
Drew Smathers (djfroofy) wrote :

> Merge away!

Hi Duncan, am I the one who is supposed to do the merge, or does this need to be done by another developer?

Revision history for this message
Duncan McGreggor (oubiwann) wrote :

On Fri, May 11, 2012 at 1:19 PM, Drew Smathers
<email address hidden> wrote:
>> Merge away!
>
> Hi Duncan, am I the one who is supposed to do the merge, or does this need to be done by another developer?

Yes! I've just added you to the team -- given your contributions (and
god-like patience!), I think that's more than reasonable :-)

You'll want to do the obvious (merge trunk into your branches, check
for conflicts, push, etc.), but you should be all set!

Let us know if you run into any problems.

d

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'txaws/client/base.py'
2--- txaws/client/base.py 2012-04-14 16:36:18 +0000
3+++ txaws/client/base.py 2012-04-14 16:36:18 +0000
4@@ -74,9 +74,10 @@
5 @param query_factory: The class or function that produces a query
6 object for making requests to the EC2 service.
7 @param parser: A parser object for parsing responses from the EC2 service.
8+ @param receiver_factory: Factory for receiving responses from EC2 service.
9 """
10 def __init__(self, creds=None, endpoint=None, query_factory=None,
11- parser=None):
12+ parser=None, receiver_factory=None):
13 if creds is None:
14 creds = AWSCredentials()
15 if endpoint is None:
16@@ -84,6 +85,7 @@
17 self.creds = creds
18 self.endpoint = endpoint
19 self.query_factory = query_factory
20+ self.receiver_factory = receiver_factory
21 self.parser = parser
22
23 class StreamingError(Exception):
24
25=== modified file 'txaws/s3/client.py'
26--- txaws/s3/client.py 2012-01-28 00:39:00 +0000
27+++ txaws/s3/client.py 2012-04-14 16:36:18 +0000
28@@ -74,10 +74,12 @@
29 class S3Client(BaseClient):
30 """A client for S3."""
31
32- def __init__(self, creds=None, endpoint=None, query_factory=None):
33+ def __init__(self, creds=None, endpoint=None, query_factory=None,
34+ receiver_factory=None):
35 if query_factory is None:
36 query_factory = Query
37- super(S3Client, self).__init__(creds, endpoint, query_factory)
38+ super(S3Client, self).__init__(creds, endpoint, query_factory,
39+ receiver_factory=receiver_factory)
40
41 def list_buckets(self):
42 """
43@@ -87,7 +89,8 @@
44 the request.
45 """
46 query = self.query_factory(
47- action="GET", creds=self.creds, endpoint=self.endpoint)
48+ action="GET", creds=self.creds, endpoint=self.endpoint,
49+ receiver_factory=self.receiver_factory)
50 d = query.submit()
51 return d.addCallback(self._parse_list_buckets)
52
53@@ -131,7 +134,7 @@
54 """
55 query = self.query_factory(
56 action="GET", creds=self.creds, endpoint=self.endpoint,
57- bucket=bucket)
58+ bucket=bucket, receiver_factory=self.receiver_factory)
59 d = query.submit()
60 return d.addCallback(self._parse_get_bucket)
61
62@@ -174,7 +177,8 @@
63 """
64 query = self.query_factory(action="GET", creds=self.creds,
65 endpoint=self.endpoint, bucket=bucket,
66- object_name="?location")
67+ object_name="?location",
68+ receiver_factory=self.receiver_factory)
69 d = query.submit()
70 return d.addCallback(self._parse_bucket_location)
71
72@@ -193,7 +197,8 @@
73 """
74 query = self.query_factory(
75 action='GET', creds=self.creds, endpoint=self.endpoint,
76- bucket=bucket, object_name='?lifecycle')
77+ bucket=bucket, object_name='?lifecycle',
78+ receiver_factory=self.receiver_factory)
79 return query.submit().addCallback(self._parse_lifecycle_config)
80
81 def _parse_lifecycle_config(self, xml_bytes):
82@@ -221,7 +226,8 @@
83 """
84 query = self.query_factory(
85 action='GET', creds=self.creds, endpoint=self.endpoint,
86- bucket=bucket, object_name='?website')
87+ bucket=bucket, object_name='?website',
88+ receiver_factory=self.receiver_factory)
89 return query.submit().addCallback(self._parse_website_config)
90
91 def _parse_website_config(self, xml_bytes):
92@@ -242,7 +248,8 @@
93 """
94 query = self.query_factory(
95 action='GET', creds=self.creds, endpoint=self.endpoint,
96- bucket=bucket, object_name='?notification')
97+ bucket=bucket, object_name='?notification',
98+ receiver_factory=self.receiver_factory)
99 return query.submit().addCallback(self._parse_notification_config)
100
101 def _parse_notification_config(self, xml_bytes):
102@@ -262,7 +269,8 @@
103 """
104 query = self.query_factory(
105 action='GET', creds=self.creds, endpoint=self.endpoint,
106- bucket=bucket, object_name='?versioning')
107+ bucket=bucket, object_name='?versioning',
108+ receiver_factory=self.receiver_factory)
109 return query.submit().addCallback(self._parse_versioning_config)
110
111 def _parse_versioning_config(self, xml_bytes):
112@@ -279,7 +287,8 @@
113 """
114 query = self.query_factory(
115 action='GET', creds=self.creds, endpoint=self.endpoint,
116- bucket=bucket, object_name='?acl')
117+ bucket=bucket, object_name='?acl',
118+ receiver_factory=self.receiver_factory)
119 return query.submit().addCallback(self._parse_acl)
120
121 def put_bucket_acl(self, bucket, access_control_policy):
122@@ -289,7 +298,8 @@
123 data = access_control_policy.to_xml()
124 query = self.query_factory(
125 action='PUT', creds=self.creds, endpoint=self.endpoint,
126- bucket=bucket, object_name='?acl', data=data)
127+ bucket=bucket, object_name='?acl', data=data,
128+ receiver_factory=self.receiver_factory)
129 return query.submit().addCallback(self._parse_acl)
130
131 def _parse_acl(self, xml_bytes):
132@@ -299,8 +309,8 @@
133 """
134 return AccessControlPolicy.from_xml(xml_bytes)
135
136- def put_object(self, bucket, object_name, data, content_type=None,
137- metadata={}, amz_headers={}):
138+ def put_object(self, bucket, object_name, data=None, content_type=None,
139+ metadata={}, amz_headers={}, body_producer=None):
140 """
141 Put an object in a bucket.
142
143@@ -318,7 +328,8 @@
144 action="PUT", creds=self.creds, endpoint=self.endpoint,
145 bucket=bucket, object_name=object_name, data=data,
146 content_type=content_type, metadata=metadata,
147- amz_headers=amz_headers)
148+ amz_headers=amz_headers, body_producer=body_producer,
149+ receiver_factory=self.receiver_factory)
150 return query.submit()
151
152 def copy_object(self, source_bucket, source_object_name, dest_bucket=None,
153@@ -344,7 +355,8 @@
154 query = self.query_factory(
155 action="PUT", creds=self.creds, endpoint=self.endpoint,
156 bucket=dest_bucket, object_name=dest_object_name,
157- metadata=metadata, amz_headers=amz_headers)
158+ metadata=metadata, amz_headers=amz_headers,
159+ receiver_factory=self.receiver_factory)
160 return query.submit()
161
162 def get_object(self, bucket, object_name):
163@@ -353,7 +365,8 @@
164 """
165 query = self.query_factory(
166 action="GET", creds=self.creds, endpoint=self.endpoint,
167- bucket=bucket, object_name=object_name)
168+ bucket=bucket, object_name=object_name,
169+ receiver_factory=self.receiver_factory)
170 return query.submit()
171
172 def head_object(self, bucket, object_name):
173@@ -384,7 +397,8 @@
174 data = access_control_policy.to_xml()
175 query = self.query_factory(
176 action='PUT', creds=self.creds, endpoint=self.endpoint,
177- bucket=bucket, object_name='%s?acl' % object_name, data=data)
178+ bucket=bucket, object_name='%s?acl' % object_name, data=data,
179+ receiver_factory=self.receiver_factory)
180 return query.submit().addCallback(self._parse_acl)
181
182 def get_object_acl(self, bucket, object_name):
183@@ -393,7 +407,8 @@
184 """
185 query = self.query_factory(
186 action='GET', creds=self.creds, endpoint=self.endpoint,
187- bucket=bucket, object_name='%s?acl' % object_name)
188+ bucket=bucket, object_name='%s?acl' % object_name,
189+ receiver_factory=self.receiver_factory)
190 return query.submit().addCallback(self._parse_acl)
191
192 def put_request_payment(self, bucket, payer):
193@@ -407,7 +422,8 @@
194 data = RequestPayment(payer).to_xml()
195 query = self.query_factory(
196 action="PUT", creds=self.creds, endpoint=self.endpoint,
197- bucket=bucket, object_name="?requestPayment", data=data)
198+ bucket=bucket, object_name="?requestPayment", data=data,
199+ receiver_factory=self.receiver_factory)
200 return query.submit()
201
202 def get_request_payment(self, bucket):
203@@ -419,7 +435,8 @@
204 """
205 query = self.query_factory(
206 action="GET", creds=self.creds, endpoint=self.endpoint,
207- bucket=bucket, object_name="?requestPayment")
208+ bucket=bucket, object_name="?requestPayment",
209+ receiver_factory=self.receiver_factory)
210 return query.submit().addCallback(self._parse_get_request_payment)
211
212 def _parse_get_request_payment(self, xml_bytes):
213@@ -434,12 +451,13 @@
214 """A query for submission to the S3 service."""
215
216 def __init__(self, bucket=None, object_name=None, data="",
217- content_type=None, metadata={}, amz_headers={}, *args,
218- **kwargs):
219+ content_type=None, metadata={}, amz_headers={},
220+ body_producer=None, *args, **kwargs):
221 super(Query, self).__init__(*args, **kwargs)
222 self.bucket = bucket
223 self.object_name = object_name
224 self.data = data
225+ self.body_producer = body_producer
226 self.content_type = content_type
227 self.metadata = metadata
228 self.amz_headers = amz_headers
229@@ -463,9 +481,14 @@
230 """
231 Build the list of headers needed in order to perform S3 operations.
232 """
233- headers = {"Content-Length": len(self.data),
234- "Content-MD5": calculate_md5(self.data),
235+ if self.body_producer:
236+ content_length = self.body_producer.length
237+ else:
238+ content_length = len(self.data)
239+ headers = {"Content-Length": content_length,
240 "Date": self.date}
241+ if self.body_producer is None:
242+ headers["Content-MD5"] = calculate_md5(self.data)
243 for key, value in self.metadata.iteritems():
244 headers["x-amz-meta-" + key] = value
245 for key, value in self.amz_headers.iteritems():
246@@ -529,5 +552,6 @@
247 self.endpoint, self.bucket, self.object_name)
248 d = self.get_page(
249 url_context.get_url(), method=self.action, postdata=self.data,
250- headers=self.get_headers())
251+ headers=self.get_headers(), body_producer=self.body_producer,
252+ receiver_factory=self.receiver_factory)
253 return d.addErrback(s3_error_wrapper)
254
255=== modified file 'txaws/s3/tests/test_client.py'
256--- txaws/s3/tests/test_client.py 2012-01-28 00:44:53 +0000
257+++ txaws/s3/tests/test_client.py 2012-04-14 16:36:18 +0000
258@@ -10,6 +10,7 @@
259 s3clientSkip = None
260 from txaws.s3.acls import AccessControlPolicy
261 from txaws.s3.model import RequestPayment
262+from txaws.testing.producers import StringBodyProducer
263 from txaws.service import AWSServiceEndpoint
264 from txaws.testing import payload
265 from txaws.testing.base import TXAWSTestCase
266@@ -100,7 +101,8 @@
267
268 class StubQuery(client.Query):
269
270- def __init__(query, action, creds, endpoint):
271+ def __init__(query, action, creds, endpoint,
272+ body_producer=None, receiver_factory=None):
273 super(StubQuery, query).__init__(
274 action=action, creds=creds)
275 self.assertEquals(action, "GET")
276@@ -134,7 +136,8 @@
277
278 class StubQuery(client.Query):
279
280- def __init__(query, action, creds, endpoint, bucket=None):
281+ def __init__(query, action, creds, endpoint, bucket=None,
282+ body_producer=None, receiver_factory=None):
283 super(StubQuery, query).__init__(
284 action=action, creds=creds, bucket=bucket)
285 self.assertEquals(action, "PUT")
286@@ -156,7 +159,8 @@
287
288 class StubQuery(client.Query):
289
290- def __init__(query, action, creds, endpoint, bucket=None):
291+ def __init__(query, action, creds, endpoint, bucket=None,
292+ body_producer=None, receiver_factory=None):
293 super(StubQuery, query).__init__(
294 action=action, creds=creds, bucket=bucket)
295 self.assertEquals(action, "GET")
296@@ -208,7 +212,8 @@
297 class StubQuery(client.Query):
298
299 def __init__(query, action, creds, endpoint, bucket=None,
300- object_name=None):
301+ object_name=None, body_producer=None,
302+ receiver_factory=None):
303 super(StubQuery, query).__init__(action=action, creds=creds,
304 bucket=bucket,
305 object_name=object_name)
306@@ -243,7 +248,8 @@
307 class StubQuery(client.Query):
308
309 def __init__(query, action, creds, endpoint, bucket=None,
310- object_name=None):
311+ object_name=None, body_producer=None,
312+ receiver_factory=None):
313 super(StubQuery, query).__init__(action=action, creds=creds,
314 bucket=bucket,
315 object_name=object_name)
316@@ -284,7 +290,8 @@
317 class StubQuery(client.Query):
318
319 def __init__(query, action, creds, endpoint, bucket=None,
320- object_name=None):
321+ object_name=None, body_producer=None,
322+ receiver_factory=None):
323 super(StubQuery, query).__init__(action=action, creds=creds,
324 bucket=bucket,
325 object_name=object_name)
326@@ -323,7 +330,8 @@
327 class StubQuery(client.Query):
328
329 def __init__(query, action, creds, endpoint, bucket=None,
330- object_name=None):
331+ object_name=None, body_producer=None,
332+ receiver_factory=None):
333 super(StubQuery, query).__init__(action=action, creds=creds,
334 bucket=bucket,
335 object_name=object_name)
336@@ -360,7 +368,8 @@
337 class StubQuery(client.Query):
338
339 def __init__(query, action, creds, endpoint, bucket=None,
340- object_name=None):
341+ object_name=None, body_producer=None,
342+ receiver_factory=None):
343 super(StubQuery, query).__init__(action=action, creds=creds,
344 bucket=bucket,
345 object_name=object_name)
346@@ -396,7 +405,8 @@
347 class StubQuery(client.Query):
348
349 def __init__(query, action, creds, endpoint, bucket=None,
350- object_name=None):
351+ object_name=None, body_producer=None,
352+ receiver_factory=None):
353 super(StubQuery, query).__init__(action=action, creds=creds,
354 bucket=bucket,
355 object_name=object_name)
356@@ -433,7 +443,8 @@
357 class StubQuery(client.Query):
358
359 def __init__(query, action, creds, endpoint, bucket=None,
360- object_name=None):
361+ object_name=None, body_producer=None,
362+ receiver_factory=None):
363 super(StubQuery, query).__init__(action=action, creds=creds,
364 bucket=bucket,
365 object_name=object_name)
366@@ -473,7 +484,8 @@
367 class StubQuery(client.Query):
368
369 def __init__(query, action, creds, endpoint, bucket=None,
370- object_name=None):
371+ object_name=None, body_producer=None,
372+ receiver_factory=None):
373 super(StubQuery, query).__init__(action=action, creds=creds,
374 bucket=bucket,
375 object_name=object_name)
376@@ -509,7 +521,8 @@
377 class StubQuery(client.Query):
378
379 def __init__(query, action, creds, endpoint, bucket=None,
380- object_name=None):
381+ object_name=None, body_producer=None,
382+ receiver_factory=None):
383 super(StubQuery, query).__init__(action=action, creds=creds,
384 bucket=bucket,
385 object_name=object_name)
386@@ -546,7 +559,8 @@
387 class StubQuery(client.Query):
388
389 def __init__(query, action, creds, endpoint, bucket=None,
390- object_name=None):
391+ object_name=None, body_producer=None,
392+ receiver_factory=None):
393 super(StubQuery, query).__init__(action=action, creds=creds,
394 bucket=bucket,
395 object_name=object_name)
396@@ -576,7 +590,8 @@
397
398 class StubQuery(client.Query):
399
400- def __init__(query, action, creds, endpoint, bucket=None):
401+ def __init__(query, action, creds, endpoint, bucket=None,
402+ body_producer=None, receiver_factory=None):
403 super(StubQuery, query).__init__(
404 action=action, creds=creds, bucket=bucket)
405 self.assertEquals(action, "DELETE")
406@@ -599,7 +614,8 @@
407 class StubQuery(client.Query):
408
409 def __init__(query, action, creds, endpoint, bucket=None,
410- object_name=None, data=""):
411+ object_name=None, data="", body_producer=None,
412+ receiver_factory=None):
413 super(StubQuery, query).__init__(action=action, creds=creds,
414 bucket=bucket,
415 object_name=object_name,
416@@ -630,7 +646,8 @@
417 class StubQuery(client.Query):
418
419 def __init__(query, action, creds, endpoint, bucket=None,
420- object_name=None, data=""):
421+ object_name=None, data="", receiver_factory=None,
422+ body_producer=None):
423 super(StubQuery, query).__init__(action=action, creds=creds,
424 bucket=bucket,
425 object_name=object_name,
426@@ -665,7 +682,7 @@
427
428 def __init__(query, action, creds, endpoint, bucket=None,
429 object_name=None, data=None, content_type=None,
430- metadata=None):
431+ metadata=None, body_producer=None, receiver_factory=None):
432 super(StubQuery, query).__init__(
433 action=action, creds=creds, bucket=bucket,
434 object_name=object_name, data=data,
435@@ -701,7 +718,7 @@
436
437 def __init__(query, action, creds, endpoint, bucket=None,
438 object_name=None, data=None, content_type=None,
439- metadata=None):
440+ metadata=None, body_producer=None, receiver_factory=None):
441 super(StubQuery, query).__init__(
442 action=action, creds=creds, bucket=bucket,
443 object_name=object_name, data=data,
444@@ -730,7 +747,8 @@
445
446 def __init__(query, action, creds, endpoint, bucket=None,
447 object_name=None, data=None, content_type=None,
448- metadata=None, amz_headers=None):
449+ metadata=None, amz_headers=None, body_producer=None,
450+ receiver_factory=None):
451 super(StubQuery, query).__init__(
452 action=action, creds=creds, bucket=bucket,
453 object_name=object_name, data=data,
454@@ -756,6 +774,42 @@
455 metadata={"key": "some meta data"},
456 amz_headers={"acl": "public-read"})
457
458+ def test_put_object_with_custom_body_producer(self):
459+
460+ class StubQuery(client.Query):
461+
462+ def __init__(query, action, creds, endpoint, bucket=None,
463+ object_name=None, data=None, content_type=None,
464+ metadata=None, amz_headers=None, body_producer=None,
465+ receiver_factory=None):
466+ super(StubQuery, query).__init__(
467+ action=action, creds=creds, bucket=bucket,
468+ object_name=object_name, data=data,
469+ content_type=content_type, metadata=metadata,
470+ amz_headers=amz_headers, body_producer=body_producer)
471+ self.assertEqual(action, "PUT")
472+ self.assertEqual(creds.access_key, "foo")
473+ self.assertEqual(creds.secret_key, "bar")
474+ self.assertEqual(query.bucket, "mybucket")
475+ self.assertEqual(query.object_name, "objectname")
476+ self.assertEqual(query.content_type, "text/plain")
477+ self.assertEqual(query.metadata, {"key": "some meta data"})
478+ self.assertEqual(query.amz_headers, {"acl": "public-read"})
479+ self.assertIdentical(body_producer, string_producer)
480+
481+ def submit(query):
482+ return succeed(None)
483+
484+
485+ string_producer = StringBodyProducer("some data")
486+ creds = AWSCredentials("foo", "bar")
487+ s3 = client.S3Client(creds, query_factory=StubQuery)
488+ return s3.put_object("mybucket", "objectname",
489+ content_type="text/plain",
490+ metadata={"key": "some meta data"},
491+ amz_headers={"acl": "public-read"},
492+ body_producer=string_producer)
493+
494 def test_copy_object(self):
495 """
496 L{S3Client.copy_object} creates a L{Query} to copy an object from one
497@@ -766,7 +820,8 @@
498
499 def __init__(query, action, creds, endpoint, bucket=None,
500 object_name=None, data=None, content_type=None,
501- metadata=None, amz_headers=None):
502+ metadata=None, amz_headers=None, body_producer=None,
503+ receiver_factory=None):
504 super(StubQuery, query).__init__(
505 action=action, creds=creds, bucket=bucket,
506 object_name=object_name, data=data,
507@@ -798,7 +853,8 @@
508
509 def __init__(query, action, creds, endpoint, bucket=None,
510 object_name=None, data=None, content_type=None,
511- metadata=None, amz_headers=None):
512+ metadata=None, amz_headers=None, body_producer=None,
513+ receiver_factory=None):
514 super(StubQuery, query).__init__(
515 action=action, creds=creds, bucket=bucket,
516 object_name=object_name, data=data,
517@@ -822,7 +878,7 @@
518
519 def __init__(query, action, creds, endpoint, bucket=None,
520 object_name=None, data=None, content_type=None,
521- metadata=None):
522+ metadata=None, body_producer=None, receiver_factory=None):
523 super(StubQuery, query).__init__(
524 action=action, creds=creds, bucket=bucket,
525 object_name=object_name, data=data,
526@@ -846,7 +902,7 @@
527
528 def __init__(query, action, creds, endpoint, bucket=None,
529 object_name=None, data=None, content_type=None,
530- metadata=None):
531+ metadata=None, body_producer=None, receiver_factory=None):
532 super(StubQuery, query).__init__(
533 action=action, creds=creds, bucket=bucket,
534 object_name=object_name, data=data,
535@@ -869,7 +925,8 @@
536 class StubQuery(client.Query):
537
538 def __init__(query, action, creds, endpoint, bucket=None,
539- object_name=None, data=""):
540+ object_name=None, data="", body_producer=None,
541+ receiver_factory=None):
542 super(StubQuery, query).__init__(action=action, creds=creds,
543 bucket=bucket,
544 object_name=object_name,
545@@ -902,7 +959,8 @@
546 class StubQuery(client.Query):
547
548 def __init__(query, action, creds, endpoint, bucket=None,
549- object_name=None, data=""):
550+ object_name=None, data="", body_producer=None,
551+ receiver_factory=None):
552 super(StubQuery, query).__init__(action=action, creds=creds,
553 bucket=bucket,
554 object_name=object_name,
555@@ -1077,7 +1135,8 @@
556 """
557 class StubQuery(client.Query):
558
559- def __init__(query, action, creds, endpoint, bucket):
560+ def __init__(query, action, creds, endpoint, bucket,
561+ body_producer=None, receiver_factory=None):
562 super(StubQuery, query).__init__(
563 action=action, creds=creds, bucket=bucket)
564 self.assertEquals(action, "GET")

Subscribers

People subscribed via source and target branches