From 097eeb1d19abde9f58f4ebeb5866be3fa556fa16 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Mon, 4 Nov 2024 21:39:13 +0800 Subject: [PATCH 1/3] fix: check whether xattr is changed before and after clear Some extend attributes cannot be removed in certain setups on macOS, which would cause the file being modified meaninglessly --- src/exif_stripper/__init__.py | 20 ++++++++++++++++++-- tests/test_cli.py | 12 +++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/exif_stripper/__init__.py b/src/exif_stripper/__init__.py index b7fcef5..6d048b2 100644 --- a/src/exif_stripper/__init__.py +++ b/src/exif_stripper/__init__.py @@ -37,12 +37,28 @@ def process_image(filename: str | os.PathLike) -> bool: else: # remove extended attributes (Unix only) if platform.system() != 'Windows': + import warnings + from xattr import xattr xattr_obj = xattr(filename) - if xattr_obj.list(): + xattr_list = xattr_obj.list() + + if xattr_list: + original_xattr_list = xattr_list[:] + xattr_obj.clear() - has_changed = True + + xattr_obj = xattr(filename) + xattr_list = xattr_obj.list() + + has_changed |= set(xattr_list) != set(original_xattr_list) + if xattr_list: + xattr_list_str = ', '.join(xattr_list) + warnings.warn( + f'Extended attributes {xattr_list_str} in {filename} cannot be removed.', + stacklevel=2, + ) if has_changed: print(f'Stripped metadata from {filename}') diff --git a/tests/test_cli.py b/tests/test_cli.py index 77d212d..e28dec2 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -13,6 +13,7 @@ RUNNING_ON = platform.system() RUNNING_ON_WINDOWS = RUNNING_ON == 'Windows' +RUNNING_ON_MACOS = RUNNING_ON == 'Darwin' if not RUNNING_ON_WINDOWS: from xattr import xattr @@ -51,7 +52,16 @@ def has_metadata(filepath, on_windows): has_exif = dict(im.getexif()) != {} if on_windows: return has_exif - return has_exif or xattr(filepath).list() + + xattr_list = xattr(filepath).list() + if RUNNING_ON_MACOS: + has_removable_xattr = any( + not attr.startswith('com.apple.') for attr in xattr_list + ) + else: + has_removable_xattr = bool(xattr_list) + + return has_exif or has_removable_xattr def assert_metadata_stripped(filepath, on_windows=RUNNING_ON_WINDOWS): From 7a4cf48733551a6483ca287888d195f766202b2e Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Sat, 9 Nov 2024 00:08:36 +0800 Subject: [PATCH 2/3] test(cli): extend test case test_process_image_full to cover removable attribute warning --- tests/test_cli.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index e28dec2..894e573 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -78,15 +78,24 @@ def assert_metadata_stripped(filepath, on_windows=RUNNING_ON_WINDOWS): @pytest.mark.skipif(RUNNING_ON_WINDOWS, reason='xattr does not work on Windows') -def test_process_image_full(image_with_metadata, monkeypatch): +def test_process_image_full(image_with_metadata, monkeypatch, recwarn): """Test that cli.process_image() removes EXIF and extended attributes.""" + assert_metadata_stripped(image_with_metadata) + # Unremovable attributes may not be present in all system setups. + # This is to assert the warning message if the user has such system configurations. + if recwarn: + message = str(recwarn[0].message) + assert message.startswith('Extended attributes') + assert message.endswith('cannot be removed.') + def test_process_image_exif_only(image_with_exif_data, monkeypatch): """Test that cli.process_image() removes EXIF only (Windows version).""" if not RUNNING_ON_WINDOWS: monkeypatch.setattr(platform, 'system', lambda: 'Windows') + assert_metadata_stripped(image_with_exif_data, on_windows=True) From 6b471d3411f7bcad6b0ea8c04f49f54d46dd707f Mon Sep 17 00:00:00 2001 From: Stefanie Molin <24376333+stefmolin@users.noreply.github.com> Date: Wed, 13 Nov 2024 07:36:40 -0500 Subject: [PATCH 3/3] Exclude lines from test that are only accessible on certain Mac setups --- tests/test_cli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 894e573..f92df8d 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -86,9 +86,9 @@ def test_process_image_full(image_with_metadata, monkeypatch, recwarn): # Unremovable attributes may not be present in all system setups. # This is to assert the warning message if the user has such system configurations. if recwarn: - message = str(recwarn[0].message) - assert message.startswith('Extended attributes') - assert message.endswith('cannot be removed.') + message = str(recwarn[0].message) # pragma: no cover + assert message.startswith('Extended attributes') # pragma: no cover + assert message.endswith('cannot be removed.') # pragma: no cover def test_process_image_exif_only(image_with_exif_data, monkeypatch):