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

Add --include and --exclude filters to the ls and rm commands #253

Merged
merged 11 commits into from
Feb 22, 2024
4 changes: 2 additions & 2 deletions b2/_internal/_utils/uri.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,10 @@ def list_file_versions_by_uri(self, uri, *args, **kwargs):
raise NotImplementedError(f"Unsupported URI type: {type(uri)}")

@list_file_versions_by_uri.register
def _(self, uri: B2URI, *args, **kwargs):
def _(self, uri: B2URI, *args, filters=(), **kwargs):

Choose a reason for hiding this comment

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

Type hint?

bucket = self.api.get_bucket_by_name(uri.bucket_name)
try:
yield from bucket.ls(uri.path, *args, **kwargs)
yield from bucket.ls(uri.path, *args, filters=filters, **kwargs)
except ValueError as error:
# Wrap these errors into B2Error. At the time of writing there's
# exactly one – `with_wildcard` being passed without `recursive` option.
Expand Down
4 changes: 4 additions & 0 deletions b2/_internal/console_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
EncryptionSetting,
FileRetentionSetting,
FileVersion,
Filter,
KeepOrDeleteMode,
LegalHold,
LifecycleRule,
Expand Down Expand Up @@ -2175,6 +2176,8 @@ def _setup_parser(cls, parser):
parser.add_argument('--versions', action='store_true')
parser.add_argument('-r', '--recursive', action='store_true')
parser.add_argument('--withWildcard', action='store_true')
parser.add_argument('--include', dest='filters', action='append', type=Filter.include)
parser.add_argument('--exclude', dest='filters', action='append', type=Filter.exclude)

Choose a reason for hiding this comment

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

The docstring is outdated now.

super()._setup_parser(parser)

def _print_files(self, args):
Expand All @@ -2198,6 +2201,7 @@ def _get_ls_generator(self, args):
latest_only=not args.versions,
recursive=args.recursive,
with_wildcard=args.withWildcard,
filters=args.filters or (),

Choose a reason for hiding this comment

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

Maybe use default value in add_argument instead? Is this possible?

parser.add_argument('--include', dest='filters', action='append', type=Filter.include, default=())

Copy link
Author

@emnoor-reef emnoor-reef Feb 9, 2024

Choose a reason for hiding this comment

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

That doesn't work. With action='append', argparse stores the default, copies the object with dest[:] before appending, then calls .append() on that. So tuples don't work here.

But we can have default=[] here. A quick forage through argparse code verifies that having multiple flags with with the same destination and a default won't cause any problems.

)

def get_b2_uri_from_arg(self, args: argparse.Namespace) -> B2URI:
Expand Down
1 change: 1 addition & 0 deletions changelog.d/+ls-rm-filters.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add `--include` and `--exclude` filters to the `ls` and `rm` commands.
58 changes: 58 additions & 0 deletions test/unit/test_console_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -2445,6 +2445,64 @@ def test_ls_b2id(self):
'''
self._run_command(['ls', f'b2id://{file_version.id_}'], expected_stdout, '', 0)

def test_ls_filters(self):

Choose a reason for hiding this comment

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

This checks filters working on ls command but doesn't ensure they work with rm command. I understand that it should work automatically bc of some inheritance, but still I think some very basic test would be good here. If some code changes in future, we don't want rm to misbehave with those flags.

self._authorize_account()
self._create_my_bucket()

# Create some files, including files in a folder
bucket = self.b2_api.get_bucket_by_name('my-bucket')
data = UploadSourceBytes(b'test-data')
bucket.upload(data, 'a/test.csv')
bucket.upload(data, 'a/test.tsv')
bucket.upload(data, 'b/b/test.csv')
bucket.upload(data, 'c/test.csv')
bucket.upload(data, 'c/test.tsv')
bucket.upload(data, 'test.csv')
bucket.upload(data, 'test.tsv')

expected_stdout = '''
a/
b/
c/
test.csv
'''
self._run_command(
['ls', *self.b2_uri_args('my-bucket'), '--include', '*.csv'],
expected_stdout,
)
self._run_command(
['ls', *self.b2_uri_args('my-bucket'), '--exclude', '*.tsv'],
expected_stdout,
)

expected_stdout = '''
a/test.csv
b/b/test.csv
c/test.csv
test.csv
'''
self._run_command(
['ls', *self.b2_uri_args('my-bucket'), '--recursive', '--include', '*.csv'],
expected_stdout,
)
self._run_command(
['ls', *self.b2_uri_args('my-bucket'), '--recursive', '--exclude', '*.tsv'],
expected_stdout,
)

expected_stdout = '''
b/b/test.csv
c/test.csv
test.csv
'''
self._run_command(
[
'ls', *self.b2_uri_args('my-bucket'), '--recursive', '--exclude', '*', '--include',
'*.csv', '--exclude', 'a/*'
],
expected_stdout,
)


class TestConsoleToolWithV1(BaseConsoleToolTest):
"""These tests use v1 interface to perform various setups before running CLI commands"""
Expand Down
Loading