Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accept and pass on a prefix value. #79

Merged
merged 4 commits into from
Aug 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions txaws/newsfragments/78.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
txaws.s3.client.S3Client.get_bucket now accepts a ``prefix`` parameter for selecting a subset of S3 objects.
8 changes: 7 additions & 1 deletion txaws/s3/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ def delete_bucket(self, bucket):
query = self._query_factory(details)
return self._submit(query)

def get_bucket(self, bucket, marker=None, max_keys=None):
def get_bucket(self, bucket, marker=None, max_keys=None, prefix=None):
"""
Get a list of all the objects in a bucket.

Expand All @@ -205,6 +205,10 @@ def get_bucket(self, bucket, marker=None, max_keys=None):
return.
@type max_keys: L{int} or L{NoneType}

@param prefix: If given, indicate that only objects with keys
beginning with this value should be returned.
@type prefix: L{bytes} or L{NoneType}

@return: A L{Deferred} that fires with a L{BucketListing}
describing the result.

Expand All @@ -215,6 +219,8 @@ def get_bucket(self, bucket, marker=None, max_keys=None):
args.append(("marker", marker))
if max_keys is not None:
args.append(("max-keys", "%d" % (max_keys,)))
if prefix is not None:
args.append(("prefix", prefix))
if args:
object_name = "?" + urlencode(args)
else:
Expand Down
19 changes: 19 additions & 0 deletions txaws/s3/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,25 @@ def check_query_args(passthrough):
d.addCallback(check_query_args)
return d

def test_get_bucket_prefix(self):
"""
L{S3Client.get_bucket} accepts a C{prefix} argument to ask the server to
limit its response to objects beginning with a certain prefix.
"""
query_factory = mock_query_factory(payload.sample_get_bucket_result)
def check_query_args(passthrough):
self.assertEqual(
b"http:///mybucket/?prefix=foobar",
query_factory.details.url_context.get_encoded_url(),
)
return passthrough

creds = AWSCredentials("foo", "bar")
s3 = client.S3Client(creds, query_factory=query_factory)
d = s3.get_bucket("mybucket", prefix=b"foobar")
d.addCallback(check_query_args)
return d

def test_get_bucket_location(self):
"""
L{S3Client.get_bucket_location} creates a L{Query} to get a bucket's
Expand Down
19 changes: 17 additions & 2 deletions txaws/testing/s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ class S3ClientState(object):
``S3ClientState`` instances hold the ``_MemoryS3Client`` instance
state that is specific to testing and does not exist on
``txaws.s3.S3Client`` instances.

@ivar buckets: A ``dict`` mapping bucket identifiers to ``dict`` of
``Bucket`` and ``BucketListing`` details.
"""
from time import time

Expand Down Expand Up @@ -91,12 +94,24 @@ def delete_bucket(self, bucket):
return succeed(None)

@_rate_limited
def get_bucket(self, bucket):
def get_bucket(self, bucket, prefix=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch - this also needed to be updated!

try:
pieces = self._state.buckets[bucket]
except KeyError:
return fail(S3Error("<nosuchbucket/>", 400))
return succeed(pieces["listing"])
listing = pieces["listing"]
if prefix is not None:
listing = attr.assoc(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #80

listing,
contents=list(
content
for content
in listing.contents
if content.key.startswith(prefix)
),
prefix=prefix,
)
return succeed(listing)

@_rate_limited
def get_bucket_location(self, bucket):
Expand Down
15 changes: 15 additions & 0 deletions txaws/testing/s3_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,21 @@ def test_objects(self):
"Expected to not find deleted objects in listing {}".format(objects),
)

@inlineCallbacks
def test_get_bucket_prefix(self):
"""
A subset of S3 objects in a bucket can be retrieved by specifying a value
for the ``prefix`` argument to ``get_bucket``.
"""
bucket_name = str(uuid4())
client = get_client(self)
yield client.create_bucket(bucket_name)
yield client.put_object(bucket_name, b"a", b"foo")
yield client.put_object(bucket_name, b"b", b"bar")

objects = yield client.get_bucket(bucket_name, prefix=b"a")
self.assertEqual([b"a"], list(obj.key for obj in objects.contents))

def test_get_bucket_location_empty(self):
"""
When called for a bucket with no explicit location,
Expand Down