From d13b75e7631ee30a8eb3ec7deb2655a8647375bf Mon Sep 17 00:00:00 2001 From: Rob Miller Date: Wed, 20 Dec 2023 21:42:58 +0000 Subject: [PATCH 1/2] implement --rmdirs option (#225) --- phockup.py | 12 ++++++++++++ src/phockup.py | 22 ++++++++++++++++++++++ tests/test_phockup.py | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/phockup.py b/phockup.py index bbf4e48..b18bb70 100755 --- a/phockup.py +++ b/phockup.py @@ -286,6 +286,17 @@ def parse_args(args=sys.argv[1:]): and `--skip-unknown`. """, ) + + parser.add_argument( + '--rmdirs', + action='store_true', + default=False, + help="""\ + DELETE empty directories after processing. Only valid in + conjunction with `--move`. + """, + ) + parser.add_argument( '--output_prefix', type=str, @@ -376,6 +387,7 @@ def main(options): no_date_dir=options.no_date_dir, skip_unknown=options.skip_unknown, movedel=options.movedel, + rmdirs=options.rmdirs, output_prefix=options.output_prefix, output_suffix=options.output_suffix, from_date=options.from_date, diff --git a/src/phockup.py b/src/phockup.py index 4c2b89e..5add1cd 100755 --- a/src/phockup.py +++ b/src/phockup.py @@ -51,6 +51,7 @@ def __init__(self, input_dir, output_dir, **args): self.date_field = args.get('date_field', False) self.skip_unknown = args.get("skip_unknown", False) self.movedel = args.get("movedel", False), + self.rmdirs = args.get("rmdirs", False), self.dry_run = args.get('dry_run', False) self.progress = args.get('progress', False) self.max_depth = args.get('max_depth', -1) @@ -89,6 +90,9 @@ def __init__(self, input_dir, output_dir, **args): self.pbar = None self.walk_directory() + if self.move and self.rmdirs: + self.rm_subdirs() + run_time = time.time() - start_time if self.files_processed and run_time: self.print_action_report(run_time) @@ -156,6 +160,24 @@ def walk_directory(self): if root.count(os.sep) >= self.stop_depth: del dirnames[:] + def rm_subdirs(self): + def _get_depth(sub_path): + return sub_path.count(os.sep) - self.input_dir.count(os.sep) + + for root, dirs, files in os.walk(self.input_dir, topdown=False): + # Traverse the tree bottom-up + if _get_depth(root) > self.stop_depth: + continue + for name in dirs: + dir_path = os.path.join(root, name) + if _get_depth(dir_path) > self.stop_depth: + continue + try: + os.rmdir(dir_path) # Try to remove the dir + logger.info(f"Deleted empty directory: {dir_path}") + except OSError as e: + logger.info(f"{e.strerror} - {dir_path} not deleted.") + def get_file_count(self): file_count = 0 for root, dirnames, files in os.walk(self.input_dir): diff --git a/tests/test_phockup.py b/tests/test_phockup.py index aefa776..0c634a6 100644 --- a/tests/test_phockup.py +++ b/tests/test_phockup.py @@ -311,6 +311,41 @@ def test_process_movedel(mocker, caplog): shutil.rmtree('output', ignore_errors=True) +def test_process_rmdirs(mocker, caplog): + shutil.rmtree('output', ignore_errors=True) + shutil.rmtree('input/sub_folder/sub0', ignore_errors=True) + mocker.patch.object(Exif, 'data') + Exif.data.return_value = { + "MIMEType": "image/jpeg" + } + os.mkdir('input/sub_folder/sub0') + os.mkdir('input/sub_folder/sub0/sub1') + os.mkdir('input/sub_folder/sub0/sub2') + os.mkdir('input/sub_folder/sub0/sub2/sub3') + open("input/sub_folder/sub0/tmp_20170101_010101.jpg", "w").close() + open("input/sub_folder/sub0/sub1/tmp_20170101_010102.jpg", "w").close() + open("input/sub_folder/sub0/sub2/tmp_20170101_010103.jpg", "w").close() + open("input/sub_folder/sub0/sub2/sub3/tmp_20170101_010104.jpg", "w").close() + with caplog.at_level(logging.INFO): + Phockup('input/sub_folder/sub0', 'output', move=True, rmdirs=True, max_depth=1) + assert 'Deleted empty directory: input/sub_folder/sub0/sub1' in caplog.text + assert 'input/sub_folder/sub0/sub2/sub3 not deleted' in caplog.text + assert os.path.isfile("output/2017/01/01/20170101-010101.jpg") + assert os.path.isfile("output/2017/01/01/20170101-010102.jpg") + assert os.path.isfile("output/2017/01/01/20170101-010103.jpg") + assert not os.path.isfile("output/2017/01/01/20170101-010104.jpg") + assert not os.path.isdir("input/sub_folder/sub0/sub1") + assert os.path.isdir("input/sub_folder/sub0/sub2") + assert os.path.isdir("input/sub_folder/sub0/sub2/sub3") + with caplog.at_level(logging.INFO): + Phockup('input/sub_folder/sub0', 'output', move=True, rmdirs=True) + assert 'Deleted empty directory: input/sub_folder/sub0/sub2' in caplog.text + assert not os.path.isdir("input/sub_folder/sub0/sub2") + assert os.path.isfile("output/2017/01/01/20170101-010104.jpg") + shutil.rmtree('input/sub_folder/sub0', ignore_errors=True) + shutil.rmtree('output', ignore_errors=True) + + def test_process_link(mocker): shutil.rmtree('output', ignore_errors=True) mocker.patch.object(Phockup, 'check_directories') From f23f8081666804dcd2473abc0e2d08b1c72c4216 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Dec 2023 23:43:22 +0200 Subject: [PATCH 2/2] Bump actions/setup-python from 4 to 5 (#226) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/deploy.yml | 2 +- .github/workflows/tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a379b0c..5554df1 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -18,7 +18,7 @@ jobs: fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1873a1b..0435443 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v4.1.1 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }}