def delete(paths: List[str]) -> None: """Move one or more images to the trash directory. **syntax:** ``:delete path [path ...]`` positional arguments: * ``paths``: The path(s) to the images to delete. .. note:: This only deletes images, not any other path(s). """ _last_deleted.clear() images = [path for path in paths if files.is_image(path)] if not images: raise api.commands.CommandError("No images to delete") failed_images = [] for filename in images: try: trash_filename = trash_manager.delete(filename) _last_deleted.append(os.path.basename(trash_filename)) except OSError: failed_images.append(filename) n_fail = len(failed_images) n_success = len(images) - n_fail fail_msg = f"Failed to delete {', '.join(failed_images)}" if n_fail > 0 else "" succ_msg = f"Deleted {n_success} images" if n_success > 0 else "" if fail_msg: log.warning(f"{succ_msg + ' but ' if succ_msg else ''}{fail_msg}") elif succ_msg: log.info(succ_msg)
def mark(self, paths: List[str], action: Action = Action.Toggle) -> None: """Mark one or more paths. **syntax:** ``:mark path [path ...] [--action=ACTION]`` .. hint:: ``:mark %`` marks the current path. positional arguments: * ``paths``: The path(s) to mark. optional arguments: * ``--action``: One of toggle/mark/unmark. Toggle, the default, inverses the mark status of the path(s). Mark forces marking while unmark forces removing the mark. """ _logger.debug("Calling %s on %d paths", action.value, len(paths)) function = self._actions[action] for path in paths: if files.is_image(path): try: function(path) except ValueError: _logger.debug("Calling %s on '%s' failed", action.value, path) self.markdone.emit()
def _load_single(path: str) -> None: """Populate list of paths in same directory for single path.""" if path in _paths: goto(_paths.index(path) + 1) # goto is indexed from 1 elif path not in api.working_directory.handler.images and files.is_image(path): _load_paths([path, *api.working_directory.handler.images], path) else: _load_paths(api.working_directory.handler.images, path)
def test_tar_gz_not_an_image(tmpdir): """Test if is_image for a tar.gz returns False. The default implementation of QImageReader.canRead returns True which is not correct. """ outfile = str(tmpdir.join("dummy.tar.gz")) indirectory = str(tmpdir.mkdir("indir")) with tarfile.open(outfile, mode="w:gz") as tar: tar.add(indirectory, arcname=os.path.basename(indirectory)) assert files.is_image(outfile) is False
def test_tar_gz_not_an_image(tmp_path): """Test if is_image for a tar.gz returns False. The default implementation of QImageReader.canRead returns True which is not correct. """ tarpath = tmp_path / "dummy.tar.gz" tarred_directory = tmp_path / "indir" tarred_directory.mkdir() with tarfile.open(tarpath, mode="w:gz") as tar: tar.add(tarred_directory, arcname=tarred_directory.name) assert files.is_image(str(tarpath)) is False
def mark(self, paths: List[str]) -> None: """Mark one or more paths. **syntax:** ``:mark path [path ...]`` If a path is currently marked, it is unmarked instead. .. hint:: ``:mark %`` marks the current path. positional arguments: * ``paths``: The path(s) to mark. """ for path in (path for path in paths if files.is_image(path)): self._toggle_mark(path)
def rename( paths: List[str], base: str, start: int = 1, separator: str = "_", overwrite: bool = False, skip_image_check: bool = False, ) -> None: """Rename images with a common base. **syntax:** ``:rename path [path ...] base [--start=INDEX] [--separator=SEPARATOR] [--overwrite] [--skip-image-check]`` Example:: ``:rename * identifier`` would rename all images in the filelist to ``identifier_001``, ``identifier_002``, ..., ``identifier_NNN``. positional arguments: * ``paths``: The path(s) to rename. * ``base``: Base name to use for numbering. optional arguments: * ``--start``: Index to start numbering with. Default: 1. * ``--separator``: Separator between base and numbers. Default: '_'. * ``--overwrite``: Overwrite existing paths when renaming. * ``--skip-image-check``: Do not check if all renamed paths are images. """ paths = [ path for path in paths if files.is_image(path) or skip_image_check ] if not paths: raise api.commands.CommandError("No paths to rename") marked = [] for i, path in enumerate(paths, start=start): _, extension = os.path.splitext(path) dirname = os.path.dirname(path) basename = f"{base}{separator}{i:03d}{extension}" outfile = os.path.join(dirname, basename) if os.path.exists(outfile) and not overwrite: log.warning( "Outfile '%s' exists, skipping. To overwrite add '--overwrite'.", outfile, ) else: _logger.debug("%s -> %s", path, outfile) os.rename(path, outfile) if path in api.mark.paths: # Keep mark status of the renamed path marked.append(outfile) api.mark.mark(marked)
def _write(self): """Write pixmap to disk.""" # Get pixmap type _, ext = os.path.splitext(self._path) # First create temporary file and then move it to avoid race conditions handle, filename = tempfile.mkstemp(dir=os.getcwd(), suffix=ext) os.close(handle) self._pixmap.save(filename) # Copy exif info from original file to new file imutils.exif.copy_exif(self._original_path, filename) os.rename(filename, self._path) # Check if valid image was created if not os.path.isfile(self._path): raise WriteError("File not written, unknown exception") if not files.is_image(self._path): os.remove(self._path) raise WriteError("No valid image written. Is the extention valid?")
def delete(paths: List[str]) -> None: """Move one or more images to the trash directory. **syntax:** ``:delete path [path ...]`` positional arguments: * ``paths``: The path(s) to the images to delete. .. note:: This only deletes images, not any other path(s). """ _last_deleted.clear() images = [path for path in paths if files.is_image(path)] if not images: raise api.commands.CommandError("No images to delete") for filename in images: trash_filename = trash_manager.delete(filename) _last_deleted.append(os.path.basename(trash_filename)) n_images = len(images) if n_images > 1: log.info("Deleted %d images", n_images)
def delete(paths: List[str], ask: bool = False) -> None: """Move one or more images to the trash directory. **syntax:** ``:delete path [path ...]`` positional arguments: * ``paths``: The path(s) to the images to delete. optional arguments: * ``--ask``: Prompt for confirmation before deleting the images. .. note:: This only deletes images, not any other path(s). """ if ask and not api.prompt.ask_question( title="delete", body=f"delete {quotedjoin(paths)}?" ): return _last_deleted.clear() images = [path for path in paths if files.is_image(path)] if not images: raise api.commands.CommandError("No images to delete") failed_images = [] for filename in images: try: trash_filename = trash_manager.delete(filename) _last_deleted.append(os.path.basename(trash_filename)) except OSError: failed_images.append(filename) n_fail = len(failed_images) n_success = len(images) - n_fail fail_msg = f"Failed to delete {', '.join(failed_images)}" if n_fail > 0 else "" succ_msg = f"Deleted {n_success} images" if n_success > 0 else "" if fail_msg: log.warning(f"{succ_msg + ' but ' if succ_msg else ''}{fail_msg}") elif succ_msg: log.info(succ_msg)
def _write(pixmap, path, original_path): """Write pixmap to disk. See write_pixmap for the args description. """ # Get pixmap type _, ext = os.path.splitext(path) # First create temporary file and then move it to avoid race conditions handle, filename = tempfile.mkstemp(suffix=ext) os.close(handle) pixmap.save(filename) # Copy exif info from original file to new file try: imutils.exif.ExifHandler(original_path).copy_exif(filename) except imutils.exif.UnsupportedExifOperation: pass shutil.move(filename, path) # Check if valid image was created if not os.path.isfile(path): raise WriteError("File not written, unknown exception") if not files.is_image(path): os.remove(path) raise WriteError("No valid image written. Is the extention valid?")
def test_is_image_on_fifo_file(qtbot, tmp_path): path = tmp_path / "my_file" os.mkfifo(path) assert files.is_image(str(path)) is False
def test_is_image_on_error(tmp_path): path = tmp_path / "my_file" path.touch(mode=0o000) assert files.is_image(str(path)) is False
def test_is_image_on_error(tmpdir): path = tmpdir.join("my_file") path.write("") path.chmod(0o00) assert files.is_image(path) is False