smore-inc/tinys3 — pull request #32 by Scylardor (2014-08-06 15:34:36+00:00)
Title: Merge multipart uploads

I implemented the multipart uploads in tinys3, I currently use them in my application and they work well.

A quick tour on how to use them if you would like to test:

- Create a multipart upload:
```
co = tinys3.Connection('key', 'secret', 'bucket', tls=True)
mp_upload = co.initiate_multipart_upload(key='test', bucket='bucket') # bucket is optional
```

`initiate_multipart_upload` returns a MultipartUpload object bound to the connection it comes from, and it works quite like the Boto one.

- Upload a part:
```
resp = mp_upload.upload_part_from_file(fp, 1)
```

`upload_part_from_file` returns the requests response. It can take a length and md5 parameters that will be put in the request's `Content-Length` and `Content-MD5` headers, and also the file handling parameters (close, rewind) UploadRequest already takes and that do the same thing.

- Complete the upload:
```
resp = mp_upload.complete_upload()
```

`complete_upload` returns the requests response.

- Abort the upload:
```
mp_upload.cancel_upload()
```
`cancel_upload` returns the requests response.

- List a bucket's multipart uploads:
```
for mp in co.list_multipart_uploads():
print mp.bucket, mp.key, mp.uploadId
```

- List a multipart upload's already uploaded parts:
```
for p in mp.list_parts():
print p['part_number'], p[last_modified], p['size'], p['etag']
```

However, I also made a number of changes in the rest of the project, here are some notes :

- Since I tried as much as possible to comply to PEP8, a lot of formatting has changed. I hope it won't bother (but PEP8 compliance is cool)

- I updated of the AWS_QUERY_PARAMS for multipart upload requests to work

- It turned out that sorting the query string keys in low-level request signature method was necessary

- I changed all the format strings from the "str % format" version to string.format version, for PEP8

- Since I need to use the GET request's Range header, I added an headers param to S3Connection.get()

- Also added some parameters to the list function

- Created the XML_PARSE_STRING global as it is used at a lot of places in the code (more maintainable)

- Changed the request URL in bucket_url from region-based to virtual-hosting style

- I added the DeleteRequest and HeadRequest classes.