Skip to content

Commit d02098e

Browse files
authored
feat: add matchGlob parameter to list_blobs (#1055)
* feat: add matchGlob parameter to list_blobs * update docstrings and tests * move parameter order * align param order
1 parent 7d65c26 commit d02098e

File tree

5 files changed

+58
-0
lines changed

5 files changed

+58
-0
lines changed

google/cloud/storage/bucket.py

+8
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,7 @@ def list_blobs(
12901290
client=None,
12911291
timeout=_DEFAULT_TIMEOUT,
12921292
retry=DEFAULT_RETRY,
1293+
match_glob=None,
12931294
):
12941295
"""Return an iterator used to find blobs in the bucket.
12951296
@@ -1365,6 +1366,12 @@ def list_blobs(
13651366
:param retry:
13661367
(Optional) How to retry the RPC. See: :ref:`configuring_retries`
13671368
1369+
:type match_glob: str
1370+
:param match_glob:
1371+
(Optional) A glob pattern used to filter results (for example, foo*bar).
1372+
The string value must be UTF-8 encoded. See:
1373+
https://cloud.google.com/storage/docs/json_api/v1/objects/list#list-object-glob
1374+
13681375
:rtype: :class:`~google.api_core.page_iterator.Iterator`
13691376
:returns: Iterator of all :class:`~google.cloud.storage.blob.Blob`
13701377
in this bucket matching the arguments.
@@ -1384,6 +1391,7 @@ def list_blobs(
13841391
fields=fields,
13851392
timeout=timeout,
13861393
retry=retry,
1394+
match_glob=match_glob,
13871395
)
13881396

13891397
def list_notifications(

google/cloud/storage/client.py

+9
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,7 @@ def list_blobs(
11271127
page_size=None,
11281128
timeout=_DEFAULT_TIMEOUT,
11291129
retry=DEFAULT_RETRY,
1130+
match_glob=None,
11301131
):
11311132
"""Return an iterator used to find blobs in the bucket.
11321133
@@ -1220,6 +1221,11 @@ def list_blobs(
12201221
See the retry.py source code and docstrings in this package (google.cloud.storage.retry) for
12211222
information on retry types and how to configure them.
12221223
1224+
match_glob (str):
1225+
(Optional) A glob pattern used to filter results (for example, foo*bar).
1226+
The string value must be UTF-8 encoded. See:
1227+
https://cloud.google.com/storage/docs/json_api/v1/objects/list#list-object-glob
1228+
12231229
Returns:
12241230
Iterator of all :class:`~google.cloud.storage.blob.Blob`
12251231
in this bucket matching the arguments. The RPC call
@@ -1238,6 +1244,9 @@ def list_blobs(
12381244
if delimiter is not None:
12391245
extra_params["delimiter"] = delimiter
12401246

1247+
if match_glob is not None:
1248+
extra_params["matchGlob"] = match_glob
1249+
12411250
if start_offset is not None:
12421251
extra_params["startOffset"] = start_offset
12431252

tests/system/test_bucket.py

+32
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,38 @@ def test_bucket_list_blobs_hierarchy_w_include_trailing_delimiter(
621621
assert iterator.prefixes == expected_prefixes
622622

623623

624+
@_helpers.retry_failures
625+
def test_bucket_list_blobs_w_match_glob(
626+
storage_client,
627+
buckets_to_delete,
628+
blobs_to_delete,
629+
):
630+
bucket_name = _helpers.unique_name("w-matchglob")
631+
bucket = _helpers.retry_429_503(storage_client.create_bucket)(bucket_name)
632+
buckets_to_delete.append(bucket)
633+
634+
payload = b"helloworld"
635+
blob_names = ["foo/bar", "foo/baz", "foo/foobar", "foobar"]
636+
for name in blob_names:
637+
blob = bucket.blob(name)
638+
blob.upload_from_string(payload)
639+
blobs_to_delete.append(blob)
640+
641+
match_glob_results = {
642+
"foo*bar": ["foobar"],
643+
"foo**bar": ["foo/bar", "foo/foobar", "foobar"],
644+
"**/foobar": ["foo/foobar", "foobar"],
645+
"*/ba[rz]": ["foo/bar", "foo/baz"],
646+
"*/ba[!a-y]": ["foo/baz"],
647+
"**/{foobar,baz}": ["foo/baz", "foo/foobar", "foobar"],
648+
"foo/{foo*,*baz}": ["foo/baz", "foo/foobar"],
649+
}
650+
for match_glob, expected_names in match_glob_results.items():
651+
blob_iter = bucket.list_blobs(match_glob=match_glob)
652+
blobs = list(blob_iter)
653+
assert [blob.name for blob in blobs] == expected_names
654+
655+
624656
def test_bucket_w_retention_period(
625657
storage_client,
626658
buckets_to_delete,

tests/unit/test_bucket.py

+6
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,7 @@ def test_list_blobs_w_defaults(self):
11431143
expected_max_results = None
11441144
expected_prefix = None
11451145
expected_delimiter = None
1146+
expected_match_glob = None
11461147
expected_start_offset = None
11471148
expected_end_offset = None
11481149
expected_include_trailing_delimiter = None
@@ -1163,6 +1164,7 @@ def test_list_blobs_w_defaults(self):
11631164
fields=expected_fields,
11641165
timeout=self._get_default_timeout(),
11651166
retry=DEFAULT_RETRY,
1167+
match_glob=expected_match_glob,
11661168
)
11671169

11681170
def test_list_blobs_w_explicit(self):
@@ -1171,6 +1173,7 @@ def test_list_blobs_w_explicit(self):
11711173
page_token = "ABCD"
11721174
prefix = "subfolder"
11731175
delimiter = "/"
1176+
match_glob = "**txt"
11741177
start_offset = "c"
11751178
end_offset = "g"
11761179
include_trailing_delimiter = True
@@ -1197,6 +1200,7 @@ def test_list_blobs_w_explicit(self):
11971200
client=other_client,
11981201
timeout=timeout,
11991202
retry=retry,
1203+
match_glob=match_glob,
12001204
)
12011205

12021206
self.assertIs(iterator, other_client.list_blobs.return_value)
@@ -1205,6 +1209,7 @@ def test_list_blobs_w_explicit(self):
12051209
expected_max_results = max_results
12061210
expected_prefix = prefix
12071211
expected_delimiter = delimiter
1212+
expected_match_glob = match_glob
12081213
expected_start_offset = start_offset
12091214
expected_end_offset = end_offset
12101215
expected_include_trailing_delimiter = include_trailing_delimiter
@@ -1225,6 +1230,7 @@ def test_list_blobs_w_explicit(self):
12251230
fields=expected_fields,
12261231
timeout=timeout,
12271232
retry=retry,
1233+
match_glob=expected_match_glob,
12281234
)
12291235

12301236
def test_list_notifications_w_defaults(self):

tests/unit/test_client.py

+3
Original file line numberDiff line numberDiff line change
@@ -1928,6 +1928,7 @@ def test_list_blobs_w_explicit_w_user_project(self):
19281928
page_token = "ABCD"
19291929
prefix = "subfolder"
19301930
delimiter = "/"
1931+
match_glob = "**txt"
19311932
start_offset = "c"
19321933
end_offset = "g"
19331934
include_trailing_delimiter = True
@@ -1962,6 +1963,7 @@ def test_list_blobs_w_explicit_w_user_project(self):
19621963
page_size=page_size,
19631964
timeout=timeout,
19641965
retry=retry,
1966+
match_glob=match_glob,
19651967
)
19661968

19671969
self.assertIs(iterator, client._list_resource.return_value)
@@ -1976,6 +1978,7 @@ def test_list_blobs_w_explicit_w_user_project(self):
19761978
"projection": projection,
19771979
"prefix": prefix,
19781980
"delimiter": delimiter,
1981+
"matchGlob": match_glob,
19791982
"startOffset": start_offset,
19801983
"endOffset": end_offset,
19811984
"includeTrailingDelimiter": include_trailing_delimiter,

0 commit comments

Comments
 (0)