spacr.folder_consolidation

Copy a folder tree into ONE folder, naming each copy after its folder path.

A tree like:

exp/
  nucleus/  a.tif  b.tif
  cell/     a.tif  b.tif

becomes exp_renamed/ holding exp_nucleus.tif, exp_nucleus_2.tif, exp_cell.tif and exp_cell_2.tif: every copy is named after the folders it sat in, joined by _, and a second file from the same folder is numbered. A rename_manifest.csv beside the copies maps each original path to its new name, so nothing about where a file came from is lost.

It needs only the standard library. The originals are COPIED, never moved; symbolic links, to files or folders, are skipped and listed; names are made safe for Windows; a name too long for a typical filesystem is shortened with a hash of the full name so two long names cannot collide; and the output folder must not exist yet. Two options were added for Make Masks, which offers this on a dropped folder: extensions limits the copy to image files and skip_dirs leaves out folders such as masks whose contents are not images to edit. With neither, every file is copied, as the script did.

Run as a program:

python -m spacr.folder_consolidation /path/to/source [/path/to/new_output]

Classes

Functions

available_filename(→ pathlib.Path)

Pick the next free name for stem in output.

consolidate_folder(, log, ...)

Copy every file under source into one new folder, named by folder path.

copy_and_rename(→ int)

The script's entry point: consolidate and return an exit status.

default_output_folder(→ pathlib.Path)

Return the unused <parent>/<name>_renamed beside source.

file_extension(→ str)

Return the extension of path, keeping a compound one whole.

main(→ int)

Command line: python -m spacr.folder_consolidation SOURCE [OUTPUT].

nested_file_count() → Tuple[int, int])

Count the files that sit in SUBFOLDERS of source, recursively.

safe_part(→ str)

Replace characters Windows forbids in a filename; keep spaces.

unused_output_folder(→ pathlib.Path)

Return parent/name, or name_2, name_3... when it exists.

Module Contents

class spacr.folder_consolidation.ConsolidationResult[source]

What consolidate_folder() did.

Variables:
  • output – the new folder holding the copies.

  • manifest – the rename_manifest.csv inside it.

  • copied – files copied.

  • failed – files or folders that could not be read or copied.

  • skipped_links – symbolic links left out.

  • rows – the manifest rows, (original, new name, status, error).

spacr.folder_consolidation.available_filename(output: pathlib.Path, stem: str, extension: str, used: set, counters: dict) → pathlib.Path[source]

Pick the next free name for stem in output.

Collisions are numbered _2, _3 and so on; names are compared case-insensitively so the folder survives a move to Windows or macOS. A name longer than 240 bytes is cut and ends in a 12-character hash of the full stem. Windows’ reserved device names are prefixed with _.

Parameters:
  • output – the output folder.

  • stem – the name wanted, without extension.

  • extension – the extension, with its dot.

  • used – case-folded names already handed out; updated.

  • counters – the next number per (stem, extension); updated.

Returns:

the path to copy to.

Raises:

ValueError – when the extension alone leaves no room for a name.

spacr.folder_consolidation.consolidate_folder(source, output=None, *, extensions: Iterable[str] | None = None, skip_dirs: Iterable[str] = (), log: Callable[[str], None] | None = None) → ConsolidationResult[source]

Copy every file under source into one new folder, named by folder path.

Each copy is named after the folder path it came from, from source’s own name down, parts joined by _; a file directly in source is named after source. Several files in one folder are numbered _2, _3…, in sorted file-name order. The originals are never touched.

Parameters:
  • source – the folder to consolidate.

  • output – the NEW folder to create; default default_output_folder().

  • extensions – copy only these extensions (e.g. image types); None, the script’s behaviour, copies every file.

  • skip_dirs – folder names not descended into, case-insensitively and with or without a numbered _2 suffix.

  • log – called with progress lines; default prints them.

Returns:

a ConsolidationResult.

Raises:

ValueError – when source is not a folder or output exists.

spacr.folder_consolidation.copy_and_rename(source: pathlib.Path, output: pathlib.Path) → int[source]

The script’s entry point: consolidate and return an exit status.

Parameters:
  • source – the folder to consolidate.

  • output – the NEW output folder.

Returns:

1 when any file failed, else 0.

spacr.folder_consolidation.default_output_folder(source) → pathlib.Path[source]

Return the unused <parent>/<name>_renamed beside source.

Parameters:

source – the folder to consolidate.

spacr.folder_consolidation.file_extension(path: pathlib.Path) → str[source]

Return the extension of path, keeping a compound one whole.

Parameters:

path – a file path.

Returns:

e.g. .ome.tif for x.ome.tif and .tif for x.tif.

spacr.folder_consolidation.main(argv: List[str] | None = None) → int[source]

Command line: python -m spacr.folder_consolidation SOURCE [OUTPUT].

Parameters:

argv – the arguments; default sys.argv[1:].

Returns:

the exit status.

spacr.folder_consolidation.nested_file_count(source, extensions: Iterable[str] | None = None, skip_dirs: Iterable[str] = ()) → Tuple[int, int][source]

Count the files that sit in SUBFOLDERS of source, recursively.

Make Masks asks whether to consolidate only when this is not zero: files directly in source open as they are.

Parameters:
  • source – the folder.

  • extensions – count only these extensions; None counts every file.

  • skip_dirs – folder names not descended into (case-insensitive), such as masks; hidden folders are never descended into.

Returns:

(files, folders) – how many files lie below the top level and how many distinct subfolders hold them. Symbolic links are not counted or followed.

spacr.folder_consolidation.safe_part(name: str) → str[source]

Replace characters Windows forbids in a filename; keep spaces.

Parameters:

name – one folder name.

Returns:

the name with <>:"/\|?* and control characters replaced by _ and trailing spaces and dots removed; folder when nothing is left.

spacr.folder_consolidation.unused_output_folder(parent: pathlib.Path, name: str) → pathlib.Path[source]

Return parent/name, or name_2, name_3… when it exists.

Parameters:
  • parent – the folder to create the output in.

  • name – the name wanted.

Returns:

a path that does not exist yet.

Nested helpers

consolidate_folder.record(row) → None

Write one manifest row and keep it on the result.

Parameters:

row – (original, new name, status, error).

spacr/folder_consolidation.py:280

consolidate_folder.walk_error(error) → None

Record a folder os.walk could not read.

Parameters:

error – the OSError it raised.

spacr/folder_consolidation.py:288