Merge lp:~oubiwann/txaws/413738-method-name-cleanup into lp:~txawsteam/txaws/trunk

Proposed by Duncan McGreggor
Status: Merged
Merge reported by: Duncan McGreggor
Merged at revision: not available
Proposed branch: lp:~oubiwann/txaws/413738-method-name-cleanup
Merge into: lp:~txawsteam/txaws/trunk
Diff against target: None lines
To merge this branch: bzr merge lp:~oubiwann/txaws/413738-method-name-cleanup
Reviewer Review Type Date Requested Status
Robert Collins (community) Needs Fixing
Jamu Kakar Pending
Thomas Herve Pending
Review via email: mp+10245@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Duncan McGreggor (oubiwann) wrote :

This is ready for review. The PEP-8 path was chosen instead of the Twisted coding standard.

Revision history for this message
Robert Collins (lifeless) wrote :

On Mon, 2009-08-17 at 13:00 +0000, Duncan McGreggor wrote:
>
> +from txaws.util import XML, calculate_md5
> from txaws.credentials import AWSCredentials
> -from txaws.util import XML

PEP8 mandates sorting this:
from txaws.credentials should be the first line.

> +
> +
> +NS = '{http://s3.amazonaws.com/doc/2006-03-01/}'

Rather than NS, perhaps name_space.

> class S3Request(object):
> - def __init__(self, verb, bucket=None, objectName=None, data='',
> - contentType=None, metadata={},
> rootURI='https://s3.amazonaws.com',
> - creds=None):
> +
> + def __init__(
> + self, verb, bucket=None, object_name=None, data='',
> content_type=None,
> + metadata={}, root_uri='https://s3.amazonaws.com',
> creds=None):

I believe PEP-8 allows the style of wrapping that was in use before - I
won't insist either way, but I do fine using as much of the line as
possible nicer. e.g
def __init__(self, verb, bucket, object_name, data,
    content_type, metadata):

> === modified file 'txaws/storage/test/test_client.py'
> --- txaws/storage/test/test_client.py 2009-04-26 08:32:36 +0000
> +++ txaws/storage/test/test_client.py 2009-08-17 12:49:40 +0000
> @@ -4,17 +4,21 @@
>
> from twisted.internet.defer import succeed

c,s,t,u - sorting :) on the import lines below.

> +from txaws.util import calculate_md5
> +from txaws.tests import TXAWSTestCase
> from txaws.credentials import AWSCredentials
> -from txaws.tests import TXAWSTestCase
> -from txaws.storage.client import S3, S3Request, calculateMD5
> +from txaws.storage.client import S3, S3Request
> +
>

> === modified file 'txaws/util.py'
> --- txaws/util.py 2009-04-27 08:53:11 +0000
> +++ txaws/util.py 2009-08-17 12:49:40 +0000
> @@ -6,16 +6,23 @@
>
> __all__ = ['hmac_sha1', 'iso8601time']

and here too.

> +import time
> +import hmac
> +from hashlib import sha1, md5
> from base64 import b64encode
> -from hashlib import sha1
> -import hmac
> -import time
> +

 review needsfixing

review: Needs Fixing
7. By Duncan McGreggor

Replaced NS with name_space (lifeless 2).

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

> On Mon, 2009-08-17 at 13:00 +0000, Duncan McGreggor wrote:
> >
> > +from txaws.util import XML, calculate_md5
> > from txaws.credentials import AWSCredentials
> > -from txaws.util import XML
>
> PEP8 mandates sorting this:
> from txaws.credentials should be the first line.

[1]

So PEP-8 states the following:

      1. standard library imports
      2. related third party imports
      3. local application/library specific imports

Both lines are local application, and there's no further specification on sorting those, is there? Or am I missing something?

> > +
> > +
> > +NS = '{http://s3.amazonaws.com/doc/2006-03-01/}'
>
> Rather than NS, perhaps name_space.

[2]

Good idea -- done.

> > class S3Request(object):
> > - def __init__(self, verb, bucket=None, objectName=None, data='',
> > - contentType=None, metadata={},
> > rootURI='https://s3.amazonaws.com',
> > - creds=None):
> > +
> > + def __init__(
> > + self, verb, bucket=None, object_name=None, data='',
> > content_type=None,
> > + metadata={}, root_uri='https://s3.amazonaws.com',
> > creds=None):
>
> I believe PEP-8 allows the style of wrapping that was in use before - I
> won't insist either way, but I do fine using as much of the line as
> possible nicer. e.g
>
> def __init__(self, verb, bucket, object_name, data,
> content_type, metadata):

[3]

I don't think that's PEP-8, but I may be misreading the PEP. If you take a look at the section that starts with "The preferred way of wrapping long lines..." and the example code below that, they wrap to the point where the parens of the contained code starts, not a 4-space indent (I was actually only made aware of this last year).

I compromised, and re-wrapped like this:

    def __init__(self, verb, bucket, object_name, data,
                 content_type, metadata):

> > === modified file 'txaws/storage/test/test_client.py'
> > --- txaws/storage/test/test_client.py 2009-04-26 08:32:36 +0000
> > +++ txaws/storage/test/test_client.py 2009-08-17 12:49:40 +0000
> > @@ -4,17 +4,21 @@
> >
> > from twisted.internet.defer import succeed
>
> c,s,t,u - sorting :) on the import lines below.
>
> > +from txaws.util import calculate_md5
> > +from txaws.tests import TXAWSTestCase
> > from txaws.credentials import AWSCredentials
> > -from txaws.tests import TXAWSTestCase
> > -from txaws.storage.client import S3, S3Request, calculateMD5
> > +from txaws.storage.client import S3, S3Request
> > +

[4]

Again, same question about the ordering... can you be more specific about what part of PEP-8 I'm missing? Thanks!

> > === modified file 'txaws/util.py'
> > --- txaws/util.py 2009-04-27 08:53:11 +0000
> > +++ txaws/util.py 2009-08-17 12:49:40 +0000
> > @@ -6,16 +6,23 @@
> >
> > __all__ = ['hmac_sha1', 'iso8601time']
>
> and here too.
>
> > +import time
> > +import hmac
> > +from hashlib import sha1, md5
> > from base64 import b64encode
> > -from hashlib import sha1
> > -import hmac
> > -import time
> > +
>
>
> review needsfixing

[5]

Ditto ;-)

8. By Duncan McGreggor

Re-wrapped the __init__ method signature in an alternative PEP-8 compliant
manner (lifeless 3).

Revision history for this message
Robert Collins (lifeless) wrote :

On Tue, 2009-08-18 at 17:48 +0000, Duncan McGreggor wrote:
>
> [1]
>
> So PEP-8 states the following:
>
> 1. standard library imports
> 2. related third party imports
> 3. local application/library specific imports
>
> Both lines are local application, and there's no further specification
> on sorting those, is there? Or am I missing something?

Oh hmm, its a bzr convention. But its very useful, reduces merge
conflicts and makes coffee!

-Rob

9. By Duncan McGreggor

Merged from trunk and resolved conflicts.

10. By Duncan McGreggor

Renamed NS variable in s3 to name_space.

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

Hey Rob, you've got your review labeled as "needs fixing" -- is that still the case?

Thanks!

11. By Duncan McGreggor

Merged from trunk.

Revision history for this message
Robert Collins (lifeless) wrote :

Uhm, I'm not sure :)

The only remaining thing was import sorting. I don't think you replied
to my reply on that.

-Rob

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

On Wed, Aug 19, 2009 at 10:46 PM, Robert
Collins<email address hidden> wrote:
> Uhm, I'm not sure :)
>
> The only remaining thing was import sorting. I don't think you replied
> to my reply on that.

Hrm, well I don't know what you're sorting one... can you explain it?

d

Revision history for this message
Robert Collins (lifeless) wrote :

On Thu, 2009-08-20 at 02:06 +0000, Duncan McGreggor wrote:
> On Wed, Aug 19, 2009 at 10:46 PM, Robert
> Collins<email address hidden> wrote:
> > Uhm, I'm not sure :)
> >
> > The only remaining thing was import sorting. I don't think you replied
> > to my reply on that.
>
> Hrm, well I don't know what you're sorting one... can you explain it?

the module name, and the item.

from foo import bar
from gam import alpha, beta
from gam.quux import zulu

is well sorted.

Why does sorting matter? It reduces merge conflicts - a lot. Because
when people add the same import they'll do so at the same line, and
different imports will be spread out rather than all at the bottom.

-Rob

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

On Wed, Aug 19, 2009 at 11:04 PM, Duncan McGreggor<email address hidden> wrote:
> On Wed, Aug 19, 2009 at 10:46 PM, Robert
> Collins<email address hidden> wrote:
>> Uhm, I'm not sure :)
>>
>> The only remaining thing was import sorting. I don't think you replied
>> to my reply on that.
>
> Hrm, well I don't know what you're sorting one... can you explain it?

Er, sorting *on* :-)

d

12. By Duncan McGreggor

Sorted import alphabetically (lifeless).

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

> On Thu, 2009-08-20 at 02:06 +0000, Duncan McGreggor wrote:
> > On Wed, Aug 19, 2009 at 10:46 PM, Robert
> > Collins<email address hidden> wrote:
> > > Uhm, I'm not sure :)
> > >
> > > The only remaining thing was import sorting. I don't think you replied
> > > to my reply on that.
> >
> > Hrm, well I don't know what you're sorting one... can you explain it?
>
> the module name, and the item.
>
> from foo import bar
> from gam import alpha, beta
> from gam.quux import zulu
>
> is well sorted.
>
> Why does sorting matter? It reduces merge conflicts - a lot. Because
> when people add the same import they'll do so at the same line, and
> different imports will be spread out rather than all at the bottom.
>
> -Rob

Awesome. Thanks for the breakdown on that.

I've updated the imports accordingly and pushed.

13. By Duncan McGreggor

Renamed storage sub-package's test directory to be consistent with the rest of
txAWS' tests directories.

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

A quick ping on this branch... I've got dependent branches starting to pile up...

Thanks!

Revision history for this message
Robert Collins (lifeless) wrote :

in which case,
review +1

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

> in which case,
> review +1

Thanks!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'txaws/storage/client.py'
--- txaws/storage/client.py 2009-04-27 08:53:11 +0000
+++ txaws/storage/client.py 2009-08-17 12:49:40 +0000
@@ -7,111 +7,107 @@
7functionality in this wrapper.7functionality in this wrapper.
8"""8"""
99
10
11from hashlib import md510from hashlib import md5
12from base64 import b64encode11from base64 import b64encode
1312
14
15from epsilon.extime import Time13from epsilon.extime import Time
1614
17from twisted.web.client import getPage15from twisted.web.client import getPage
18from twisted.web.http import datetimeToString16from twisted.web.http import datetimeToString
1917
18from txaws.util import XML, calculate_md5
20from txaws.credentials import AWSCredentials19from txaws.credentials import AWSCredentials
21from txaws.util import XML20
2221
2322NS = '{http://s3.amazonaws.com/doc/2006-03-01/}'
24def calculateMD5(data):
25 digest = md5(data).digest()
26 return b64encode(digest)
2723
2824
29class S3Request(object):25class S3Request(object):
30 def __init__(self, verb, bucket=None, objectName=None, data='',26
31 contentType=None, metadata={}, rootURI='https://s3.amazonaws.com',27 def __init__(
32 creds=None):28 self, verb, bucket=None, object_name=None, data='', content_type=None,
29 metadata={}, root_uri='https://s3.amazonaws.com', creds=None):
33 self.verb = verb30 self.verb = verb
34 self.bucket = bucket31 self.bucket = bucket
35 self.objectName = objectName32 self.object_name = object_name
36 self.data = data33 self.data = data
37 self.contentType = contentType34 self.content_type = content_type
38 self.metadata = metadata35 self.metadata = metadata
39 self.rootURI = rootURI36 self.root_uri = root_uri
40 self.creds = creds37 self.creds = creds
41 self.date = datetimeToString()38 self.date = datetimeToString()
4239
43 def getURIPath(self):40 def get_uri_path(self):
44 path = '/'41 path = '/'
45 if self.bucket is not None:42 if self.bucket is not None:
46 path += self.bucket43 path += self.bucket
47 if self.objectName is not None:44 if self.object_name is not None:
48 path += '/' + self.objectName45 path += '/' + self.object_name
49 return path46 return path
5047
51 def getURI(self):48 def get_uri(self):
52 return self.rootURI + self.getURIPath()49 return self.root_uri + self.get_uri_path()
5350
54 def getHeaders(self):51 def get_headers(self):
55 headers = {'Content-Length': len(self.data),52 headers = {'Content-Length': len(self.data),
56 'Content-MD5': calculateMD5(self.data),53 'Content-MD5': calculate_md5(self.data),
57 'Date': self.date}54 'Date': self.date}
5855
59 for key, value in self.metadata.iteritems():56 for key, value in self.metadata.iteritems():
60 headers['x-amz-meta-' + key] = value57 headers['x-amz-meta-' + key] = value
6158
62 if self.contentType is not None:59 if self.content_type is not None:
63 headers['Content-Type'] = self.contentType60 headers['Content-Type'] = self.content_type
6461
65 if self.creds is not None:62 if self.creds is not None:
66 signature = self.getSignature(headers)63 signature = self.get_signature(headers)
67 headers['Authorization'] = 'AWS %s:%s' % (self.creds.access_key, signature)64 headers['Authorization'] = 'AWS %s:%s' % (self.creds.access_key, signature)
6865
69 return headers66 return headers
7067
71 def getCanonicalizedResource(self):68 def get_canonicalized_resource(self):
72 return self.getURIPath()69 return self.get_uri_path()
7370
74 def getCanonicalizedAmzHeaders(self, headers):71 def get_canonicalized_amz_headers(self, headers):
75 result = ''72 result = ''
76 headers = [(name.lower(), value) for name, value in headers.iteritems() if name.lower().startswith('x-amz-')]73 headers = [(name.lower(), value) for name, value in headers.iteritems() if name.lower().startswith('x-amz-')]
77 headers.sort()74 headers.sort()
78 return ''.join('%s:%s\n' % (name, value) for name, value in headers)75 return ''.join('%s:%s\n' % (name, value) for name, value in headers)
7976
80 def getSignature(self, headers):77 def get_signature(self, headers):
81 text = self.verb + '\n'78 text = self.verb + '\n'
82 text += headers.get('Content-MD5', '') + '\n'79 text += headers.get('Content-MD5', '') + '\n'
83 text += headers.get('Content-Type', '') + '\n'80 text += headers.get('Content-Type', '') + '\n'
84 text += headers.get('Date', '') + '\n'81 text += headers.get('Date', '') + '\n'
85 text += self.getCanonicalizedAmzHeaders(headers)82 text += self.get_canonicalized_amz_headers(headers)
86 text += self.getCanonicalizedResource()83 text += self.get_canonicalized_resource()
87 return self.creds.sign(text)84 return self.creds.sign(text)
8885
89 def submit(self):86 def submit(self):
90 return self.getPage(url=self.getURI(), method=self.verb, postdata=self.data, headers=self.getHeaders())87 return self.get_page(url=self.get_uri(), method=self.verb, postdata=self.data, headers=self.get_headers())
9188
92 def getPage(self, *a, **kw):89 def get_page(self, *a, **kw):
93 return getPage(*a, **kw)90 return getPage(*a, **kw)
9491
9592
96NS = '{http://s3.amazonaws.com/doc/2006-03-01/}'
97
98class S3(object):93class S3(object):
99 rootURI = 'https://s3.amazonaws.com/'94
100 requestFactory = S3Request95 root_uri = 'https://s3.amazonaws.com/'
96 request_factory = S3Request
10197
102 def __init__(self, creds):98 def __init__(self, creds):
103 self.creds = creds99 self.creds = creds
104100
105 def makeRequest(self, *a, **kw):101 def make_request(self, *a, **kw):
106 """102 """
107 Create a request with the arguments passed in.103 Create a request with the arguments passed in.
108104
109 This uses the requestFactory attribute, adding the credentials to the105 This uses the request_factory attribute, adding the credentials to the
110 arguments passed in.106 arguments passed in.
111 """107 """
112 return self.requestFactory(creds=self.creds, *a, **kw)108 return self.request_factory(creds=self.creds, *a, **kw)
113109
114 def _parseBucketList(self, response):110 def _parse_bucket_list(self, response):
115 """111 """
116 Parse XML bucket list response.112 Parse XML bucket list response.
117 """113 """
@@ -120,57 +116,57 @@
120 yield {'name': bucket.findtext(NS + 'Name'),116 yield {'name': bucket.findtext(NS + 'Name'),
121 'created': Time.fromISO8601TimeAndDate(bucket.findtext(NS + 'CreationDate'))}117 'created': Time.fromISO8601TimeAndDate(bucket.findtext(NS + 'CreationDate'))}
122118
123 def listBuckets(self):119 def list_buckets(self):
124 """120 """
125 List all buckets.121 List all buckets.
126122
127 Returns a list of all the buckets owned by the authenticated sender of123 Returns a list of all the buckets owned by the authenticated sender of
128 the request.124 the request.
129 """125 """
130 return self.makeRequest('GET').submit().addCallback(self._parseBucketList)126 return self.make_request('GET').submit().addCallback(self._parse_bucket_list)
131127
132 def createBucket(self, bucket):128 def create_bucket(self, bucket):
133 """129 """
134 Create a new bucket.130 Create a new bucket.
135 """131 """
136 return self.makeRequest('PUT', bucket).submit()132 return self.make_request('PUT', bucket).submit()
137133
138 def deleteBucket(self, bucket):134 def delete_bucket(self, bucket):
139 """135 """
140 Delete a bucket.136 Delete a bucket.
141137
142 The bucket must be empty before it can be deleted.138 The bucket must be empty before it can be deleted.
143 """139 """
144 return self.makeRequest('DELETE', bucket).submit()140 return self.make_request('DELETE', bucket).submit()
145141
146 def putObject(self, bucket, objectName, data, contentType=None, metadata={}):142 def put_object(self, bucket, object_name, data, content_type=None, metadata={}):
147 """143 """
148 Put an object in a bucket.144 Put an object in a bucket.
149145
150 Any existing object of the same name will be replaced.146 Any existing object of the same name will be replaced.
151 """147 """
152 return self.makeRequest('PUT', bucket, objectName, data, contentType, metadata).submit()148 return self.make_request('PUT', bucket, object_name, data, content_type, metadata).submit()
153149
154 def getObject(self, bucket, objectName):150 def get_object(self, bucket, object_name):
155 """151 """
156 Get an object from a bucket.152 Get an object from a bucket.
157 """153 """
158 return self.makeRequest('GET', bucket, objectName).submit()154 return self.make_request('GET', bucket, object_name).submit()
159155
160 def headObject(self, bucket, objectName):156 def head_object(self, bucket, object_name):
161 """157 """
162 Retrieve object metadata only.158 Retrieve object metadata only.
163159
164 This is like getObject, but the object's content is not retrieved.160 This is like get_object, but the object's content is not retrieved.
165 Currently the metadata is not returned to the caller either, so this161 Currently the metadata is not returned to the caller either, so this
166 method is mostly useless, and only provided for completeness.162 method is mostly useless, and only provided for completeness.
167 """163 """
168 return self.makeRequest('HEAD', bucket, objectName).submit()164 return self.make_request('HEAD', bucket, object_name).submit()
169165
170 def deleteObject(self, bucket, objectName):166 def delete_object(self, bucket, object_name):
171 """167 """
172 Delete an object from a bucket.168 Delete an object from a bucket.
173169
174 Once deleted, there is no method to restore or undelete an object.170 Once deleted, there is no method to restore or undelete an object.
175 """171 """
176 return self.makeRequest('DELETE', bucket, objectName).submit()172 return self.make_request('DELETE', bucket, object_name).submit()
177173
=== modified file 'txaws/storage/test/test_client.py'
--- txaws/storage/test/test_client.py 2009-04-26 08:32:36 +0000
+++ txaws/storage/test/test_client.py 2009-08-17 12:49:40 +0000
@@ -4,17 +4,21 @@
44
5from twisted.internet.defer import succeed5from twisted.internet.defer import succeed
66
7from txaws.util import calculate_md5
8from txaws.tests import TXAWSTestCase
7from txaws.credentials import AWSCredentials9from txaws.credentials import AWSCredentials
8from txaws.tests import TXAWSTestCase10from txaws.storage.client import S3, S3Request
9from txaws.storage.client import S3, S3Request, calculateMD511
1012
11class StubbedS3Request(S3Request):13class StubbedS3Request(S3Request):
12 def getPage(self, url, method, postdata, headers):14
15 def get_page(self, url, method, postdata, headers):
13 self.getPageArgs = (url, method, postdata, headers)16 self.getPageArgs = (url, method, postdata, headers)
14 return succeed('')17 return succeed('')
1518
1619
17class RequestTests(TXAWSTestCase):20class RequestTests(TXAWSTestCase):
21
18 creds = AWSCredentials(access_key='0PN5J17HBGZHT7JJ3X82',22 creds = AWSCredentials(access_key='0PN5J17HBGZHT7JJ3X82',
19 secret_key='uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o')23 secret_key='uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o')
2024
@@ -25,10 +29,10 @@
25 DATA = 'objectData'29 DATA = 'objectData'
26 DIGEST = 'zhdB6gwvocWv/ourYUWMxA=='30 DIGEST = 'zhdB6gwvocWv/ourYUWMxA=='
2731
28 request = S3Request('PUT', 'somebucket', 'object/name/here', DATA, contentType='text/plain', metadata={'foo': 'bar'})32 request = S3Request('PUT', 'somebucket', 'object/name/here', DATA, content_type='text/plain', metadata={'foo': 'bar'})
29 self.assertEqual(request.verb, 'PUT')33 self.assertEqual(request.verb, 'PUT')
30 self.assertEqual(request.getURI(), 'https://s3.amazonaws.com/somebucket/object/name/here')34 self.assertEqual(request.get_uri(), 'https://s3.amazonaws.com/somebucket/object/name/here')
31 headers = request.getHeaders()35 headers = request.get_headers()
32 self.assertNotEqual(headers.pop('Date'), '')36 self.assertNotEqual(headers.pop('Date'), '')
33 self.assertEqual(headers,37 self.assertEqual(headers,
34 {'Content-Type': 'text/plain',38 {'Content-Type': 'text/plain',
@@ -45,8 +49,8 @@
4549
46 request = S3Request('GET', 'somebucket')50 request = S3Request('GET', 'somebucket')
47 self.assertEqual(request.verb, 'GET')51 self.assertEqual(request.verb, 'GET')
48 self.assertEqual(request.getURI(), 'https://s3.amazonaws.com/somebucket')52 self.assertEqual(request.get_uri(), 'https://s3.amazonaws.com/somebucket')
49 headers = request.getHeaders()53 headers = request.get_headers()
50 self.assertNotEqual(headers.pop('Date'), '')54 self.assertNotEqual(headers.pop('Date'), '')
51 self.assertEqual(headers,55 self.assertEqual(headers,
52 {'Content-Length': 0,56 {'Content-Length': 0,
@@ -63,10 +67,10 @@
63 self.assertEqual(result, '')67 self.assertEqual(result, '')
6468
65 url, method, postdata, headers = request.getPageArgs69 url, method, postdata, headers = request.getPageArgs
66 self.assertEqual(url, request.getURI())70 self.assertEqual(url, request.get_uri())
67 self.assertEqual(method, request.verb)71 self.assertEqual(method, request.verb)
68 self.assertEqual(postdata, request.data)72 self.assertEqual(postdata, request.data)
69 self.assertEqual(headers, request.getHeaders())73 self.assertEqual(headers, request.get_headers())
7074
71 return request.submit().addCallback(_postCheck)75 return request.submit().addCallback(_postCheck)
7276
@@ -74,7 +78,7 @@
74 req = S3Request('GET', creds=self.creds)78 req = S3Request('GET', creds=self.creds)
75 req.date = 'Wed, 28 Mar 2007 01:29:59 +0000'79 req.date = 'Wed, 28 Mar 2007 01:29:59 +0000'
7680
77 headers = req.getHeaders()81 headers = req.get_headers()
78 self.assertEqual(headers['Authorization'], 'AWS 0PN5J17HBGZHT7JJ3X82:jF7L3z/FTV47vagZzhKupJ9oNig=')82 self.assertEqual(headers['Authorization'], 'AWS 0PN5J17HBGZHT7JJ3X82:jF7L3z/FTV47vagZzhKupJ9oNig=')
7983
8084
@@ -102,13 +106,13 @@
102 """106 """
103 Testable version of S3.107 Testable version of S3.
104108
105 This subclass stubs requestFactory to use InertRequest, making it easy to109 This subclass stubs request_factory to use InertRequest, making it easy to
106 assert things about the requests that are created in response to various110 assert things about the requests that are created in response to various
107 operations.111 operations.
108 """112 """
109 response = None113 response = None
110114
111 def requestFactory(self, *a, **kw):115 def request_factory(self, *a, **kw):
112 req = InertRequest(response=self.response, *a, **kw)116 req = InertRequest(response=self.response, *a, **kw)
113 self._lastRequest = req117 self._lastRequest = req
114 return req118 return req
@@ -143,9 +147,9 @@
143 self.creds = AWSCredentials(access_key='accessKey', secret_key='secretKey')147 self.creds = AWSCredentials(access_key='accessKey', secret_key='secretKey')
144 self.s3 = TestableS3(creds=self.creds)148 self.s3 = TestableS3(creds=self.creds)
145149
146 def test_makeRequest(self):150 def test_make_request(self):
147 """151 """
148 Test that makeRequest passes in the service credentials.152 Test that make_request passes in the service credentials.
149 """153 """
150 marker = object()154 marker = object()
151155
@@ -153,79 +157,79 @@
153 self.assertEqual(kw['creds'], self.creds)157 self.assertEqual(kw['creds'], self.creds)
154 return marker158 return marker
155159
156 self.s3.requestFactory = _cb160 self.s3.request_factory = _cb
157 self.assertIdentical(self.s3.makeRequest('GET'), marker)161 self.assertIdentical(self.s3.make_request('GET'), marker)
158162
159 def test_listBuckets(self):163 def test_list_buckets(self):
160 self.s3.response = samples['ListAllMyBucketsResult']164 self.s3.response = samples['ListAllMyBucketsResult']
161 d = self.s3.listBuckets()165 d = self.s3.list_buckets()
162166
163 req = self.s3._lastRequest167 req = self.s3._lastRequest
164 self.assertTrue(req.submitted)168 self.assertTrue(req.submitted)
165 self.assertEqual(req.verb, 'GET')169 self.assertEqual(req.verb, 'GET')
166 self.assertEqual(req.bucket, None)170 self.assertEqual(req.bucket, None)
167 self.assertEqual(req.objectName, None)171 self.assertEqual(req.object_name, None)
168172
169 def _checkResult(buckets):173 def _check_result(buckets):
170 self.assertEqual(list(buckets),174 self.assertEqual(list(buckets),
171 [{'name': u'quotes',175 [{'name': u'quotes',
172 'created': Time.fromDatetime(datetime(2006, 2, 3, 16, 45, 9))},176 'created': Time.fromDatetime(datetime(2006, 2, 3, 16, 45, 9))},
173 {'name': u'samples',177 {'name': u'samples',
174 'created': Time.fromDatetime(datetime(2006, 2, 3, 16, 41, 58))}])178 'created': Time.fromDatetime(datetime(2006, 2, 3, 16, 41, 58))}])
175 return d.addCallback(_checkResult)179 return d.addCallback(_check_result)
176180
177 def test_createBucket(self):181 def test_create_bucket(self):
178 self.s3.createBucket('foo')182 self.s3.create_bucket('foo')
179 req = self.s3._lastRequest183 req = self.s3._lastRequest
180 self.assertTrue(req.submitted)184 self.assertTrue(req.submitted)
181 self.assertEqual(req.verb, 'PUT')185 self.assertEqual(req.verb, 'PUT')
182 self.assertEqual(req.bucket, 'foo')186 self.assertEqual(req.bucket, 'foo')
183 self.assertEqual(req.objectName, None)187 self.assertEqual(req.object_name, None)
184188
185 def test_deleteBucket(self):189 def test_delete_bucket(self):
186 self.s3.deleteBucket('foo')190 self.s3.delete_bucket('foo')
187 req = self.s3._lastRequest191 req = self.s3._lastRequest
188 self.assertTrue(req.submitted)192 self.assertTrue(req.submitted)
189 self.assertEqual(req.verb, 'DELETE')193 self.assertEqual(req.verb, 'DELETE')
190 self.assertEqual(req.bucket, 'foo')194 self.assertEqual(req.bucket, 'foo')
191 self.assertEqual(req.objectName, None)195 self.assertEqual(req.object_name, None)
192196
193 def test_putObject(self):197 def test_put_object(self):
194 self.s3.putObject('foobucket', 'foo', 'data', 'text/plain', {'foo': 'bar'})198 self.s3.put_object('foobucket', 'foo', 'data', 'text/plain', {'foo': 'bar'})
195 req = self.s3._lastRequest199 req = self.s3._lastRequest
196 self.assertTrue(req.submitted)200 self.assertTrue(req.submitted)
197 self.assertEqual(req.verb, 'PUT')201 self.assertEqual(req.verb, 'PUT')
198 self.assertEqual(req.bucket, 'foobucket')202 self.assertEqual(req.bucket, 'foobucket')
199 self.assertEqual(req.objectName, 'foo')203 self.assertEqual(req.object_name, 'foo')
200 self.assertEqual(req.data, 'data')204 self.assertEqual(req.data, 'data')
201 self.assertEqual(req.contentType, 'text/plain')205 self.assertEqual(req.content_type, 'text/plain')
202 self.assertEqual(req.metadata, {'foo': 'bar'})206 self.assertEqual(req.metadata, {'foo': 'bar'})
203207
204 def test_getObject(self):208 def test_get_object(self):
205 self.s3.getObject('foobucket', 'foo')209 self.s3.get_object('foobucket', 'foo')
206 req = self.s3._lastRequest210 req = self.s3._lastRequest
207 self.assertTrue(req.submitted)211 self.assertTrue(req.submitted)
208 self.assertEqual(req.verb, 'GET')212 self.assertEqual(req.verb, 'GET')
209 self.assertEqual(req.bucket, 'foobucket')213 self.assertEqual(req.bucket, 'foobucket')
210 self.assertEqual(req.objectName, 'foo')214 self.assertEqual(req.object_name, 'foo')
211215
212 def test_headObject(self):216 def test_head_object(self):
213 self.s3.headObject('foobucket', 'foo')217 self.s3.head_object('foobucket', 'foo')
214 req = self.s3._lastRequest218 req = self.s3._lastRequest
215 self.assertTrue(req.submitted)219 self.assertTrue(req.submitted)
216 self.assertEqual(req.verb, 'HEAD')220 self.assertEqual(req.verb, 'HEAD')
217 self.assertEqual(req.bucket, 'foobucket')221 self.assertEqual(req.bucket, 'foobucket')
218 self.assertEqual(req.objectName, 'foo')222 self.assertEqual(req.object_name, 'foo')
219223
220 def test_deleteObject(self):224 def test_delete_object(self):
221 self.s3.deleteObject('foobucket', 'foo')225 self.s3.delete_object('foobucket', 'foo')
222 req = self.s3._lastRequest226 req = self.s3._lastRequest
223 self.assertTrue(req.submitted)227 self.assertTrue(req.submitted)
224 self.assertEqual(req.verb, 'DELETE')228 self.assertEqual(req.verb, 'DELETE')
225 self.assertEqual(req.bucket, 'foobucket')229 self.assertEqual(req.bucket, 'foobucket')
226 self.assertEqual(req.objectName, 'foo')230 self.assertEqual(req.object_name, 'foo')
227231
228232
229class MiscellaneousTests(TXAWSTestCase):233class MiscellaneousTests(TXAWSTestCase):
230 def test_contentMD5(self):234 def test_contentMD5(self):
231 self.assertEqual(calculateMD5('somedata'), 'rvr3UC1SmUw7AZV2NqPN0g==')235 self.assertEqual(calculate_md5('somedata'), 'rvr3UC1SmUw7AZV2NqPN0g==')
232236
=== modified file 'txaws/util.py'
--- txaws/util.py 2009-04-27 08:53:11 +0000
+++ txaws/util.py 2009-08-17 12:49:40 +0000
@@ -6,16 +6,23 @@
66
7__all__ = ['hmac_sha1', 'iso8601time']7__all__ = ['hmac_sha1', 'iso8601time']
88
9import time
10import hmac
11from hashlib import sha1, md5
9from base64 import b64encode12from base64 import b64encode
10from hashlib import sha113
11import hmac
12import time
13# Import XML from somwhere; here in one place to prevent duplication.14# Import XML from somwhere; here in one place to prevent duplication.
14try:15try:
15 from xml.etree.ElementTree import XML16 from xml.etree.ElementTree import XML
16except ImportError:17except ImportError:
17 from elementtree.ElementTree import XML18 from elementtree.ElementTree import XML
1819
20
21def calculate_md5(data):
22 digest = md5(data).digest()
23 return b64encode(digest)
24
25
19def hmac_sha1(secret, data):26def hmac_sha1(secret, data):
20 digest = hmac.new(secret, data, sha1).digest()27 digest = hmac.new(secret, data, sha1).digest()
21 return b64encode(digest)28 return b64encode(digest)

Subscribers

People subscribed via source and target branches