From 48387733a08672d5aef5d4778144bb6f22b24a29 Mon Sep 17 00:00:00 2001 From: Rhet Turnbull Date: Sat, 12 Nov 2022 18:17:02 -0800 Subject: [PATCH] Began refactor, added python 3.11 support --- photoscript/__init__.py | 368 ++++++++------- photoscript/photoscript.applescript | 680 ++++++++++++++-------------- poetry.lock | 231 +++++----- pyproject.toml | 9 +- tests/mock_photoscript.applescript | 16 +- 5 files changed, 651 insertions(+), 653 deletions(-) diff --git a/photoscript/__init__.py b/photoscript/__init__.py index 1a8705c..e53ce39 100644 --- a/photoscript/__init__.py +++ b/photoscript/__init__.py @@ -10,6 +10,7 @@ from subprocess import run from applescript import AppleScript, kMissingValue + from photoscript.utils import ditto, findfiles from .script_loader import run_script @@ -29,20 +30,20 @@ def __init__(self, *message): class PhotosLibrary: def __init__(self): - """ create new PhotosLibrary object and launch Photos """ - run_script("_photoslibrary_waitforphotos", 300) - self._version = str(run_script("_photoslibrary_version")) + """create new PhotosLibrary object and launch Photos""" + run_script("photosLibraryWaitForPhotos", 300) + self._version = str(run_script("photosLibraryVersion")) def activate(self): - """ activate Photos.app """ - run_script("_photoslibrary_activate") + """activate Photos.app""" + run_script("photosLibraryActivate") def quit(self): - """ quit Photos.app """ - run_script("_photoslibrary_quit") + """quit Photos.app""" + run_script("photosLibraryQuit") def open(self, library_path, delay=10): - """ open a library and wait for delay for user to acknowledge in Photos """ + """open a library and wait for delay for user to acknowledge in Photos""" # Note: Unlike the other AppleScript scripts, this one is not included in photoscript.applescript # because, for reasons I cannot explain, it fails to run if included there if not pathlib.Path(library_path).is_dir(): @@ -70,80 +71,79 @@ def open(self, library_path, delay=10): @property def running(self): - """ True if Photos is running, otherwise False """ - return run_script("_photoslibrary_isrunning") + """True if Photos is running, otherwise False""" + return run_script("photosLibraryIsRunning") def hide(self): - """ Tell Photos to hide its window """ - run_script("_photoslibrary_hide") + """Tell Photos to hide its window""" + run_script("photosLibraryHide") @property def hidden(self): - """ True if Photos is hidden (or not running), False if Photos is visible """ - return run_script("_photoslibrary_hidden") + """True if Photos is hidden (or not running), False if Photos is visible""" + return run_script("photosLibraryIsHidden") @property def name(self): - """ name of Photos.app """ - return run_script("_photoslibrary_name") + """name of Photos.app""" + return run_script("photosLibraryName") @property def version(self): - """ version of Photos.app as str """ + """version of Photos.app as str""" return self._version @property def frontmost(self): - """ True if Photos.app is front most app otherwise False """ - return run_script("_photoslibrary_frontmost") + """True if Photos.app is front most app otherwise False""" + return run_script("photosLibraryIsFrontMost") @property def selection(self): - """ List of Photo objects for currently selected photos or [] if no selection """ - uuids = run_script("_photoslibrary_get_selection") + """List of Photo objects for currently selected photos or [] if no selection""" + uuids = run_script("photosLibraryGetSelection") return [Photo(uuid) for uuid in uuids] @property def favorites(self): - """ Album object for the Favorites album """ - fav_id = run_script("_photoslibrary_favorites") + """Album object for the Favorites album""" + fav_id = run_script("photosLibraryFavorites") return Album(fav_id) # doesn't seem to be a way to do anything with the recently deleted album except count items # @property # def recently_deleted(self): # """ Album object for the Recently Deleted album """ - # del_id = run_script("_photoslibrary_recently_deleted") + # del_id = run_script("photosLibraryRecentlyDeleted") # return Album(del_id) def photos(self, search=None, uuid=None, range_=None): - """Returns a generator that yields Photo objects - for media items in the library. + """Returns a generator that yields Photo objects for media items in the library. Args: search: optional text string to search for (returns matching items) uuid: optional list of UUIDs to get range\_: optional list of [start, stop] sequence of photos to get - + Returns: Generator that yields Photo objects - Raises: + Raises: ValueError if more than one of search, uuid, range\_ passed or invalid range\_ TypeError if list not passed for range\_ Note: photos() returns a generator instead of a list because retrieving all the photos from a large Photos library can take a very long time--on my system, the rate is about 1 - per second; this is limited by the Photos AppleScript interface and I've not found - anyway to speed it up. Using a generator allows you process photos individually rather - than waiting, possibly hours, for Photos to return the results. - - range\_ works like python's range function. Thus range\_=[0,4] will return - Photos 0, 1, 2, 3; range\_=[10] returns the first 10 photos in the library; - range\_ start must be in range 0 to len(PhotosLibrary())-1, + per second; this is limited by the Photos AppleScript interface and I've not found + anyway to speed it up. Using a generator allows you process photos individually rather + than waiting, possibly hours, for Photos to return the results. + + range\_ works like python's range function. Thus range\_=[0,4] will return + Photos 0, 1, 2, 3; range\_=[10] returns the first 10 photos in the library; + range\_ start must be in range 0 to len(PhotosLibrary())-1, stop in range 1 to len(PhotosLibrary()). You may be able to optimize the speed by which - photos are return by chunking up requests in batches of photos using range\_, - e.g. request 10 photos at a time. + photos are return by chunking up requests in batches of photos using range\_, + e.g. request 10 photos at a time. """ if len([x for x in [search, uuid, range_] if x]) > 1: @@ -154,7 +154,7 @@ def photos(self, search=None, uuid=None, range_=None): if search is not None: # search for text - photo_ids = run_script("_photoslibrary_search_photos", search) + photo_ids = run_script("photosLibrarySearchPhotos", search) elif uuid: # search by uuid photo_ids = uuid @@ -181,7 +181,7 @@ def photos(self, search=None, uuid=None, range_=None): f"invalid range: valid range is start: 0 to {count-1}, stop: 1 to {count}" ) - photo_ids = run_script("_photoslibrary_get_photo_by_range", start + 1, stop) + photo_ids = run_script("photosLibraryGetPhotoByRange", start + 1, stop) if photo_ids: return self._iterphotos(uuids=photo_ids) @@ -197,7 +197,7 @@ def _iterphotos(self, uuids=None): count = len(self) for x in range(1, count + 1): # AppleScript list indexes start at 1 - photo_id = run_script("_photoslibrary_get_photo_by_range", x, x)[0] + photo_id = run_script("photosLibraryGetPhotoByRange", x, x)[0] yield Photo(photo_id) def import_photos(self, photo_paths, album=None, skip_duplicate_check=False): @@ -206,26 +206,26 @@ def import_photos(self, photo_paths, album=None, skip_duplicate_check=False): Args: photo_paths: list of file paths to import as str or pathlib.Path album: optional, Album object for album to import into - skip_duplicate_check: if True, Photos will not check for duplicates on import, default is False. - + skip_duplicate_check: if True, Photos will not check for duplicates on import, default is False. + Returns: list of Photo objects for imported photos - - NOTE: If you attempt to import a duplicate photo and skip_duplicate_check != True, + + NOTE: If you attempt to import a duplicate photo and skip_duplicate_check != True, Photos will block with drop-down sheet until the user clicks "Cancel, Import, or Don't Import." """ # stringify paths in case pathlib.Path paths are passed photo_paths = [str(photo_path) for photo_path in photo_paths] if album is not None: photo_ids = run_script( - "_photoslibrary_import_to_album", + "photosLibraryImportToAlbum", photo_paths, album.id, skip_duplicate_check, ) else: photo_ids = run_script( - "_photoslibrary_import", photo_paths, skip_duplicate_check + "photosLibraryImport", photo_paths, skip_duplicate_check ) return [Photo(photo) for photo in photo_ids] @@ -236,7 +236,7 @@ def album_names(self, top_level=False): Args: top_level: if True, returns only top-level albums otherwise also returns albums in sub-folders; default is False """ - return run_script("_photoslibrary_album_names", top_level) + return run_script("photosLibraryAlbumNames", top_level) def folder_names(self, top_level=False): """List of folder names in the Photos library @@ -244,7 +244,7 @@ def folder_names(self, top_level=False): Args: top_level: if True, returns only top-level folders otherwise also returns sub-folders; default is False """ - return run_script("_photoslibrary_folder_names", top_level) + return run_script("photosLibraryFolderNames", top_level) def album(self, *name, uuid=None, top_level=False): """Album instance by name or id @@ -257,7 +257,7 @@ def album(self, *name, uuid=None, top_level=False): Returns: Album object or None if album could not be found - Raises: + Raises: ValueError if both name and id passed or neither passed. Must pass only name or id but not both. @@ -267,7 +267,7 @@ def album(self, *name, uuid=None, top_level=False): raise ValueError("Must pass only name or uuid but not both") if name: - uuid = run_script("_album_by_name", name[0], top_level) + uuid = run_script("albumByName", name[0], top_level) if uuid != 0: return Album(uuid) else: @@ -276,8 +276,8 @@ def album(self, *name, uuid=None, top_level=False): return Album(uuid) def albums(self, top_level=False): - """ list of Album objects for all albums """ - album_ids = run_script("_photoslibrary_album_ids", top_level) + """list of Album objects for all albums""" + album_ids = run_script("photosLibraryAlbumIDs", top_level) return [Album(uuid) for uuid in album_ids] def create_album(self, name, folder=None): @@ -295,11 +295,9 @@ def create_album(self, name, folder=None): AppleScriptError if error creating the album """ if folder is None: - album_id = run_script("_photoslibrary_create_album", name) + album_id = run_script("photosLibraryCreateAlbum", name) else: - album_id = run_script( - "_photoslibrary_create_album_at_folder", name, folder.id - ) + album_id = run_script("photosLibraryCreateAlbumAtFolder", name, folder.id) if album_id != 0: return Album(album_id) @@ -312,7 +310,7 @@ def delete_album(self, album): Args: album: an Album object for album to delete """ - return run_script("_photoslibrary_delete_album", album.id) + return run_script("photosLibraryDeleteAlbum", album.id) def folder(self, *name, uuid=None, top_level=True): """Folder instance by name or uuid @@ -325,9 +323,9 @@ def folder(self, *name, uuid=None, top_level=True): Returns: Folder object or None if folder could not be found - Raises: + Raises: ValueError if both name and id passed or neither passed. - + Must pass only name or id but not both. If more than one folder with same name, returns first one found. """ @@ -335,7 +333,7 @@ def folder(self, *name, uuid=None, top_level=True): raise ValueError("Must pass only name or uuid but not both") if name: - uuid = run_script("_folder_by_name", name[0], top_level) + uuid = run_script("folderByName", name[0], top_level) if uuid != 0: return Folder(uuid) else: @@ -344,23 +342,23 @@ def folder(self, *name, uuid=None, top_level=True): return Folder(uuid) def folder_by_path(self, folder_path): - """ Return folder in the library by path + """Return folder in the library by path Args: folder_path: list of folder names in descending path order, e.g. ["Folder", "SubFolder1", "SubFolder2"] - Returns: + Returns: Folder object for folder at folder_path or None if not found """ - folder_id = run_script("_folder_by_path", folder_path) + folder_id = run_script("folderByPath", folder_path) if folder_id != 0: return Folder(folder_id) else: return None def folders(self, top_level=True): - """ list of Folder objects for all folders """ - folder_ids = run_script("_photoslibrary_folder_ids", top_level) + """list of Folder objects for all folders""" + folder_ids = run_script("photosLibraryFolderIDs", top_level) return [Folder(uuid) for uuid in folder_ids] def create_folder(self, name, folder=None): @@ -378,11 +376,9 @@ def create_folder(self, name, folder=None): AppleScriptError if folder cannot be created """ if folder is None: - folder_id = run_script("_photoslibrary_create_folder", name) + folder_id = run_script("photosLibraryCreateFolder", name) else: - folder_id = run_script( - "_photoslibrary_create_folder_at_folder", name, folder.id - ) + folder_id = run_script("photosLibraryCreateFolderAtFolder", name, folder.id) if folder_id != 0: return Folder(folder_id) @@ -390,7 +386,7 @@ def create_folder(self, name, folder=None): raise AppleScriptError(f"Could not create folder {name}") def make_folders(self, folder_path): - """Recursively makes folders and subfolders. Works similar to os.makedirs_. + """Recursively makes folders and subfolders. Works similar to os.makedirs_. If any component of folder_path already exists, does not raise error. .. _os.makedirs: https://docs.python.org/3/library/os.html#os.makedirs @@ -422,7 +418,7 @@ def make_folders(self, folder_path): def make_album_folders(self, album_name, folder_path): """Make album in a folder path. If either the album or any component of the - folder path doesn't exist, it will be created. If album or folder path + folder path doesn't exist, it will be created. If album or folder path does exist, no duplicate is created. Folder path is created recursively if needed. @@ -432,7 +428,7 @@ def make_album_folders(self, album_name, folder_path): Returns: Album object. - + Raises: ValueError if folder_path is empty or album_name is None. TypeError if folder_path is not a list. @@ -456,13 +452,13 @@ def delete_folder(self, folder): Args: folder: a Folder object for folder to delete """ - return run_script("_photoslibrary_delete_folder", folder.id) + return run_script("photosLibraryDeleteFolder", folder.id) def __len__(self): - return run_script("_photoslibrary_count") + return run_script("photosLibraryCount") def _temp_album_name(self): - """ get a temporary album name that doesn't clash with album in the library """ + """get a temporary album name that doesn't clash with album in the library""" temp_name = self._temp_name() while self.album(temp_name) is not None: temp_name = self._temp_name() @@ -485,7 +481,7 @@ def _export_photo( timeout=120, reveal_in_finder=False, ): - """ Export photo to export_path + """Export photo to export_path Args: photo: Photo object to export @@ -494,19 +490,19 @@ def _export_photo( overwrite: if True, export will overwrite a file of same name as photo in export_path; default = False timeout: number of seconds to wait for Photos to complete export before timing out; default = 120 reveal_in_finder: if True, will open Finder with exported items selected when done; default = False - + Returns: - List of full paths of exported photos. There may be more than one photo exported due + List of full paths of exported photos. There may be more than one photo exported due to live images and burst images. - + Raises: ValueError if export_path is not a valid directory - Note: Photos always exports as high-quality JPEG unless original=True. - If original=True, will export all burst images for burst photos and - live movie for live photos. If original=False, only the primary image from a - burst set will be exported for burst photos and the live movie component of a - live image will not be exported, only the JPEG component. + Note: Photos always exports as high-quality JPEG unless original=True. + If original=True, will export all burst images for burst photos and + live movie for live photos. If original=False, only the primary image from a + burst set will be exported for burst photos and the live movie component of a + live image will not be exported, only the JPEG component. """ dest = pathlib.Path(export_path) @@ -519,7 +515,7 @@ def _export_photo( # export original filename = run_script( - "_photo_export", photo.id, tmpdir.name, original, edited, timeout + "photoExport", photo.id, tmpdir.name, original, edited, timeout ) exported_paths = [] @@ -551,7 +547,7 @@ def _export_photo( ditto(str(path), str(dest_new)) exported_paths.append(str(dest_new)) if reveal_in_finder: - run_script("_reveal_in_finder", exported_paths) + run_script("revealInFinder", exported_paths) return exported_paths @@ -566,7 +562,7 @@ def __init__(self, uuid): else: uuid = uuid.split("/")[0] - valuuidalbum = run_script("_album_exists", id_) + valuuidalbum = run_script("albumExists", id_) if valuuidalbum: self.id = id_ self._uuid = uuid @@ -575,41 +571,41 @@ def __init__(self, uuid): @property def uuid(self): - """ UUID of Album (read only)""" + """UUID of Album (read only)""" return self._uuid @property def name(self): - """ name of album (read/write) """ - name = run_script("_album_name", self.id) + """name of album (read/write)""" + name = run_script("albumName", self.id) return name if name != kMissingValue else "" @name.setter def name(self, name): - """ set name of album """ + """set name of album""" name = "" if name is None else name - return run_script("_album_set_name", self.id, name) + return run_script("albumSetName", self.id, name) @property def title(self): - """ title of album (alias for Album.name) """ + """title of album (alias for Album.name)""" return self.name @title.setter def title(self, title): - """ set title of album (alias for name) """ + """set title of album (alias for name)""" name = "" if title is None else title - return run_script("_album_set_name", self.id, name) + return run_script("albumSetName", self.id, name) @property def parent_id(self): - """ parent container id """ - return run_script("_album_parent", self.id) + """parent container id""" + return run_script("albumParent", self.id) # TODO: if no parent should return a "My Albums" object that contains all top-level folders/albums @property def parent(self): - """ Return parent Folder object """ + """Return parent Folder object""" parent_id = self.parent_id if parent_id != 0: return Folder(parent_id) @@ -629,11 +625,11 @@ def path_str(self, delim="/"): if len(delim) > 1: raise ValueError("delim must be single character") - return run_script("_album_get_path", self.id, delim) + return run_script("albumGetPath", self.id, delim) def photos(self): - """ list of Photo objects for photos contained in album """ - photo_ids = run_script("_album_photos", self.id) + """list of Photo objects for photos contained in album""" + photo_ids = run_script("albumPhotes", self.id) return [Photo(uuid) for uuid in photo_ids] def add(self, photos): @@ -646,7 +642,7 @@ def add(self, photos): list of Photo objects for added photos """ uuids = [p.id for p in photos] - added_ids = run_script("_album_add", self.id, uuids) + added_ids = run_script("albumAdd", self.id, uuids) return [Photo(uuid) for uuid in added_ids] def import_photos(self, photo_paths, skip_duplicate_check=False): @@ -681,19 +677,19 @@ def export( overwrite: if True, export will overwrite a file of same name as photo in export_path; default = False timeout: number of seconds to wait for Photos to complete export (for each photo) before timing out; default = 120 reveal_in_finder: if True, will open Finder with exported items selected when done; default = False - + Returns: - List of full paths of exported photos. There may be more than one photo exported due + List of full paths of exported photos. There may be more than one photo exported due to live images and burst images. - + Raises: ValueError if export_path is not a valid directory - Note: Photos always exports as high-quality JPEG unless original=True. - If original=True, will export all burst images for burst photos and - live movie for live photos. If original=False, only the primary image from a - burst set will be exported for burst photos and the live movie component of a - live image will not be exported, only the JPEG component. + Note: Photos always exports as high-quality JPEG unless original=True. + If original=True, will export all burst images for burst photos and + live movie for live photos. If original=False, only the primary image from a + burst set will be exported for burst photos and the live movie component of a + live image will not be exported, only the JPEG component. """ exported_photos = [] for photo in self.photos(): @@ -706,11 +702,11 @@ def export( ) ) if reveal_in_finder and exported_photos: - run_script("_reveal_in_finder", exported_photos) + run_script("revealInFinder", exported_photos) return exported_photos def remove_by_id(self, photo_ids): - """Remove photos from album. + """Remove photos from album. Note: Photos does not provide a way to remove photos from an album via AppleScript. This method actually creates a new Album with the same name as the original album and copies all photos from original album with exception of those to remove to the new album @@ -757,11 +753,11 @@ def remove(self, photos): return self.remove_by_id(photo_uuids) def spotlight(self): - """ spotlight the album in Photos """ - run_script("_album_spotlight", self.id) + """spotlight the album in Photos""" + run_script("albumSpotlight", self.id) def __len__(self): - return run_script("_album_len", self.id) + return run_script("albumCount", self.id) class Folder: @@ -775,7 +771,7 @@ def __init__(self, uuid): else: uuid = uuid.split("/")[0] - valid_folder = run_script("_folder_exists", id_) + valid_folder = run_script("folderExists", id_) if valid_folder: self.id = id_ self._uuid = uuid @@ -784,41 +780,41 @@ def __init__(self, uuid): @property def uuid(self): - """ UUID of folder""" + """UUID of folder""" return self._uuid @property def name(self): - """ name of folder (read/write) """ - name = run_script("_folder_name", self.id) + """name of folder (read/write)""" + name = run_script("folderName", self.id) return name if name != kMissingValue else "" @name.setter def name(self, name): - """ set name of photo """ + """set name of photo""" name = "" if name is None else name - return run_script("_folder_set_name", self.id, name) + return run_script("folderSetName", self.id, name) @property def title(self): - """ title of folder (alias for Folder.name) """ + """title of folder (alias for Folder.name)""" return self.name @title.setter def title(self, title): - """ set title of folder (alias for name) """ + """set title of folder (alias for name)""" name = "" if title is None else title - return run_script("_folder_set_name", self.id, name) + return run_script("folderSetName", self.id, name) @property def parent_id(self): - """ parent container id """ - return run_script("_folder_parent", self.id) + """parent container id""" + return run_script("folderParent", self.id) # TODO: if no parent should return a "My Albums" object that contains all top-level folders/albums? @property def parent(self): - """ Return parent Folder object """ + """Return parent Folder object""" parent_id = self.parent_id if parent_id != 0: return Folder(parent_id) @@ -838,7 +834,7 @@ def path_str(self, delim="/"): if len(delim) > 1: raise ValueError("delim must be single character") - return run_script("_folder_get_path", self.id, delim) + return run_script("folderGetPath", self.id, delim) def path(self): """Return list of Folder objects this folder is contained in. @@ -846,13 +842,13 @@ def path(self): path()[-1] is the immediate parent of this folder. Returns empty list if folder is not contained in another folders. """ - folder_path = run_script("_folder_path_ids", self.id) + folder_path = run_script("folderPathIDs", self.id) return [Folder(folder) for folder in folder_path] @property def albums(self): - """ list of Album objects for albums contained in folder """ - album_ids = run_script("_folder_albums", self.id) + """list of Album objects for albums contained in folder""" + album_ids = run_script("folderAlbums", self.id) return [Album(uuid) for uuid in album_ids] def album(self, name): @@ -866,8 +862,8 @@ def album(self, name): @property def subfolders(self): - """ list of Folder objects for immediate sub-folders contained in folder """ - folder_ids = run_script("_folder_folders", self.id) + """list of Folder objects for immediate sub-folders contained in folder""" + folder_ids = run_script("folderFolders", self.id) return [Folder(uuid) for uuid in folder_ids] def folder(self, name): @@ -904,11 +900,11 @@ def create_folder(self, name): return PhotosLibrary().create_folder(name, folder=self) def spotlight(self): - """ spotlight the folder in Photos """ - run_script("_folder_spotlight", self.id) + """spotlight the folder in Photos""" + run_script("folderSpotlight", self.id) def __len__(self): - return run_script("_folder_len", self.id) + return run_script("folderCount", self.id) class Photo: @@ -921,7 +917,7 @@ def __init__(self, uuid): id_ = f"{uuid}{UUID_SUFFIX_PHOTO}" else: uuid = uuid.split("/")[0] - valid = run_script("_photo_exists", uuid) + valid = run_script("photoExists", uuid) if valid: self.id = id_ self._uuid = uuid @@ -930,83 +926,83 @@ def __init__(self, uuid): @property def uuid(self): - """ UUID of Photo """ + """UUID of Photo""" return self._uuid @property def name(self): - """ name of photo (read/write) """ - name = run_script("_photo_name", self.id) + """name of photo (read/write)""" + name = run_script("photoName", self.id) return name if name not in [kMissingValue, ""] else "" @name.setter def name(self, name): - """ set name of photo """ + """set name of photo""" name = "" if name is None else name - return run_script("_photo_set_name", self.id, name) + return run_script("photoSetName", self.id, name) @property def title(self): - """ title of photo (alias for name) """ + """title of photo (alias for name)""" return self.name @title.setter def title(self, title): - """ set title of photo (alias for name) """ + """set title of photo (alias for name)""" name = "" if title is None else title - return run_script("_photo_set_name", self.id, name) + return run_script("photoSetName", self.id, name) @property def description(self): - """ description of photo """ - descr = run_script("_photo_description", self.id) + """description of photo""" + descr = run_script("photoDescription", self.id) return descr if descr != kMissingValue else "" @description.setter def description(self, descr): - """ set description of photo """ + """set description of photo""" descr = "" if descr is None else descr - return run_script("_photo_set_description", self.id, descr) + return run_script("photoSetDescription", self.id, descr) @property def keywords(self): - """ list of keywords for photo """ - keywords = run_script("_photo_keywords", self.id) + """list of keywords for photo""" + keywords = run_script("photoKeywords", self.id) if not isinstance(keywords, list): keywords = [keywords] if keywords != kMissingValue else [] return keywords @keywords.setter def keywords(self, keywords): - """ set keywords to list """ + """set keywords to list""" keywords = [] if keywords is None else keywords - return run_script("_photo_set_keywords", self.id, keywords) + return run_script("photoSetKeywords", self.id, keywords) @property def favorite(self): - """ return favorite status (boolean) """ - return run_script("_photo_favorite", self.id) + """return favorite status (boolean)""" + return run_script("photoFavorite", self.id) @favorite.setter def favorite(self, favorite): - """ set favorite status (boolean) """ + """set favorite status (boolean)""" favorite = bool(favorite) - return run_script("_photo_set_favorite", self.id, favorite) + return run_script("photoSetFavorite", self.id, favorite) @property def height(self): - """ height of photo in pixels """ - return run_script("_photo_height", self.id) + """height of photo in pixels""" + return run_script("photoHeight", self.id) @property def width(self): - """ width of photo in pixels """ - return run_script("_photo_width", self.id) + """width of photo in pixels""" + return run_script("photoWidth", self.id) @property def altitude(self): - """ GPS altitude of photo in meters """ - altitude = run_script("_photo_altitude", self.id) + """GPS altitude of photo in meters""" + altitude = run_script("photoAltitude", self.id) return altitude if altitude != kMissingValue else None @property @@ -1014,7 +1010,7 @@ def location(self): """The GPS latitude and longitude, in a tuple of 2 numbers or None. Latitude in range -90.0 to 90.0, longitude in range -180.0 to 180.0. """ - location = run_script("_photo_location", self.id) + location = run_script("photoLocation", self.id) location[0] = None if location[0] == kMissingValue else location[0] location[1] = None if location[1] == kMissingValue else location[1] return tuple(location) @@ -1041,31 +1037,31 @@ def location(self, location): kMissingValue if location[1] is None else location[1], ) - return run_script("_photo_set_location", self.id, location) + return run_script("photoSetLocation", self.id, location) @property def date(self): - """ date of photo as timezone-naive datetime.datetime object """ - return run_script("_photo_date", self.id) + """date of photo as timezone-naive datetime.datetime object""" + return run_script("photoDate", self.id) @date.setter def date(self, date): - """ Set date of photo as timezone-naive datetime.datetime object - + """Set date of photo as timezone-naive datetime.datetime object + Args: date: timezone-naive datetime.datetime object """ - return run_script("_photo_set_date", self.id, date) + return run_script("photoSetDate", self.id, date) @property def filename(self): - """ filename of photo """ - return run_script("_photo_filename", self.id) + """filename of photo""" + return run_script("photoFilename", self.id) @property def albums(self): - """ list of Album objects for albums photo is contained in """ - albums = run_script("_photo_albums", self.id) + """list of Album objects for albums photo is contained in""" + albums = run_script("photoAlbums", self.id) return [Album(album) for album in albums] def export( @@ -1085,19 +1081,19 @@ def export( overwrite: if True, export will overwrite a file of same name as photo in export_path; default = False timeout: number of seconds to wait for Photos to complete export before timing out; default = 120 reveal_in_finder: if True, will open Finder with exported items selected when done; default = False - + Returns: - List of full paths of exported photos. There may be more than one photo exported due + List of full paths of exported photos. There may be more than one photo exported due to live images and burst images. - + Raises: ValueError if export_path is not a valid directory - Note: Photos always exports as high-quality JPEG unless original=True. - If original=True, will export all burst images for burst photos and - live movie for live photos. If original=False, only the primary image from a - burst set will be exported for burst photos and the live movie component of a - live image will not be exported, only the JPEG component. + Note: Photos always exports as high-quality JPEG unless original=True. + If original=True, will export all burst images for burst photos and + live movie for live photos. If original=False, only the primary image from a + burst set will be exported for burst photos and the live movie component of a + live image will not be exported, only the JPEG component. """ return PhotosLibrary()._export_photo( self, @@ -1109,10 +1105,10 @@ def export( ) def duplicate(self): - """ duplicates the photo and returns Photo object for the duplicate """ - dup_id = run_script("_photo_duplicate", self.id) + """duplicates the photo and returns Photo object for the duplicate""" + dup_id = run_script("photoDuplicate", self.id) return Photo(dup_id) def spotlight(self): - """ spotlight the photo in Photos """ - run_script("_photo_spotlight", self.id) + """spotlight the photo in Photos""" + run_script("photoSpotlight", self.id) diff --git a/photoscript/photoscript.applescript b/photoscript/photoscript.applescript index 1544f6c..ad95b83 100644 --- a/photoscript/photoscript.applescript +++ b/photoscript/photoscript.applescript @@ -14,7 +14,7 @@ property WAIT_FOR_PHOTOS : 300 ---------- PhotoLibrary ---------- -on _photoslibrary_waitforphotos(timeoutDurationInSeconds) +on photosLibraryWaitForPhotos(timeoutDurationInSeconds) if running of application "Photos" is false then tell application "Photos" to launch tell current application @@ -35,194 +35,194 @@ on _photoslibrary_waitforphotos(timeoutDurationInSeconds) error number -128 end if return true -end _photoslibrary_waitforphotos +end photosLibraryWaitForPhotos -on _photoslibrary_isrunning() +on photosLibraryIsRunning() (* return true if Photos is running, otherwise false *) - set app_name_ to "Photos" + set theApp to "Photos" - if application app_name_ is running then + if application theApp is running then return true else return false end if -end _photoslibrary_isrunning +end photosLibraryIsRunning -on _photoslibrary_hide() +on photosLibraryHide() (* tell Photos to hide if it's running; if not running, do nothing *) - set app_name_ to "Photos" + set theApp to "Photos" try tell application "System Events" - set visible of application process app_name_ to false + set visible of application process theApp to false end tell end try -end _photoslibrary_hide +end photosLibraryHide -on _photoslibrary_hidden() +on photosLibraryIsHidden() (* return true if hidden or not running, otherwise false *) - set app_name_ to "Photos" + set theApp to "Photos" try tell application "System Events" - return not visible of application process app_name_ + return not visible of application process theApp end tell on error return true end try -end _photoslibrary_hidden +end photosLibraryIsHidden -on _photoslibrary_activate() +on photosLibraryActivate() (* activate Photos app *) tell application "Photos" activate end tell -end _photoslibrary_activate +end photosLibraryActivate -on _photoslibrary_quit() +on photosLibraryQuit() (* quit Photos app *) tell application "Photos" quit end tell -end _photoslibrary_quit +end photosLibraryQuit -on _photoslibrary_name() +on photosLibraryName() (* name of application *) tell application "Photos" return name end tell -end _photoslibrary_name +end photosLibraryName -on _photoslibrary_version() +on photosLibraryVersion() (* Photos version *) tell application "Photos" return version end tell -end _photoslibrary_version +end photosLibraryVersion -on _photoslibrary_frontmost() +on photosLibraryIsFrontMost() (* returns true if front most app, otherwise false *) tell application "Photos" return frontmost end tell -end _photoslibrary_frontmost +end photosLibraryIsFrontMost -on _photoslibrary_get_all_photos() +on photosLibraryGetAllPhotos() (* return all photos in the library *) tell application "Photos" - set ids to id of media items + set theIDs to id of media items end tell - return ids -end _photoslibrary_get_all_photos + return theIDs +end photosLibraryGetAllPhotos -on _photoslibrary_get_photo_by_number(num_) +on photosLibraryGetPhotoByNumber(photoNumber) (* return photo number num_; uses Photos' internal numbering *) tell application "Photos" - return id of media item num_ + return id of media item photoNumber end tell -end _photoslibrary_get_photo_by_number +end photosLibraryGetPhotoByNumber -on _photoslibrary_get_photo_by_range(start_, stop_) +on photosLibraryGetPhotoByRange(startNumber, stopNumber) (* return photos in range (inclusive); uses Photos' internal numbering *) tell application "Photos" - return id of media items start_ thru stop_ + return id of media items startNumber thru stopNumber end tell -end _photoslibrary_get_photo_by_range +end photosLibraryGetPhotoByRange -on _photoslibrary_search_photos(search_str) +on photosLibrarySearchPhotos(searchString) (* search for photos by text string *) - set ids to {} + set theIDs to {} tell application "Photos" - set _items to search for search_str - repeat with _item in _items - copy id of _item to end of ids + set theItems to search for searchString + repeat with anItem in theItems + copy id of anItem to end of theIDs end repeat end tell - return ids -end _photoslibrary_search_photos + return theIDs +end photosLibrarySearchPhotos -on _photoslibrary_count() +on photosLibraryCount() (* return count of photos in the library *) tell application "Photos" set mediaItemCount to (count of media items) return mediaItemCount end tell -end _photoslibrary_count - -on _photoslibrary_import(filenames, skip_duplicate_check) - (* import files - Args: - filenames: list of files in POSIX format to import - skip_duplicate_check: boolean, if True, skips checking for duplicates - Returns: - list of item IDs for imported items +end photosLibraryCount + +on photosLibraryImport(filenames, skipDuplicateCheck) + (* import files + Args: + filenames: list of files in POSIX format to import + skipDuplicateCheck: boolean, if True, skips checking for duplicates + Returns: + list of item IDs for imported items *) - set file_list to {} + set fileList to {} repeat with f in filenames set fname to POSIX file f - copy fname to the end of file_list + copy fname to the end of fileList end repeat - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" - set items_ to import file_list skip check duplicates skip_duplicate_check - if items_ = missing value then + set theItems to import fileList skip check duplicates skipDuplicateCheck + if theItems = missing value then return {} end if - set item_list_ to {} - repeat with item_ in items_ - copy id of item_ to end of item_list_ + set itemList to {} + repeat with theItem in theItems + copy id of theItem to end of itemList end repeat - return item_list_ + return itemList end tell -end _photoslibrary_import +end photosLibraryImport -on _photoslibrary_import_to_album(filenames, album_, skip_duplicate_check) +on photosLibraryImportToAlbum(filenames, albumID, skipDuplicateCheck) (* import files into album Args: filenames: list of files in POSIX format to import - album_name: name of album to import to - skip_duplicate_check: boolean, if True, skips checking for duplicates + albumID: ID of album to import to + skipDuplicateCheck: boolean, if True, skips checking for duplicates Returns: list of item IDs for imported items *) - set file_list to {} + set fileList to {} repeat with f in filenames set fname to POSIX file f - copy fname to the end of file_list + copy fname to the end of fileList end repeat tell application "Photos" - set items_ to import file_list into album id (album_) skip check duplicates skip_duplicate_check - if items_ = missing value then + set theItems to import fileList into album id (albumID) skip check duplicates skipDuplicateCheck + if theItems = missing value then return {} end if - set item_list_ to {} - repeat with item_ in items_ - copy id of item_ to end of item_list_ + set itemList to {} + repeat with theItem in theItems + copy id of theItem to end of itemList end repeat - return item_list_ + return itemList end tell -end _photoslibrary_import_to_album +end photosLibraryImportToAlbum -on _photoslibrary_album_names(top_level) +on photosLibraryAlbumNames(topLevel) (* return list of album names found in Photos *) - set albums_folders to _photoslibrary_get_album_folder_names(top_level) + set albums_folders to photosLibraryGetAlbumFolderNames(topLevel) return album_names of albums_folders -end _photoslibrary_album_names +end photosLibraryAlbumNames -on _photoslibrary_folder_names(top_level) +on photosLibraryFolderNames(topLevel) (* return list of folder names found in Photos *) - set albums_folders to _photoslibrary_get_album_folder_names(top_level) + set albums_folders to photosLibraryGetAlbumFolderNames(topLevel) return folder_names of albums_folders -end _photoslibrary_folder_names +end photosLibraryFolderNames -on _photoslibrary_get_albums_folders() +on photosLibraryGetAlbumsFolders() (* return record containing album names and folder names in the library Returns: {album_names:list of album names, folder_names:list of folder names} *) # see https://discussions.apple.com/docs/DOC-250002459 tell application "Photos" - set allfolders to {} - set allalbums to the albums -- collect all albums + set allFolders to {} + set allAlbums to the albums -- collect all albums set level to 0 -- nesting level of folders set nextlevelFolders to the folders @@ -236,94 +236,94 @@ on _photoslibrary_get_albums_folders() set ffolders to its folders set falbums to its albums set nextlevelFolders to ffolders & nextlevelFolders - set allalbums to falbums & allalbums + set allAlbums to falbums & allAlbums end tell end repeat - set allfolders to currentLevelFolders & allfolders + set allFolders to currentLevelFolders & allFolders set level to level + 1 end repeat end tell - set albums_folders to {_albums:allalbums, _folders:allfolders} + set albums_folders to {_albums:allAlbums, _folders:allFolders} return albums_folders -end _photoslibrary_get_albums_folders +end photosLibraryGetAlbumsFolders -on _photoslibrary_get_top_level_albums_folders() +on photosLibraryGetTopLevelAlbumsFolders() (* return record containing album names and folder names in the library Returns: {album_names:list of album names, folder_names:list of folder names} *) tell application "Photos" - set allfolders_ to the folders - set allalbums_ to the albums + set allFolders to the folders + set allAlbums to the albums -- On Mojave, this returns all albums and folders so filter only those with no parents - set allfolders to {} - set allalbums to {} - repeat with folder_ in allfolders_ + set allFoldersFiltered to {} + set allAlbumsFiltered to {} + repeat with folder_ in allFolders try - set parent_id_ to id of parent of folder_ + set parentID to id of parent of folder_ on error -- no parent set top_folder_ to folder id (id of folder_) - copy top_folder_ to end of allfolders + copy top_folder_ to end of allFoldersFiltered end try end repeat - repeat with album_ in allalbums_ + repeat with album_ in allAlbums try - set parent_id_ to id of parent of album_ + set parentID to id of parent of album_ on error -- no parent - set top_album_ to album id (id of album_) - copy top_album_ to end of allalbums + set topAlbum to album id (id of album_) + copy topAlbum to end of allAlbumsFiltered end try end repeat end tell - set albums_folders to {_albums:allalbums, _folders:allfolders} + set albums_folders to {_albums:allAlbumsFiltered, _folders:allFoldersFiltered} return albums_folders -end _photoslibrary_get_top_level_albums_folders +end photosLibraryGetTopLevelAlbumsFolders -on _photoslibrary_get_album_folder_names(top_level) +on photosLibraryGetAlbumFolderNames(topLevel) (* return names of albums and folders *) - if top_level then - set albums_folders to _photoslibrary_get_top_level_albums_folders() + if topLevel then + set albums_folders to photosLibraryGetTopLevelAlbumsFolders() else - set albums_folders to _photoslibrary_get_albums_folders() + set albums_folders to photosLibraryGetAlbumsFolders() end if - set allalbums to _albums of albums_folders - set allfolders to _folders of albums_folders - set allalbumnames to {} - set allfoldernames to {} + set allAlbums to _albums of albums_folders + set allFolders to _folders of albums_folders + set allAlbumNames to {} + set allFolderNames to {} tell application "Photos" - repeat with _album in allalbums + repeat with _album in allAlbums set theName to name of _album - copy theName to end of allalbumnames + copy theName to end of allAlbumNames end repeat - repeat with _folder in allfolders + repeat with _folder in allFolders set theName to name of _folder - copy theName to end of allfoldernames + copy theName to end of allFolderNames end repeat end tell - set album_folder_names to {album_names:allalbumnames, folder_names:allfoldernames} - return album_folder_names -end _photoslibrary_get_album_folder_names + set albumfolderNames to {album_names:allAlbumNames, folder_names:allFolderNames} + return albumfolderNames +end photosLibraryGetAlbumFolderNames -on _photoslibrary_album_ids(top_level) +on photosLibraryAlbumIDs(topLevel) (* return list of album ids found in Photos Args: - top_level: boolean; if true returns only top-level albums otherwise all albums + topLevel: boolean; if true returns only top-level albums otherwise all albums *) - if top_level then + if topLevel then tell application "Photos" return id of every album end tell else - set albums_folders to _photoslibrary_get_albums_folders() + set albums_folders to photosLibraryGetAlbumsFolders() set _albums to _albums of albums_folders set _ids to {} repeat with _a in _albums @@ -331,18 +331,18 @@ on _photoslibrary_album_ids(top_level) end repeat return _ids end if -end _photoslibrary_album_ids +end photosLibraryAlbumIDs -on _photoslibrary_folder_ids(top_level) +on photosLibraryFolderIDs(topLevel) (* return list of folder ids found in Photos Args: - top_level: boolean; if true returns only top-level folders otherwise all folders + topLevel: boolean; if true returns only top-level folders otherwise all folders *) - if top_level then - set albums_folders to _photoslibrary_get_top_level_albums_folders() + if topLevel then + set albums_folders to photosLibraryGetTopLevelAlbumsFolders() else - set albums_folders to _photoslibrary_get_albums_folders() + set albums_folders to photosLibraryGetAlbumsFolders() end if set _folders to _folders of albums_folders set _ids to {} @@ -350,18 +350,18 @@ on _photoslibrary_folder_ids(top_level) copy id of _f to end of _ids end repeat return _ids -end _photoslibrary_folder_ids +end photosLibraryFolderIDs -on _photoslibrary_folder_id_lists(top_level) +on photosLibraryFolderIDLists(topLevel) (* return list of folder ids found in Photos as list of ids Args: - top_level: boolean; if true returns only top-level folders otherwise all folders + topLevel: boolean; if true returns only top-level folders otherwise all folders *) - if top_level then - set albums_folders to _photoslibrary_get_top_level_albums_folders() + if topLevel then + set albums_folders to photosLibraryGetTopLevelAlbumsFolders() else - set albums_folders to _photoslibrary_get_albums_folders() + set albums_folders to photosLibraryGetAlbumsFolders() end if set _folders to _folders of albums_folders set _id_list to {} @@ -369,8 +369,8 @@ on _photoslibrary_folder_id_lists(top_level) set folder_ids_ to {id of _f} try repeat - set parent_id_ to id of parent of _f - copy parent_id_ to end of folder_ids_ + set parentID to id of parent of _f + copy parentID to end of folder_ids_ set _f to parent of _f end repeat on error @@ -378,16 +378,16 @@ on _photoslibrary_folder_id_lists(top_level) end try end repeat return _id_list -end _photoslibrary_folder_id_lists +end photosLibraryFolderIDLists -on _photoslibrary_create_album(albumName) +on photosLibraryCreateAlbum(albumName) (* creates album named albumName does not check for duplicate album Returns: UUID of newly created album or 0 if error *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" set count_ to 0 repeat while count_ < MAX_RETRY @@ -401,16 +401,16 @@ on _photoslibrary_create_album(albumName) end repeat return 0 end tell -end _photoslibrary_create_album +end photosLibraryCreateAlbum -on _photoslibrary_create_album_at_folder(albumName, folder_id_) +on photosLibraryCreateAlbumAtFolder(albumName, folder_id_) (* creates album named albumName inside folder folder_id_ does not check for duplicate album Returns: UUID of newly created album or 0 if error *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) - set folder_ to _folder_get_folder_for_id(folder_id_) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) + set folder_ to folderGetFolderForID(folder_id_) tell application "Photos" set count_ to 0 repeat while count_ < MAX_RETRY @@ -424,49 +424,49 @@ on _photoslibrary_create_album_at_folder(albumName, folder_id_) end repeat return 0 end tell -end _photoslibrary_create_album_at_folder +end photosLibraryCreateAlbumAtFolder -on _photoslibrary_get_selection() +on photosLibraryGetSelection() (* return ids of selected items *) - set item_ids_ to {} + set theItemids_ to {} tell application "Photos" - set items_ to selection - repeat with item_ in items_ - copy id of item_ to end of item_ids_ + set theItems to selection + repeat with theItem in theItems + copy id of theItem to end of theItemids_ end repeat end tell - return item_ids_ -end _photoslibrary_get_selection + return theItemids_ +end photosLibraryGetSelection -on _photoslibrary_favorites() +on photosLibraryFavorites() (* return favorites album *) tell application "Photos" return id of favorites album end tell -end _photoslibrary_favorites +end photosLibraryFavorites -on _photoslibrary_recently_deleted() +on photosLibraryRecentlyDeleted() (* return recently deleted album *) tell application "Photos" return id of recently deleted album end tell -end _photoslibrary_recently_deleted +end photosLibraryRecentlyDeleted -on _photoslibrary_delete_album(id_) +on photosLibraryDeleteAlbum(id_) (* delete album with id_ *) tell application "Photos" set album_ to album id (id_) delete album_ end tell -end _photoslibrary_delete_album +end photosLibraryDeleteAlbum -on _photoslibrary_create_folder(folderName) +on photosLibraryCreateFolder(folderName) (* creates folder named folderName does not check for duplicate folder Returns: UUID of newly created folder or 0 if error *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" set count_ to 0 repeat while count_ < MAX_RETRY @@ -480,16 +480,16 @@ on _photoslibrary_create_folder(folderName) end repeat return 0 end tell -end _photoslibrary_create_folder +end photosLibraryCreateFolder -on _photoslibrary_create_folder_at_folder(folderName, folder_id_) +on photosLibraryCreateFolderAtFolder(folderName, folder_id_) (* creates folder named folderName inside folder folder_id_ does not check for duplicate folder Returns: UUID of newly created folder *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) - set folder_ to _folder_get_folder_for_id(folder_id_) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) + set folder_ to folderGetFolderForID(folder_id_) tell application "Photos" set count_ to 0 repeat while count_ < MAX_RETRY @@ -503,36 +503,36 @@ on _photoslibrary_create_folder_at_folder(folderName, folder_id_) end repeat return 0 end tell -end _photoslibrary_create_folder_at_folder +end photosLibraryCreateFolderAtFolder -on _photoslibrary_delete_folder(id_) +on photosLibraryDeleteFolder(id_) (* delete folder with id_ *) - set folder_ to _folder_get_folder_for_id(id_) + set folder_ to folderGetFolderForID(id_) tell application "Photos" delete folder_ end tell -end _photoslibrary_delete_folder +end photosLibraryDeleteFolder (* -on _photoslibrary_delete_folder(_id) +on photosLibraryDeleteFolder(_id) --TODO: doesn't currently work - _photoslibrary_waitforphotos(300) - set _folder_ids to _photoslibrary_internal_path_ids_to_album_folder(_folder_get_folder_for_id(_id)) + photosLibraryWaitForPhotos(300) + set _folder_ids to photosLibraryInternalPathIDsToAlbumFolder(folderGetFolderForID(_id)) tell application "Photos" set folder_ to folder id (item 1 of _folder_ids) set _folder_ids to rest of _folder_ids repeat with _folder_id in _folder_ids - set folder_ to _folder_get_folder_for_id(_folder_id) + set folder_ to folderGetFolderForID(_folder_id) end repeat say (name of folder_ as text) delete (folder_) end tell -end _photoslibrary_delete_folder +end photosLibraryDeleteFolder *) -on _photoslibrary_internal_path_to_album_folder(targetObject, pathItemDelimiter) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) +on photosLibraryInternalPathToAlbumFolder(targetObject, pathItemDelimiter) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" if not (exists targetObject) then error "The indicated item does not exist." @@ -551,17 +551,17 @@ on _photoslibrary_internal_path_to_album_folder(targetObject, pathItemDelimiter) set folderName to name of parent of targetObject set parentID to id of parent of targetObject set pathToObject to folderName & pathItemDelimiter & pathToObject - set targetObject to _folder_get_folder_for_id(parentID) + set targetObject to folderGetFolderForID(parentID) on error return pathToObject end try end repeat -end _photoslibrary_internal_path_to_album_folder +end photosLibraryInternalPathToAlbumFolder -on _photoslibrary_internal_path_ids_to_album_folder(targetObject) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) +on photosLibraryInternalPathIDsToAlbumFolder(targetObject) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" if not (exists targetObject) then error "The indicated item does not exist." @@ -580,32 +580,32 @@ on _photoslibrary_internal_path_ids_to_album_folder(targetObject) set folderID to id of parent of targetObject set parentID to id of parent of targetObject copy folderID to beginning of pathToObject - set targetObject to _folder_get_folder_for_id(parentID) + set targetObject to folderGetFolderForID(parentID) on error return pathToObject end try end repeat -end _photoslibrary_internal_path_ids_to_album_folder +end photosLibraryInternalPathIDsToAlbumFolder ---------- Album ---------- -on _album_name(_id) +on albumName(_id) (* return name of album with id _id *) tell application "Photos" return name of album id (_id) end tell -end _album_name +end albumName -on _album_by_name(name_, top_level_) +on albumByName(name_, topLevel) (* return album id of album named name_ or 0 if no album found with name_ if more than one album named name_, returns the first one found - if top_level_ = true, returns only top level albums + if topLevel = true, returns only top level albums *) - if top_level_ then - set albums_folders_ to _photoslibrary_get_top_level_albums_folders() + if topLevel then + set albums_folders_ to photosLibraryGetTopLevelAlbumsFolders() else - set albums_folders_ to _photoslibrary_get_albums_folders() + set albums_folders_ to photosLibraryGetAlbumsFolders() end if set _albums to _albums of albums_folders_ repeat with _a in _albums @@ -614,11 +614,11 @@ on _album_by_name(name_, top_level_) end if end repeat return 0 -end _album_by_name +end albumByName -on _album_exists(_id) +on albumExists(_id) (* return true if album with _id exists otherwise false *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" try set _exist to album id (_id) @@ -628,9 +628,9 @@ on _album_exists(_id) return true end tell -end _album_exists +end albumExists -on _album_parent(_id) +on albumParent(_id) (* returns parent folder id of album or 0 if no parent *) try tell application "Photos" @@ -639,9 +639,9 @@ on _album_parent(_id) on error return 0 end try -end _album_parent +end albumParent -on _album_photos(id_) +on albumPhotes(id_) (* return list of ids for media items in album _id *) set ids to {} tell application "Photos" @@ -652,38 +652,38 @@ on _album_photos(id_) end repeat end tell return ids -end _album_photos +end albumPhotes -on _album_len(id_) +on albumCount(id_) (* return count of items in albums *) tell application "Photos" return count of media items in album id (id_) end tell -end _album_len +end albumCount -on _album_add(id_, items_) +on albumAdd(id_, theItems) (* add media items to album Args: id_: id of album - items_: list of media item ids + theItems: list of media item ids Returns: list of media item ids added *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" - if items_ = {} then + if theItems = {} then return {} end if set media_list_ to {} - repeat with item_ in items_ - copy media item id (item_) to end of media_list_ + repeat with theItem in theItems + copy media item id (theItem) to end of media_list_ end repeat set media_id_list_ to {} - repeat with item_ in media_list_ - copy id of item_ to end of media_id_list_ + repeat with theItem in media_list_ + copy id of theItem to end of media_id_list_ end repeat set album_ to album id (id_) @@ -708,11 +708,11 @@ on _album_add(id_, items_) return media_id_list_ end tell -end _album_add +end albumAdd -on _album_set_name(_id, _title) +on albumSetName(_id, _title) (* set name or title of album *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) set count_ to 0 repeat while count_ < MAX_RETRY tell application "Photos" @@ -723,38 +723,38 @@ on _album_set_name(_id, _title) end tell set count_ to count_ + 1 end repeat -end _album_set_name +end albumSetName -on _album_get_path(id_, path_delimiter_) +on albumGetPath(id_, path_delimiter_) (* return path to album as a string *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" set album_ to album id (id_) end tell try - set path_ to _photoslibrary_internal_path_to_album_folder(album_, path_delimiter_) + set path_ to photosLibraryInternalPathToAlbumFolder(album_, path_delimiter_) on error set path_ to "" end try return path_ -end _album_get_path +end albumGetPath -on _album_spotlight(id_) +on albumSpotlight(id_) (* spotlight album *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" activate spotlight album id (id_) end tell -end _album_spotlight +end albumSpotlight ---------- Folder ---------- -on _folder_get_folder_for_id(_id) +on folderGetFolderForID(_id) (* return folder for _id *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) - set albums_folders to _photoslibrary_get_albums_folders() + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) + set albums_folders to photosLibraryGetAlbumsFolders() set _folders to _folders of albums_folders tell application "Photos" repeat with _folder in _folders @@ -765,12 +765,12 @@ on _folder_get_folder_for_id(_id) end repeat return missing value end tell -end _folder_get_folder_for_id +end folderGetFolderForID -on _folder_exists(_id) +on folderExists(_id) (* return true if folder with _id exists otherwise false *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) - set version_ to _photoslibrary_version() as number + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) + set version_ to photosLibraryVersion() as number if version_ < 5 then tell application "Photos" try @@ -782,28 +782,28 @@ on _folder_exists(_id) return true end tell else - set _exist to _folder_get_folder_for_id(_id) + set _exist to folderGetFolderForID(_id) if _exist is not missing value then return true else return false end if end if -end _folder_exists +end folderExists -on _folder_name(_id) +on folderName(_id) (* return name of folder with id _id *) - set folder_ to _folder_get_folder_for_id(_id) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + set folder_ to folderGetFolderForID(_id) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" return name of folder_ end tell -end _folder_name +end folderName -on _folder_set_name(_id, _title) +on folderSetName(_id, _title) (* set name or title of folder *) - set folder_ to _folder_get_folder_for_id(_id) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + set folder_ to folderGetFolderForID(_id) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) set count_ to 0 repeat while count_ < MAX_RETRY tell application "Photos" @@ -814,26 +814,26 @@ on _folder_set_name(_id, _title) end tell set count_ to count_ + 1 end repeat -end _folder_set_name +end folderSetName -on _folder_parent(_id) +on folderParent(_id) (* returns parent folder id of folder or 0 if no parent *) try - set folder_ to _folder_get_folder_for_id(_id) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + set folder_ to folderGetFolderForID(_id) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" return id of parent of folder_ end tell on error return 0 end try -end _folder_parent +end folderParent -on _folder_albums(id_) +on folderAlbums(id_) (* return list of ids for albums in folder id_ *) set ids to {} - set _folder to _folder_get_folder_for_id(id_) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + set _folder to folderGetFolderForID(id_) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" set _albums to albums of _folder repeat with _album in _albums @@ -841,13 +841,13 @@ on _folder_albums(id_) end repeat end tell return ids -end _folder_albums +end folderAlbums -on _folder_folders(id_) +on folderFolders(id_) (* return list of ids for folders in folder id_ *) set ids to {} - set _folder to _folder_get_folder_for_id(id_) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + set _folder to folderGetFolderForID(id_) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" set _folders to folders of _folder repeat with _f in _folders @@ -855,29 +855,29 @@ on _folder_folders(id_) end repeat end tell return ids -end _folder_folders +end folderFolders -on _folder_len(id_) +on folderCount(id_) (* return count of items (albums and folders) in folder id_*) - set folder_ to _folder_get_folder_for_id(id_) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + set folder_ to folderGetFolderForID(id_) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" set _albums_count to (count of albums in folder_) set _folders_count to (count of folders in folder_) set _len to _albums_count + _folders_count return _len end tell -end _folder_len +end folderCount -on _folder_by_name(name_, top_level_) +on folderByName(name_, topLevel) (* return folder id of folder named name_ or 0 if no folder found with name_ if more than one folder named name_, returns the first one found - if top_level_ = true, returns only top level folder + if topLevel = true, returns only top level folder *) - if top_level_ then - set albums_folders_ to the _photoslibrary_get_top_level_albums_folders() + if topLevel then + set albums_folders_ to the photosLibraryGetTopLevelAlbumsFolders() else - set albums_folders_ to _photoslibrary_get_albums_folders() + set albums_folders_ to photosLibraryGetAlbumsFolders() end if set _folders to _folders of albums_folders_ repeat with _f in _folders @@ -886,9 +886,9 @@ on _folder_by_name(name_, top_level_) end if end repeat return 0 -end _folder_by_name +end folderByName -on _folder_by_path(folder_path_) +on folderByPath(folder_path_) (* return folder id for folder by path Args: folder_path_: list of folder names, e.g. {"Folder","SubFolder", "SubSubFolder"} @@ -896,9 +896,9 @@ on _folder_by_path(folder_path_) Returns: folder id or 0 if not found *) - set top_level_folders to _folders of _photoslibrary_get_top_level_albums_folders() + set topLevelfolders to _folders of photosLibraryGetTopLevelAlbumsFolders() set folder_ to missing value - repeat with f_ in top_level_folders + repeat with f_ in topLevelfolders if name of f_ = item 1 of folder_path_ then set folder_ to f_ end if @@ -907,7 +907,7 @@ on _folder_by_path(folder_path_) return 0 end if set folder_path_ to rest of folder_path_ - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" try repeat with folder_name_ in folder_path_ @@ -920,44 +920,44 @@ on _folder_by_path(folder_path_) end try end tell return id of folder_ -end _folder_by_path +end folderByPath -on _folder_get_path(id_, path_delimiter_) +on folderGetPath(id_, path_delimiter_) (* return path to folder as a string *) - set folder_ to _folder_get_folder_for_id(id_) + set folder_ to folderGetFolderForID(id_) try - set path_ to _photoslibrary_internal_path_to_album_folder(folder_, path_delimiter_) + set path_ to photosLibraryInternalPathToAlbumFolder(folder_, path_delimiter_) on error set path_ to "" end try return path_ -end _folder_get_path +end folderGetPath -on _folder_path_ids(id_) +on folderPathIDs(id_) (* return path to folder as a string *) - set folder_ to _folder_get_folder_for_id(id_) + set folder_ to folderGetFolderForID(id_) try - set path_ids_ to _photoslibrary_internal_path_ids_to_album_folder(folder_) + set path_ids_ to photosLibraryInternalPathIDsToAlbumFolder(folder_) on error set path_ids_ to {} end try return path_ids_ -end _folder_path_ids +end folderPathIDs -on _folder_spotlight(id_) +on folderSpotlight(id_) (* spotlight folder *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" activate spotlight folder id (id_) end tell -end _folder_spotlight +end folderSpotlight ---------- Photo ---------- -on _photo_exists(_id) +on photoExists(_id) (* return true if media item with _id exists otherwise false *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" try set _exist to media item id (_id) @@ -967,19 +967,19 @@ on _photo_exists(_id) return true end tell -end _photo_exists +end photoExists -on _photo_name(_id) +on photoName(_id) (* name or title of photo *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" return name of media item id (_id) end tell -end _photo_name +end photoName -on _photo_set_name(_id, _title) +on photoSetName(_id, _title) (* set name or title of photo *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) set count_ to 0 repeat while count_ < MAX_RETRY tell application "Photos" @@ -990,19 +990,19 @@ on _photo_set_name(_id, _title) end tell set count_ to count_ + 1 end repeat -end _photo_set_name +end photoSetName -on _photo_description(_id) +on photoDescription(_id) (* description of photo *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" return description of media item id (_id) end tell -end _photo_description +end photoDescription -on _photo_set_description(_id, _descr) +on photoSetDescription(_id, _descr) (* set description of photo *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) set count_ to 0 repeat while count_ < MAX_RETRY tell application "Photos" @@ -1013,19 +1013,19 @@ on _photo_set_description(_id, _descr) end tell set count_ to count_ + 1 end repeat -end _photo_set_description +end photoSetDescription -on _photo_keywords(_id) +on photoKeywords(_id) (* keywords of photo *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" return keywords of media item id (_id) end tell -end _photo_keywords +end photoKeywords -on _photo_set_keywords(id_, keyword_list) +on photoSetKeywords(id_, keyword_list) (* set keywords of photo *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) set count_ to 0 repeat while count_ < MAX_RETRY tell application "Photos" @@ -1036,18 +1036,18 @@ on _photo_set_keywords(id_, keyword_list) end tell set count_ to count_ + 1 end repeat -end _photo_set_keywords +end photoSetKeywords -on _photo_favorite(id_) +on photoFavorite(id_) (* return favorite status of photo *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" return favorite of media item id (id_) end tell -end _photo_favorite +end photoFavorite -on _photo_set_favorite(id_, favorite_) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) +on photoSetFavorite(id_, favorite_) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) set count_ to 0 repeat while count_ < MAX_RETRY tell application "Photos" @@ -1058,19 +1058,19 @@ on _photo_set_favorite(id_, favorite_) end tell set count_ to count_ + 1 end repeat -end _photo_set_favorite +end photoSetFavorite -on _photo_date(_id) +on photoDate(_id) (* date of photo *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" return date of media item id (_id) end tell -end _photo_date +end photoDate -on _photo_set_date(id_, date_) +on photoSetDate(id_, date_) (* set date of photo *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) set count_ to 0 repeat while count_ < MAX_RETRY tell application "Photos" @@ -1081,43 +1081,43 @@ on _photo_set_date(id_, date_) end tell set count_ to count_ + 1 end repeat -end _photo_set_date +end photoSetDate -on _photo_height(id_) +on photoHeight(id_) (* height of photo in pixels *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" return height of media item id (id_) end tell -end _photo_height +end photoHeight -on _photo_width(id_) +on photoWidth(id_) (* width of photo in pixels *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" return width of media item id (id_) end tell -end _photo_width +end photoWidth -on _photo_altitude(id_) +on photoAltitude(id_) (* GPS altitude of photo in meters *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" return altitude of media item id (id_) end tell -end _photo_altitude +end photoAltitude -on _photo_location(id_) +on photoLocation(id_) (* GPS location of photo *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" return location of media item id (id_) end tell -end _photo_location +end photoLocation -on _photo_set_location(id_, location_) +on photoSetLocation(id_, location_) (* set GPS location of photo *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) set count_ to 0 repeat while count_ < MAX_RETRY tell application "Photos" @@ -1128,17 +1128,17 @@ on _photo_set_location(id_, location_) end tell set count_ to count_ + 1 end repeat -end _photo_set_location +end photoSetLocation -on _photo_albums(id_) +on photoAlbums(id_) (* album ids for albums photo id_ is contained in Args: id_: id of the photo Returns: list of album ids containing photo id_ *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) - set _albums_folders to _photoslibrary_get_albums_folders() + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) + set _albums_folders to photosLibraryGetAlbumsFolders() set _album_ids to {} tell application "Photos" repeat with _album in _albums of _albums_folders @@ -1148,9 +1148,9 @@ on _photo_albums(id_) end repeat end tell return _album_ids -end _photo_albums +end photoAlbums -on _photo_export(theUUID, thePath, original, edited, theTimeOut) +on photoExport(theUUID, thePath, original, edited, theTimeOut) (* export photo Args: theUUID: id of the photo to export @@ -1159,7 +1159,7 @@ on _photo_export(theUUID, thePath, original, edited, theTimeOut) edited: boolean, if true, exports edited photo theTimeOut: how long to wait in case Photos timesout *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" set thePath to thePath set theItem to media item id theUUID @@ -1181,51 +1181,51 @@ on _photo_export(theUUID, thePath, original, edited, theTimeOut) return theFilename end tell -end _photo_export +end photoExport -on _photo_filename(id_) +on photoFilename(id_) (* original filename of the photo *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" return filename of media item id (id_) end tell -end _photo_filename +end photoFilename -on _photo_duplicate(id_) +on photoDuplicate(id_) (* duplicate photo *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" set _new_photo to duplicate media item id (id_) return id of _new_photo end tell -end _photo_duplicate +end photoDuplicate -on _photo_spotlight(id_) +on photoSpotlight(id_) (* spotlight photo *) - _photoslibrary_waitforphotos(WAIT_FOR_PHOTOS) + photosLibraryWaitForPhotos(WAIT_FOR_PHOTOS) tell application "Photos" activate spotlight media item id (id_) end tell -end _photo_spotlight +end photoSpotlight --------- Utilities ---------- use framework "Foundation" -on _reveal_in_finder(item_list_) - (* reveal list of POSIX paths in item_list_ in Finder *) - if the class of item_list_ is not list then set item_list_ to item_list as list +on revealInFinder(itemList) + (* reveal list of POSIX paths in itemList in Finder *) + if the class of itemList is not list then set itemList to theItemlist as list -- reveal items in file viewer tell current application's NSWorkspace to set theWorkspace to sharedWorkspace() - tell theWorkspace to activateFileViewerSelectingURLs:item_list_ -end _reveal_in_finder + tell theWorkspace to activateFileViewerSelectingURLs:itemList +end revealInFinder --------- Test ---------- (* tell application "Photos" set folder_ to folder id ("65E8932D-5746-465A-8B64-EE1FA2EB0B4A/L0/020") of folder id ("216F08FA-5F50-4944-99DA-042C1AEDFAEC/L0/020") --set folder_ to folder id ("216F08FA-5F50-4944-99DA-042C1AEDFAEC/L0/020") end tell *) ---_photoslibrary_get_albums_folders() ---_folder_get_folder_for_id("211E9B61-1D23-4E75-8CA2-62146A0391E1/L0/020") ---_folder_exists("211E9B61-1D23-4E75-8CA2-62146A0391E1/L0/020") +--photosLibraryGetAlbumsFolders() +--folderGetFolderForID("211E9B61-1D23-4E75-8CA2-62146A0391E1/L0/020") +--folderExists("211E9B61-1D23-4E75-8CA2-62146A0391E1/L0/020") diff --git a/poetry.lock b/poetry.lock index b15e469..60747ab 100644 --- a/poetry.lock +++ b/poetry.lock @@ -22,7 +22,7 @@ tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy [[package]] name = "Babel" -version = "2.10.3" +version = "2.11.0" description = "Internationalization utilities" category = "dev" optional = false @@ -107,11 +107,11 @@ unicode_backport = ["unicodedata2"] [[package]] name = "colorama" -version = "0.4.5" +version = "0.4.6" description = "Cross-platform colored terminal text." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" [[package]] name = "commonmark" @@ -126,7 +126,7 @@ test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] [[package]] name = "cryptography" -version = "38.0.1" +version = "38.0.3" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "dev" optional = false @@ -151,6 +151,17 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "exceptiongroup" +version = "1.0.1" +description = "Backport of PEP 654 (exception groups)" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "flaky" version = "3.7.0" @@ -242,21 +253,21 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "keyring" -version = "23.9.3" +version = "23.11.0" description = "Store and access your passwords safely." category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] -importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""} +importlib-metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""} "jaraco.classes" = "*" jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} pywin32-ctypes = {version = "<0.1.0 || >0.1.0,<0.1.1 || >0.1.1", markers = "sys_platform == \"win32\""} SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} [package.extras] -docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [[package]] @@ -289,11 +300,11 @@ python-versions = "*" [[package]] name = "more-itertools" -version = "8.14.0" +version = "9.0.0" description = "More routines for operating on iterables, beyond itertools" category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" [[package]] name = "packaging" @@ -340,14 +351,6 @@ python-versions = ">=3.6" dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - [[package]] name = "py-applescript" version = "1.0.3" @@ -382,46 +385,46 @@ plugins = ["importlib-metadata"] [[package]] name = "pyobjc-core" -version = "8.5.1" +version = "9.0" description = "Python<->ObjC Interoperability Module" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "pyobjc-framework-AppleScriptKit" -version = "8.5.1" +version = "9.0" description = "Wrappers for the framework AppleScriptKit on macOS" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -pyobjc-core = ">=8.5.1" -pyobjc-framework-Cocoa = ">=8.5.1" +pyobjc-core = ">=9.0" +pyobjc-framework-Cocoa = ">=9.0" [[package]] name = "pyobjc-framework-AppleScriptObjC" -version = "8.5.1" +version = "9.0" description = "Wrappers for the framework AppleScriptObjC on macOS" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -pyobjc-core = ">=8.5.1" -pyobjc-framework-Cocoa = ">=8.5.1" +pyobjc-core = ">=9.0" +pyobjc-framework-Cocoa = ">=9.0" [[package]] name = "pyobjc-framework-Cocoa" -version = "8.5.1" +version = "9.0" description = "Wrappers for the Cocoa frameworks on macOS" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -pyobjc-core = ">=8.5.1" +pyobjc-core = ">=9.0" [[package]] name = "pyparsing" @@ -436,7 +439,7 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" -version = "7.1.3" +version = "7.2.0" description = "pytest: simple powerful testing with Python" category = "dev" optional = false @@ -445,18 +448,18 @@ python-versions = ">=3.7" [package.dependencies] attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -tomli = ">=1.0.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] [[package]] name = "pytz" -version = "2022.4" +version = "2022.6" description = "World timezone definitions, modern and historical" category = "dev" optional = false @@ -472,7 +475,7 @@ python-versions = "*" [[package]] name = "readme-renderer" -version = "37.2" +version = "37.3" description = "readme_renderer is a library for rendering \"readme\" descriptions for Warehouse" category = "dev" optional = false @@ -506,7 +509,7 @@ use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "requests-toolbelt" -version = "0.10.0" +version = "0.10.1" description = "A utility belt for advanced users of python-requests" category = "dev" optional = false @@ -572,7 +575,7 @@ python-versions = "*" [[package]] name = "Sphinx" -version = "5.2.3" +version = "5.3.0" description = "Python documentation generator" category = "dev" optional = false @@ -604,18 +607,18 @@ test = ["cython", "html5lib", "pytest (>=4.6)", "typed_ast"] [[package]] name = "sphinx-rtd-theme" -version = "1.0.0" +version = "1.1.1" description = "Read the Docs theme for Sphinx" category = "dev" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" [package.dependencies] docutils = "<0.18" -sphinx = ">=1.6" +sphinx = ">=1.6,<6" [package.extras] -dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client"] +dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] [[package]] name = "sphinxcontrib-applehelp" @@ -757,7 +760,7 @@ test = ["pytest (>=3.0.0)", "pytest-cov"] [[package]] name = "zipp" -version = "3.9.0" +version = "3.10.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "dev" optional = false @@ -770,7 +773,7 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "aff935060fd4273d9debedd731d123731dd071c5bbd148587d99650d9b01fa06" +content-hash = "7de8fdd303046e8e8d92f47e60632c7c8b4d159d9784a3083ffac76c9e0e4ed5" [metadata.files] alabaster = [ @@ -782,8 +785,8 @@ attrs = [ {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, ] Babel = [ - {file = "Babel-2.10.3-py3-none-any.whl", hash = "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb"}, - {file = "Babel-2.10.3.tar.gz", hash = "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51"}, + {file = "Babel-2.11.0-py3-none-any.whl", hash = "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe"}, + {file = "Babel-2.11.0.tar.gz", hash = "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6"}, ] bleach = [ {file = "bleach-5.0.1-py3-none-any.whl", hash = "sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a"}, @@ -872,45 +875,49 @@ charset-normalizer = [ {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, ] colorama = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] commonmark = [ {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"}, {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, ] cryptography = [ - {file = "cryptography-38.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:10d1f29d6292fc95acb597bacefd5b9e812099d75a6469004fd38ba5471a977f"}, - {file = "cryptography-38.0.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3fc26e22840b77326a764ceb5f02ca2d342305fba08f002a8c1f139540cdfaad"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3b72c360427889b40f36dc214630e688c2fe03e16c162ef0aa41da7ab1455153"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:194044c6b89a2f9f169df475cc167f6157eb9151cc69af8a2a163481d45cc407"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca9f6784ea96b55ff41708b92c3f6aeaebde4c560308e5fbbd3173fbc466e94e"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:16fa61e7481f4b77ef53991075de29fc5bacb582a1244046d2e8b4bb72ef66d0"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d4ef6cc305394ed669d4d9eebf10d3a101059bdcf2669c366ec1d14e4fb227bd"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3261725c0ef84e7592597606f6583385fed2a5ec3909f43bc475ade9729a41d6"}, - {file = "cryptography-38.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:0297ffc478bdd237f5ca3a7dc96fc0d315670bfa099c04dc3a4a2172008a405a"}, - {file = "cryptography-38.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:89ed49784ba88c221756ff4d4755dbc03b3c8d2c5103f6d6b4f83a0fb1e85294"}, - {file = "cryptography-38.0.1-cp36-abi3-win32.whl", hash = "sha256:ac7e48f7e7261207d750fa7e55eac2d45f720027d5703cd9007e9b37bbb59ac0"}, - {file = "cryptography-38.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:ad7353f6ddf285aeadfaf79e5a6829110106ff8189391704c1d8801aa0bae45a"}, - {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:896dd3a66959d3a5ddcfc140a53391f69ff1e8f25d93f0e2e7830c6de90ceb9d"}, - {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d3971e2749a723e9084dd507584e2a2761f78ad2c638aa31e80bc7a15c9db4f9"}, - {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:79473cf8a5cbc471979bd9378c9f425384980fcf2ab6534b18ed7d0d9843987d"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:d9e69ae01f99abe6ad646947bba8941e896cb3aa805be2597a0400e0764b5818"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5067ee7f2bce36b11d0e334abcd1ccf8c541fc0bbdaf57cdd511fdee53e879b6"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:3e3a2599e640927089f932295a9a247fc40a5bdf69b0484532f530471a382750"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2e5856248a416767322c8668ef1845ad46ee62629266f84a8f007a317141013"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:64760ba5331e3f1794d0bcaabc0d0c39e8c60bf67d09c93dc0e54189dfd7cfe5"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b6c9b706316d7b5a137c35e14f4103e2115b088c412140fdbd5f87c73284df61"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0163a849b6f315bf52815e238bc2b2346604413fa7c1601eea84bcddb5fb9ac"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d1a5bd52d684e49a36582193e0b89ff267704cd4025abefb9e26803adeb3e5fb"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:765fa194a0f3372d83005ab83ab35d7c5526c4e22951e46059b8ac678b44fa5a"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:52e7bee800ec869b4031093875279f1ff2ed12c1e2f74923e8f49c916afd1d3b"}, - {file = "cryptography-38.0.1.tar.gz", hash = "sha256:1db3d807a14931fa317f96435695d9ec386be7b84b618cc61cfa5d08b0ae33d7"}, + {file = "cryptography-38.0.3-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:984fe150f350a3c91e84de405fe49e688aa6092b3525f407a18b9646f6612320"}, + {file = "cryptography-38.0.3-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:ed7b00096790213e09eb11c97cc6e2b757f15f3d2f85833cd2d3ec3fe37c1722"}, + {file = "cryptography-38.0.3-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:bbf203f1a814007ce24bd4d51362991d5cb90ba0c177a9c08825f2cc304d871f"}, + {file = "cryptography-38.0.3-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:554bec92ee7d1e9d10ded2f7e92a5d70c1f74ba9524947c0ba0c850c7b011828"}, + {file = "cryptography-38.0.3-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1b52c9e5f8aa2b802d48bd693190341fae201ea51c7a167d69fc48b60e8a959"}, + {file = "cryptography-38.0.3-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:728f2694fa743a996d7784a6194da430f197d5c58e2f4e278612b359f455e4a2"}, + {file = "cryptography-38.0.3-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dfb4f4dd568de1b6af9f4cda334adf7d72cf5bc052516e1b2608b683375dd95c"}, + {file = "cryptography-38.0.3-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5419a127426084933076132d317911e3c6eb77568a1ce23c3ac1e12d111e61e0"}, + {file = "cryptography-38.0.3-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9b24bcff7853ed18a63cfb0c2b008936a9554af24af2fb146e16d8e1aed75748"}, + {file = "cryptography-38.0.3-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:25c1d1f19729fb09d42e06b4bf9895212292cb27bb50229f5aa64d039ab29146"}, + {file = "cryptography-38.0.3-cp36-abi3-win32.whl", hash = "sha256:7f836217000342d448e1c9a342e9163149e45d5b5eca76a30e84503a5a96cab0"}, + {file = "cryptography-38.0.3-cp36-abi3-win_amd64.whl", hash = "sha256:c46837ea467ed1efea562bbeb543994c2d1f6e800785bd5a2c98bc096f5cb220"}, + {file = "cryptography-38.0.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06fc3cc7b6f6cca87bd56ec80a580c88f1da5306f505876a71c8cfa7050257dd"}, + {file = "cryptography-38.0.3-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:65535bc550b70bd6271984d9863a37741352b4aad6fb1b3344a54e6950249b55"}, + {file = "cryptography-38.0.3-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5e89468fbd2fcd733b5899333bc54d0d06c80e04cd23d8c6f3e0542358c6060b"}, + {file = "cryptography-38.0.3-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6ab9516b85bebe7aa83f309bacc5f44a61eeb90d0b4ec125d2d003ce41932d36"}, + {file = "cryptography-38.0.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:068147f32fa662c81aebab95c74679b401b12b57494872886eb5c1139250ec5d"}, + {file = "cryptography-38.0.3-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:402852a0aea73833d982cabb6d0c3bb582c15483d29fb7085ef2c42bfa7e38d7"}, + {file = "cryptography-38.0.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b1b35d9d3a65542ed2e9d90115dfd16bbc027b3f07ee3304fc83580f26e43249"}, + {file = "cryptography-38.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:6addc3b6d593cd980989261dc1cce38263c76954d758c3c94de51f1e010c9a50"}, + {file = "cryptography-38.0.3-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:be243c7e2bfcf6cc4cb350c0d5cdf15ca6383bbcb2a8ef51d3c9411a9d4386f0"}, + {file = "cryptography-38.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78cf5eefac2b52c10398a42765bfa981ce2372cbc0457e6bf9658f41ec3c41d8"}, + {file = "cryptography-38.0.3-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:4e269dcd9b102c5a3d72be3c45d8ce20377b8076a43cbed6f660a1afe365e436"}, + {file = "cryptography-38.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8d41a46251bf0634e21fac50ffd643216ccecfaf3701a063257fe0b2be1b6548"}, + {file = "cryptography-38.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:785e4056b5a8b28f05a533fab69febf5004458e20dad7e2e13a3120d8ecec75a"}, + {file = "cryptography-38.0.3.tar.gz", hash = "sha256:bfbe6ee19615b07a98b1d2287d6a6073f734735b49ee45b11324d85efc4d5cbd"}, ] docutils = [ {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, ] +exceptiongroup = [ + {file = "exceptiongroup-1.0.1-py3-none-any.whl", hash = "sha256:4d6c0aa6dd825810941c792f53d7b8d71da26f5e5f84f20f9508e8f2d33b140a"}, + {file = "exceptiongroup-1.0.1.tar.gz", hash = "sha256:73866f7f842ede6cb1daa42c4af078e2035e5f7607f0e2c762cc51bb31bbe7b2"}, +] flaky = [ {file = "flaky-3.7.0-py2.py3-none-any.whl", hash = "sha256:d6eda73cab5ae7364504b7c44670f70abed9e75f77dd116352f662817592ec9c"}, {file = "flaky-3.7.0.tar.gz", hash = "sha256:3ad100780721a1911f57a165809b7ea265a7863305acb66708220820caf8aa0d"}, @@ -944,8 +951,8 @@ Jinja2 = [ {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, ] keyring = [ - {file = "keyring-23.9.3-py3-none-any.whl", hash = "sha256:69732a15cb1433bdfbc3b980a8a36a04878a6cfd7cb99f497b573f31618001c0"}, - {file = "keyring-23.9.3.tar.gz", hash = "sha256:69b01dd83c42f590250fe7a1f503fc229b14de83857314b1933a3ddbf595c4a5"}, + {file = "keyring-23.11.0-py3-none-any.whl", hash = "sha256:3dd30011d555f1345dec2c262f0153f2f0ca6bca041fb1dc4588349bb4c0ac1e"}, + {file = "keyring-23.11.0.tar.gz", hash = "sha256:ad192263e2cdd5f12875dedc2da13534359a7e760e77f8d04b50968a821c2361"}, ] m2r2 = [ {file = "m2r2-0.3.2-py3-none-any.whl", hash = "sha256:d3684086b61b4bebe2307f15189495360f05a123c9bda2a66462649b7ca236aa"}, @@ -998,8 +1005,8 @@ mistune = [ {file = "mistune-0.8.4.tar.gz", hash = "sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e"}, ] more-itertools = [ - {file = "more-itertools-8.14.0.tar.gz", hash = "sha256:c09443cd3d5438b8dafccd867a6bc1cb0894389e90cb53d227456b0b0bccb750"}, - {file = "more_itertools-8.14.0-py3-none-any.whl", hash = "sha256:1bc4f91ee5b1b31ac7ceacc17c09befe6a40a503907baf9c839c229b5095cfd2"}, + {file = "more-itertools-9.0.0.tar.gz", hash = "sha256:5a6257e40878ef0520b1803990e3e22303a41b5714006c32a3fd8304b26ea1ab"}, + {file = "more_itertools-9.0.0-py3-none-any.whl", hash = "sha256:250e83d7e81d0c87ca6bd942e6aeab8cc9daa6096d12c5308f3f92fa5e5c1f41"}, ] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, @@ -1017,10 +1024,6 @@ pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] -py = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] py-applescript = [ {file = "py-applescript-1.0.3.tar.gz", hash = "sha256:fa22c955fc25b3d24e03e66825b36a721897ec0d9b6ce185a4d177e2d1ecfa6b"}, {file = "py_applescript-1.0.3-py3-none-any.whl", hash = "sha256:eb21dfc6e845a40be602372a5c3d6317f7ad3c999c2c355a00d1a19bdb1d57c0"}, @@ -1034,60 +1037,58 @@ Pygments = [ {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"}, ] pyobjc-core = [ - {file = "pyobjc-core-8.5.1.tar.gz", hash = "sha256:f8592a12de076c27006700c4a46164478564fa33d7da41e7cbdd0a3bf9ddbccf"}, - {file = "pyobjc_core-8.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b62dcf987cc511188fc2aa5b4d3b9fd895361ea4984380463497ce4b0752ddf4"}, - {file = "pyobjc_core-8.5.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0accc653501a655f66c13f149a1d3d30e6cb65824edf852f7960a00c4f930d5b"}, - {file = "pyobjc_core-8.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f82b32affc898e9e5af041c1cecde2c99f2ce160b87df77f678c99f1550a4655"}, - {file = "pyobjc_core-8.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f7b2f6b6f3caeb882c658fe0c7098be2e8b79893d84daa8e636cb3e58a07df00"}, - {file = "pyobjc_core-8.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:872c0202c911a5a2f1269261c168e36569f6ddac17e5d854ac19e581726570cc"}, - {file = "pyobjc_core-8.5.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:21f92e231a4bae7f2d160d065f5afbf5e859a1e37f29d34ac12592205fc8c108"}, - {file = "pyobjc_core-8.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:315334dd09781129af6a39641248891c4caa57043901750b0139c6614ce84ec0"}, + {file = "pyobjc-core-9.0.tar.gz", hash = "sha256:3e7010c648eb94b16dd37a55f7719ed3bef6559edf4cf8fd741f46869dc223b1"}, + {file = "pyobjc_core-9.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:548a069666ac07686ac3d987f7d006abd3e713738ec1b9dbcc9195c74cb60eae"}, + {file = "pyobjc_core-9.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b1eee6099b5b480cedee3803f1be75131d12509f8e0228758954df150ab15dcd"}, + {file = "pyobjc_core-9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:886050e8e1ff00e5502e5180df00a463b4f869d902c861ca3283b896f47d35f0"}, + {file = "pyobjc_core-9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a36752bc8fcf839694e6eff85ef54f8bc3c0ba71f0f42c9aa7a47b23f3cbd137"}, + {file = "pyobjc_core-9.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1640dd25122a146162bdd1c1f46a4564606325788c5d13f1047182bb4f02cd0e"}, + {file = "pyobjc_core-9.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4296f7b11912709e5aa3d60e1cce6e1731abb7cda47fce72619804c7892b22c3"}, ] pyobjc-framework-AppleScriptKit = [ - {file = "pyobjc-framework-AppleScriptKit-8.5.1.tar.gz", hash = "sha256:48b2574025c8d25fb7e98559cecfa7d58d8519b26d81f317623e28515d6765b5"}, - {file = "pyobjc_framework_AppleScriptKit-8.5.1-py2.py3-none-any.whl", hash = "sha256:13ce8f0c4f9fa45335c3b60494eb513b9fcf7271d89c02c58ecddd0e52a75a26"}, + {file = "pyobjc-framework-AppleScriptKit-9.0.tar.gz", hash = "sha256:15816b5513ddb6b9681e4311eb0e17e20196266041695d9748fec5fcc59a5a91"}, + {file = "pyobjc_framework_AppleScriptKit-9.0-py2.py3-none-any.whl", hash = "sha256:c3af04805370f8b51c0e8e4edee24a1b45fd56250712072deb99eb5447d4ba79"}, ] pyobjc-framework-AppleScriptObjC = [ - {file = "pyobjc-framework-AppleScriptObjC-8.5.1.tar.gz", hash = "sha256:9d9ae445c16cb193eadca79916e5cdb1c89306d1962a349270bd06a0a762e0d0"}, - {file = "pyobjc_framework_AppleScriptObjC-8.5.1-py2.py3-none-any.whl", hash = "sha256:51ac4a445096663e9665fb33fd0d517a32d50a6277c4403bf96349632c23d9d8"}, + {file = "pyobjc-framework-AppleScriptObjC-9.0.tar.gz", hash = "sha256:f617990cfb9c2dc43ff28c4bd0f7006911ce49388c456ddafea8036dba840d43"}, + {file = "pyobjc_framework_AppleScriptObjC-9.0-py2.py3-none-any.whl", hash = "sha256:1a74a8a88174fe0eaafcfc9c7c77493c6162c339f2bcafd2369a039800236817"}, ] pyobjc-framework-Cocoa = [ - {file = "pyobjc-framework-Cocoa-8.5.1.tar.gz", hash = "sha256:9a3de5cdb4644e85daf53f2ed912ef6c16ea5804a9e65552eafe62c2e139eb8c"}, - {file = "pyobjc_framework_Cocoa-8.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aa572acc2628488a47be8d19f4701fc96fce7377cc4da18316e1e08c3918521a"}, - {file = "pyobjc_framework_Cocoa-8.5.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cb3ae21c8d81b7f02a891088c623cef61bca89bd671eff58c632d2f926b649f3"}, - {file = "pyobjc_framework_Cocoa-8.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:88f08f5bd94c66d373d8413c1d08218aff4cff0b586e0cc4249b2284023e7577"}, - {file = "pyobjc_framework_Cocoa-8.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:063683b57e4bd88cb0f9631ae65d25ec4eecf427d2fe8d0c578f88da9c896f3f"}, - {file = "pyobjc_framework_Cocoa-8.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f8806ddfac40620fb27f185d0f8937e69e330617319ecc2eccf6b9c8451bdd1"}, - {file = "pyobjc_framework_Cocoa-8.5.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:7733a9a201df9e0cc2a0cf7bf54d76bd7981cba9b599353b243e3e0c9eefec10"}, - {file = "pyobjc_framework_Cocoa-8.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f0ab227f99d3e25dd3db73f8cde0999914a5f0dd6a08600349d25f95eaa0da63"}, + {file = "pyobjc-framework-Cocoa-9.0.tar.gz", hash = "sha256:1a511c620e9b7ef22f2f4fa68572902cb614e66d3dbfa9e46a1a05f000f30084"}, + {file = "pyobjc_framework_Cocoa-9.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c36e357641f7a6ee44fd4c21bf8b72882b74c64f9489858fa35b6edfde49b6bf"}, + {file = "pyobjc_framework_Cocoa-9.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b1dd493665319e526a269f57052ae7acd331efb5e5f1b854ae8e1f10ad446698"}, + {file = "pyobjc_framework_Cocoa-9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a4cd119626f5e8c41e790325902eed4c8d9f9d73aa9dfa90b0870d61f0c84862"}, + {file = "pyobjc_framework_Cocoa-9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:25d287d9fc1ed98becdcb80926e05a71b22e195d7552f504791e1200334de2ae"}, + {file = "pyobjc_framework_Cocoa-9.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:6fa8e0d34e2786d7f80fd70ac4f6d9575e665e326afc4b5fffb60590344b0f98"}, + {file = "pyobjc_framework_Cocoa-9.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:dc801d2a5d25bf834a78438446a9c9bd0baee6006a540fdd2f4efb5b8536ed41"}, ] pyparsing = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, ] pytest = [ - {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, - {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, + {file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"}, + {file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"}, ] pytz = [ - {file = "pytz-2022.4-py2.py3-none-any.whl", hash = "sha256:2c0784747071402c6e99f0bafdb7da0fa22645f06554c7ae06bf6358897e9c91"}, - {file = "pytz-2022.4.tar.gz", hash = "sha256:48ce799d83b6f8aab2020e369b627446696619e79645419610b9facd909b3174"}, + {file = "pytz-2022.6-py2.py3-none-any.whl", hash = "sha256:222439474e9c98fced559f1709d89e6c9cbf8d79c794ff3eb9f8800064291427"}, + {file = "pytz-2022.6.tar.gz", hash = "sha256:e89512406b793ca39f5971bc999cc538ce125c0e51c27941bef4568b460095e2"}, ] pywin32-ctypes = [ {file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"}, {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"}, ] readme-renderer = [ - {file = "readme_renderer-37.2-py3-none-any.whl", hash = "sha256:d3f06a69e8c40fca9ab3174eca48f96d9771eddb43517b17d96583418427b106"}, - {file = "readme_renderer-37.2.tar.gz", hash = "sha256:e8ad25293c98f781dbc2c5a36a309929390009f902f99e1798c761aaf04a7923"}, + {file = "readme_renderer-37.3-py3-none-any.whl", hash = "sha256:f67a16caedfa71eef48a31b39708637a6f4664c4394801a7b0d6432d13907343"}, + {file = "readme_renderer-37.3.tar.gz", hash = "sha256:cd653186dfc73055656f090f227f5cb22a046d7f71a841dfa305f55c9a513273"}, ] requests = [ {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, ] requests-toolbelt = [ - {file = "requests-toolbelt-0.10.0.tar.gz", hash = "sha256:f695d6207931200b46c8ef6addbc8a921fb5d77cc4cd209c2e7d39293fcd2b30"}, - {file = "requests_toolbelt-0.10.0-py2.py3-none-any.whl", hash = "sha256:64c6b8c51b515d123f9f708a29743f44eb70c4479440641ed2df8c4dea56d985"}, + {file = "requests-toolbelt-0.10.1.tar.gz", hash = "sha256:62e09f7ff5ccbda92772a29f394a49c3ad6cb181d568b1337626b2abb628a63d"}, + {file = "requests_toolbelt-0.10.1-py2.py3-none-any.whl", hash = "sha256:18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7"}, ] rfc3986 = [ {file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"}, @@ -1110,12 +1111,12 @@ snowballstemmer = [ {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] Sphinx = [ - {file = "Sphinx-5.2.3.tar.gz", hash = "sha256:5b10cb1022dac8c035f75767799c39217a05fc0fe2d6fe5597560d38e44f0363"}, - {file = "sphinx-5.2.3-py3-none-any.whl", hash = "sha256:7abf6fabd7b58d0727b7317d5e2650ef68765bbe0ccb63c8795fa8683477eaa2"}, + {file = "Sphinx-5.3.0.tar.gz", hash = "sha256:51026de0a9ff9fc13c05d74913ad66047e104f56a129ff73e174eb5c3ee794b5"}, + {file = "sphinx-5.3.0-py3-none-any.whl", hash = "sha256:060ca5c9f7ba57a08a1219e547b269fadf125ae25b06b9fa7f66768efb652d6d"}, ] sphinx-rtd-theme = [ - {file = "sphinx_rtd_theme-1.0.0-py2.py3-none-any.whl", hash = "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8"}, - {file = "sphinx_rtd_theme-1.0.0.tar.gz", hash = "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c"}, + {file = "sphinx_rtd_theme-1.1.1-py2.py3-none-any.whl", hash = "sha256:31faa07d3e97c8955637fc3f1423a5ab2c44b74b8cc558a51498c202ce5cbda7"}, + {file = "sphinx_rtd_theme-1.1.1.tar.gz", hash = "sha256:6146c845f1e1947b3c3dd4432c28998a1693ccc742b4f9ad7c63129f0757c103"}, ] sphinxcontrib-applehelp = [ {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, @@ -1166,6 +1167,6 @@ wheel = [ {file = "wheel-0.37.1.tar.gz", hash = "sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4"}, ] zipp = [ - {file = "zipp-3.9.0-py3-none-any.whl", hash = "sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980"}, - {file = "zipp-3.9.0.tar.gz", hash = "sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb"}, + {file = "zipp-3.10.0-py3-none-any.whl", hash = "sha256:4fcb6f278987a6605757302a6e40e896257570d11c51628968ccb2a47e80c6c1"}, + {file = "zipp-3.10.0.tar.gz", hash = "sha256:7a7262fd930bd3e36c50b9a64897aec3fafff3dfdeec9623ae22b40e93f99bb8"}, ] diff --git a/pyproject.toml b/pyproject.toml index d126812..9ec4e80 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,15 +17,16 @@ classifiers = [ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Topic :: Software Development :: Libraries :: Python Modules", ] [tool.poetry.dependencies] python = "^3.8" -pyobjc-core = ">=7.3, <9.0" -pyobjc-framework-Cocoa = ">=7.3, <9.0" -pyobjc-framework-AppleScriptKit = ">=7.3, <9.0" -pyobjc-framework-AppleScriptObjC = ">=7.3, <9.0" +pyobjc-core = ">=9.0,<10.0" +pyobjc-framework-Cocoa = ">=9.0,<10.0" +pyobjc-framework-AppleScriptKit = ">=9.0,<10.0" +pyobjc-framework-AppleScriptObjC = ">=9.0,<10.0" py-applescript = "^1.0.3" [tool.poetry.group.dev.dependencies] diff --git a/tests/mock_photoscript.applescript b/tests/mock_photoscript.applescript index 3cfefc6..61ff26a 100644 --- a/tests/mock_photoscript.applescript +++ b/tests/mock_photoscript.applescript @@ -1,17 +1,17 @@ (* mock photoscript applescript functions for testing AppleScriptError *) -on _photoslibrary_create_folder(folderName) +on photosLibraryCreateFolder(folderName) return 0 -end _photoslibrary_create_folder +end photosLibraryCreateFolder -on _photoslibrary_create_folder_at_folder(folderName, folder_id_) +on photosLibraryCreateFolderAtFolder(folderName, folder_id_) return 0 -end _photoslibrary_create_folder_at_folder +end photosLibraryCreateFolderAtFolder -on _photoslibrary_create_album(albumName) +on photosLibraryCreateAlbum(albumName) return 0 -end _photoslibrary_create_album +end photosLibraryCreateAlbum -on _photoslibrary_create_album_at_folder(albumName, folder_id_) +on photosLibraryCreateAlbumAtFolder(albumName, folder_id_) return 0 -end _photoslibrary_create_album_at_folder \ No newline at end of file +end photosLibraryCreateAlbumAtFolder \ No newline at end of file