diff --git a/osxphotos/__main__.py b/osxphotos/__main__.py index 62c04f21..ef6f7a78 100644 --- a/osxphotos/__main__.py +++ b/osxphotos/__main__.py @@ -855,12 +855,6 @@ def query( @cli.command(cls=ExportCommand) @DB_OPTION -# @click.option( -# "--all", -# is_flag=True, -# help="Export all versions of photos including " -# "edited photos, live photos, burst photos, and RAW photos.", -# ) @click.option("--verbose", "-V", is_flag=True, help="Print verbose output.") @query_options @click.option( @@ -878,29 +872,26 @@ def query( "(e.g. DEST/2019/12/20/photoname.jpg).", ) @click.option( - "--export-edited", + "--skip-edited", is_flag=True, - help="Also export edited version of photo if an edited version exists. " - 'Edited photo will be named in form of "photoname_edited.ext"', + help="Do not export edited version of photo if an edited version exists.", ) @click.option( - "--export-bursts", + "--skip-bursts", is_flag=True, - help="If a photo is a burst photo export all associated burst images in the library. " - "Not currently compatible with --download-misssing; see note on --download-missing.", + help="Do not export all associated burst images in the library if a photo is a burst photo. ", ) @click.option( - "--export-live", + "--skip-live", is_flag=True, - help="If a photo is a live photo export the associated live video component." - " Live video will have same name as photo but with .mov extension. ", + help="Do not export the associated live video component of a live photo.", ) @click.option( - "--export-raw", + "--skip-raw", is_flag=True, - help="If a photo was imported in RAW format with associated jpeg, also export the " - "RAW photo in addition to the jpeg. (By default, Photos treats the jpeg as the " - "original image.)", + help="Do not export associated RAW images of a RAW/jpeg pair. " + "Note: this does not skip RAW photos if the RAW photo does not have an associated jpeg image " + "(e.g. the RAW file was imported to Photos without a jpeg preview.", ) @click.option( "--original-name", @@ -986,10 +977,10 @@ def export( verbose, overwrite, export_by_date, - export_edited, - export_bursts, - export_live, - export_raw, + skip_edited, + skip_bursts, + skip_live, + skip_raw, original_name, sidecar, only_photos, @@ -1027,6 +1018,10 @@ def export( if more than one option is provided, they are treated as "AND" (e.g. search for photos matching all options). If no query options are provided, all photos will be exported. + By default, all versions of all photos will be exported including edited + versions, live photo movies, burst photos, and associated RAW images. + See --skip-edited, --skip-live, --skip-bursts, and --skip-raw options + to modify this behavior. """ if not os.path.isdir(dest): @@ -1055,6 +1050,12 @@ def export( click.echo(cli.commands["export"].get_help(ctx), err=True) return + # initialize export flags + # by default, will export all versions of photos unless skip flag is set + (export_edited, export_bursts, export_live, export_raw) = [ + not x for x in [skip_edited, skip_bursts, skip_live, skip_raw] + ] + # verify exiftool installed an in path if exiftool: try: diff --git a/osxphotos/_version.py b/osxphotos/_version.py index ad8d2558..191e7ce5 100644 --- a/osxphotos/_version.py +++ b/osxphotos/_version.py @@ -1,3 +1,3 @@ """ version info """ -__version__ = "0.27.7" +__version__ = "0.28.0" diff --git a/osxphotos/photoinfo.py b/osxphotos/photoinfo.py index 30b02005..0d0d5196 100644 --- a/osxphotos/photoinfo.py +++ b/osxphotos/photoinfo.py @@ -718,7 +718,7 @@ class PhotoInfo: # Photo's often converts .JPG to .jpeg suffixes = sorted([x.lower() for x in [dest.suffix, actual_suffix]]) if dest.suffix != actual_suffix and suffixes != [".jpeg", ".jpg"]: - logging.warning( + logging.debug( f"Invalid destination suffix: {dest.suffix}, should be {actual_suffix}" ) diff --git a/tests/test_cli.py b/tests/test_cli.py index a2b051a5..f3ba7c1c 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -206,6 +206,25 @@ def test_export(): import osxphotos from osxphotos.__main__ import export + runner = CliRunner() + cwd = os.getcwd() + # pylint: disable=not-context-manager + with runner.isolated_filesystem(): + result = runner.invoke( + export, [os.path.join(cwd, CLI_PHOTOS_DB), ".", "--original-name", "-V"] + ) + assert result.exit_code == 0 + files = glob.glob("*") + assert sorted(files) == sorted(CLI_EXPORT_FILENAMES) + + +def test_export_skip_edited(): + import glob + import os + import os.path + import osxphotos + from osxphotos.__main__ import export + runner = CliRunner() cwd = os.getcwd() # pylint: disable=not-context-manager @@ -215,14 +234,14 @@ def test_export(): [ os.path.join(cwd, CLI_PHOTOS_DB), ".", + "--skip-edited", "--original-name", - "--export-edited", "-V", ], ) assert result.exit_code == 0 files = glob.glob("*") - assert sorted(files) == sorted(CLI_EXPORT_FILENAMES) + assert "St James Park_edited.jpeg" not in files def test_query_date(): @@ -290,6 +309,25 @@ def test_export_live(): import osxphotos from osxphotos.__main__ import export + runner = CliRunner() + cwd = os.getcwd() + # pylint: disable=not-context-manager + with runner.isolated_filesystem(): + result = runner.invoke( + export, + [os.path.join(cwd, LIVE_PHOTOS_DB), ".", "--live", "--original-name", "-V"], + ) + files = glob.glob("*") + assert sorted(files) == sorted(CLI_EXPORT_LIVE_ORIGINAL) + + +def test_export_skip_live(): + import glob + import os + import os.path + import osxphotos + from osxphotos.__main__ import export + runner = CliRunner() cwd = os.getcwd() # pylint: disable=not-context-manager @@ -299,14 +337,13 @@ def test_export_live(): [ os.path.join(cwd, LIVE_PHOTOS_DB), ".", - "--live", + "--skip-live", "--original-name", - "--export-live", "-V", ], ) files = glob.glob("*") - assert sorted(files) == sorted(CLI_EXPORT_LIVE_ORIGINAL) + assert "img_0728.mov" not in [f.lower() for f in files] def test_export_raw(): @@ -320,11 +357,33 @@ def test_export_raw(): cwd = os.getcwd() # pylint: disable=not-context-manager with runner.isolated_filesystem(): - result = runner.invoke(export, [os.path.join(cwd, RAW_PHOTOS_DB), ".", "-V"]) + result = runner.invoke( + export, [os.path.join(cwd, RAW_PHOTOS_DB), ".", "--skip-edited", "-V"] + ) files = glob.glob("*") assert sorted(files) == sorted(CLI_EXPORT_RAW) +# TODO: Update this once RAW db is added +# def test_skip_raw(): +# import glob +# import os +# import os.path +# import osxphotos +# from osxphotos.__main__ import export + +# runner = CliRunner() +# cwd = os.getcwd() +# # pylint: disable=not-context-manager +# with runner.isolated_filesystem(): +# result = runner.invoke( +# export, [os.path.join(cwd, RAW_PHOTOS_DB), ".", "--skip-raw", "-V"] +# ) +# files = glob.glob("*") +# for rawname in CLI_EXPORT_RAW: +# assert rawname.lower() not in [f.lower() for f in files] + + def test_export_raw_original(): import glob import os @@ -337,7 +396,14 @@ def test_export_raw_original(): # pylint: disable=not-context-manager with runner.isolated_filesystem(): result = runner.invoke( - export, [os.path.join(cwd, RAW_PHOTOS_DB), ".", "--original-name", "-V"] + export, + [ + os.path.join(cwd, RAW_PHOTOS_DB), + ".", + "--skip-edited", + "--original-name", + "-V", + ], ) files = glob.glob("*") assert sorted(files) == sorted(CLI_EXPORT_RAW_ORIGINAL) @@ -354,9 +420,7 @@ def test_export_raw_edited(): cwd = os.getcwd() # pylint: disable=not-context-manager with runner.isolated_filesystem(): - result = runner.invoke( - export, [os.path.join(cwd, RAW_PHOTOS_DB), ".", "--export-edited", "-V"] - ) + result = runner.invoke(export, [os.path.join(cwd, RAW_PHOTOS_DB), ".", "-V"]) files = glob.glob("*") assert sorted(files) == sorted(CLI_EXPORT_RAW_EDITED) @@ -373,14 +437,7 @@ def test_export_raw_edited_original(): # pylint: disable=not-context-manager with runner.isolated_filesystem(): result = runner.invoke( - export, - [ - os.path.join(cwd, RAW_PHOTOS_DB), - ".", - "--export-edited", - "--original-name", - "-V", - ], + export, [os.path.join(cwd, RAW_PHOTOS_DB), ".", "--original-name", "-V"] ) files = glob.glob("*") assert sorted(files) == sorted(CLI_EXPORT_RAW_EDITED_ORIGINAL) diff --git a/tests/test_export_raw_catalina_10_15_1.py b/tests/test_export_raw_catalina_10_15_1.py index b0b97038..ca435160 100644 --- a/tests/test_export_raw_catalina_10_15_1.py +++ b/tests/test_export_raw_catalina_10_15_1.py @@ -104,7 +104,7 @@ def test_export_edited_default(): assert pathlib.Path(got_dest).name == FILENAME_DICT["current_edited"] -def test_export_edited_wrong_suffix(caplog): +def test_export_edited_wrong_suffix(): # export edited file with name provided but wrong suffix # should produce a warning via logging.warning import os @@ -126,7 +126,6 @@ def test_export_edited_wrong_suffix(caplog): expected_dest = os.path.join(dest, filename) got_dest = photos[0].export(dest, filename, edited=True)[0] - assert "Invalid destination suffix" in caplog.text + # assert "Invalid destination suffix" in caplog.text assert got_dest == expected_dest assert pathlib.Path(got_dest).name == filename -