From 6047cad6908ccbf5bd1c8816449d19af93f97640 Mon Sep 17 00:00:00 2001 From: Kivi Kaitaniemi Date: Fri, 12 Dec 2025 23:17:18 +0200 Subject: [PATCH] Unify docstring formats --- src/decman/__init__.py | 14 ++- src/decman/core/{files.py => fs.py} | 186 +++++++++++++--------------- tests/test_decman_core_files.py | 34 ++--- 3 files changed, 116 insertions(+), 118 deletions(-) rename src/decman/core/{files.py => fs.py} (66%) diff --git a/src/decman/__init__.py b/src/decman/__init__.py index 54c4143..50af313 100644 --- a/src/decman/__init__.py +++ b/src/decman/__init__.py @@ -4,6 +4,16 @@ import typing import decman.core.command as command import decman.core.output as output +# Re-export File and Directory +from decman.core.fs import Directory, File # noqa: F401 + +__all__ = [ + "File", + "Directory", + "prg", + "sh", +] + def prg( cmd: list[str], @@ -16,7 +26,7 @@ def prg( """ Shortcut for running a command. Returns the output of that command. - Args: + Arguments: cmd: Command to execute. @@ -74,7 +84,7 @@ def sh( """ Shortcut for running a shell command. Returns the output of that command. - Args: + Arguments: sh_cmd: Shell command to execute. The command is passed to the system shell /bin/sh. diff --git a/src/decman/core/files.py b/src/decman/core/fs.py similarity index 66% rename from src/decman/core/files.py rename to src/decman/core/fs.py index c2b04c2..916a452 100644 --- a/src/decman/core/files.py +++ b/src/decman/core/fs.py @@ -20,45 +20,42 @@ class File: Ownership, permissions, and parent directories are enforced on creation. Missing parent directories are created recursively and assigned the same ownership as the file when specified. - Parameters - ---------- - source_file: - Path to an existing file to copy from. Mutually exclusive with ``content``. + Parameters: + source_file: + Path to an existing file to copy from. Mutually exclusive with ``content``. - content: - In-memory file contents to write. Mutually exclusive with ``source_file``. + content: + In-memory file contents to write. Mutually exclusive with ``source_file``. - bin_file: - If ``True``, treat the file as binary. Disables variable substitution and writes bytes - verbatim. + bin_file: + If ``True``, treat the file as binary. Disables variable substitution and writes bytes + verbatim. - encoding: - Text encoding used when reading or writing non-binary files. + encoding: + Text encoding used when reading or writing non-binary files. - owner: - System user name to own the file and created parent directories. + owner: + System user name to own the file and created parent directories. - group: - System group name to own the file and created parent directories. + group: + System group name to own the file and created parent directories. - permissions: - File mode applied to the target file (e.g. ``0o644``). + permissions: + File mode applied to the target file (e.g. ``0o644``). - Raises - ------ - ValueError - If both ``source_file`` and ``content`` are ``None`` or if both are set. + Raises: + ValueError + If both ``source_file`` and ``content`` are ``None`` or if both are set. - UserNotFoundError - If ``owner`` does not exist on the system. + UserNotFoundError + If ``owner`` does not exist on the system. - GroupNotFoundError - If ``group`` does not exist on the system. + GroupNotFoundError + If ``group`` does not exist on the system. - Notes - ----- - Variable substitution is a simple string replacement where each key in ``variables`` is - replaced by its corresponding value. No escaping or templating semantics are applied. + Notes: + Variable substitution is a simple string replacement where each key in ``variables`` is + replaced by its corresponding value. No escaping or templating semantics are applied. """ def __init__( @@ -98,35 +95,31 @@ class File: """ Copies the contents of this file to the target file if they differ. - Parameters - ---------- - target: - Path to the target file on disk. + Parameters: + target: + Path to the target file on disk. - variables: - Optional mapping of literal substrings to replace in the text content before writing. - Ignored for binary files and when ``bin_file`` is True. + variables: + Optional mapping of literal substrings to replace in the text content before + writing. Ignored for binary files and when ``bin_file`` is True. - Returns - ------- - bool + Returns: True if the file contents were created or modified. False if the existing file already contained the desired contents. - Raises - ------ - OSError - If directory creation, file I/O, permission changes, or ownership changes fail - (e.g. permission denied, missing parent path components, I/O errors). + Raises: + OSError + If directory creation, file I/O, permission changes, or ownership changes fail + (e.g. permission denied, missing parent path components, I/O errors). - FileNotFoundError - If ``source_file`` is set and does not exist. + FileNotFoundError + If ``source_file`` is set and does not exist. - UnicodeDecodeError - If a text file cannot be decoded using ``encoding``. + UnicodeDecodeError + If a text file cannot be decoded using ``encoding``. - UnicodeEncodeError - If text content cannot be encoded using ``encoding``. + UnicodeEncodeError + If text content cannot be encoded using ``encoding``. """ if variables is None: variables = {} @@ -220,34 +213,32 @@ class Directory: permissions, encoding, and binary/text behavior. Text files can optionally undergo variable substitution before being written. - Parameters - ---------- - source_directory: - Path to the directory whose contents will be mirrored into the target. + Parameters: + source_directory: + Path to the directory whose contents will be mirrored into the target. - bin_files: - If ``True``, treat all files as binary; disables variable substitution and copies bytes - verbatim. + bin_files: + If ``True``, treat all files as binary; disables variable substitution and copies bytes + verbatim. - encoding: - Text encoding used when reading or writing non-binary files. + encoding: + Text encoding used when reading or writing non-binary files. - owner: - System user name to own created files and directories. + owner: + System user name to own created files and directories. - group: - System group name to own created files and directories. + group: + System group name to own created files and directories. - permissions: - File mode applied to created or updated files (e.g. ``0o644``). + permissions: + File mode applied to created or updated files (e.g. ``0o644``). - Raises - ------ - UserNotFoundError - If ``owner`` does not exist on the system. + Raises: + UserNotFoundError + If ``owner`` does not exist on the system. - GroupNotFoundError - If ``group`` does not exist on the system. + GroupNotFoundError + If ``group`` does not exist on the system. """ def __init__( @@ -287,42 +278,39 @@ class Directory: """ Copies the files in this directory to the target directory. Only replaces files that differ. - Parameters - ---------- - target_directory: - Destination directory root. Relative layout from the source is preserved beneath this - path. + Parameters: + target_directory: + Destination directory root. Relative layout from the source is preserved beneath + this path. - variables: - Optional mapping of literal substrings to replace in text files before writing. Ignored - for binary files. + variables: + Optional mapping of literal substrings to replace in text files before writing. + Ignored for binary files. - dry_run: - If ``True``, perform a dry-run: no files are written, but the list of files that *would* - be processed is returned. + dry_run: + If ``True``, perform a dry-run: no files are written, but the list of files that + *would* be processed is returned. - Returns - ------- - list[str] - When ``dry_run`` is ``False``, paths of files that were created or whose contents - were modified. + Returns: + list[str] + When ``dry_run`` is ``False``, paths of files that were created or whose contents + were modified. - When ``dry_run`` is ``True``, paths of all files that would be considered for - creation or modification (no changes are actually performed). + When ``dry_run`` is ``True``, paths of all files that would be considered for + creation or modification (no changes are actually performed). - Raises - ------ - OSError - If directory traversal or file I/O fails (e.g. permission denied). + Raises: + OSError + If directory traversal or file I/O fails (e.g. permission denied). - FileNotFoundError - If ``source_directory`` does not exist or becomes unavailable. + FileNotFoundError + If ``source_directory`` does not exist or becomes unavailable. - UnicodeDecodeError - If a text file cannot be decoded using ``encoding``. + UnicodeDecodeError + If a text file cannot be decoded using ``encoding``. - UnicodeEncodeError - If text content cannot be encoded using ``encoding``. + UnicodeEncodeError + If text content cannot be encoded using ``encoding``. """ changed_or_created = [] original_wd = os.getcwd() diff --git a/tests/test_decman_core_files.py b/tests/test_decman_core_files.py index b9a8c1c..85384f2 100644 --- a/tests/test_decman_core_files.py +++ b/tests/test_decman_core_files.py @@ -3,15 +3,15 @@ import stat from pathlib import Path # Adjust this import to match your actual module location -import decman.core.files as files +import decman.core.fs as fs -# --- files.File tests -------------------------------------------------------------- +# --- fs.File tests -------------------------------------------------------------- def test_file_from_content_creates_and_is_idempotent(tmp_path: Path) -> None: target = tmp_path / "file.txt" - f = files.File(content="hello", permissions=0o600) + f = fs.File(content="hello", permissions=0o600) # First run: file must be created and reported as changed changed1 = f.copy_to(str(target)) @@ -31,7 +31,7 @@ def test_file_from_content_creates_and_is_idempotent(tmp_path: Path) -> None: def test_file_content_with_variables_and_change_detection(tmp_path: Path) -> None: target = tmp_path / "templated.txt" - f = files.File(content="hello {{NAME}}") + f = fs.File(content="hello {{NAME}}") # First run: NAME=world changed1 = f.copy_to(str(target), {"{{NAME}}": "world"}) @@ -55,7 +55,7 @@ def test_file_from_source_text_with_and_without_variables(tmp_path: Path) -> Non target = tmp_path / "dst.txt" # Without variables (raw copy) - f_raw = files.File(source_file=str(src)) + f_raw = fs.File(source_file=str(src)) changed1 = f_raw.copy_to(str(target), {}) assert changed1 is True assert target.read_text(encoding="utf-8") == "VALUE={{X}}" @@ -65,7 +65,7 @@ def test_file_from_source_text_with_and_without_variables(tmp_path: Path) -> Non assert changed2 is False # With variables (substitution) - f_sub = files.File(source_file=str(src)) + f_sub = fs.File(source_file=str(src)) changed3 = f_sub.copy_to(str(target), {"{{X}}": "42"}) assert changed3 is True assert target.read_text(encoding="utf-8") == "VALUE=42" @@ -79,7 +79,7 @@ def test_file_binary_from_content(tmp_path: Path) -> None: target = tmp_path / "bin.dat" payload = b"\x00\x01\x02hello" - f = files.File(content=payload.decode("latin1"), bin_file=True) + f = fs.File(content=payload.decode("latin1"), bin_file=True) changed1 = f.copy_to(str(target)) assert changed1 is True @@ -97,7 +97,7 @@ def test_file_binary_copy_from_source(tmp_path: Path) -> None: src.write_bytes(payload) target = tmp_path / "dst.bin" - f = files.File(source_file=str(src), bin_file=True) + f = fs.File(source_file=str(src), bin_file=True) changed1 = f.copy_to(str(target), {"IGNORED": "x"}) assert changed1 is True @@ -113,7 +113,7 @@ def test_file_creates_parent_directories_and_applies_permissions(tmp_path: Path) nested_dir = tmp_path / "a" / "b" / "c" target = nested_dir / "file.txt" - f = files.File(content="data", permissions=0o644) + f = fs.File(content="data", permissions=0o644) changed = f.copy_to(str(target)) assert changed is True @@ -127,7 +127,7 @@ def test_file_creates_parent_directories_and_applies_permissions(tmp_path: Path) assert mode == 0o644 -# --- files.Directory tests --------------------------------------------------------- +# --- fs.Directory tests --------------------------------------------------------- def _create_sample_source_tree(root: Path) -> None: @@ -143,14 +143,14 @@ def test_directory_copy_to_creates_and_is_idempotent(tmp_path: Path) -> None: _create_sample_source_tree(src_dir) - d = files.Directory( + d = fs.Directory( source_directory=str(src_dir), bin_files=False, encoding="utf-8", permissions=0o644, ) - # First run: both files should be created and reported as changed + # First run: both fs should be created and reported as changed changed1 = d.copy_to(str(dst_dir), variables={"{{X}}": "1"}) expected_paths = { str(dst_dir / "a.txt"), @@ -161,7 +161,7 @@ def test_directory_copy_to_creates_and_is_idempotent(tmp_path: Path) -> None: assert (dst_dir / "a.txt").read_text(encoding="utf-8") == "A=1" assert (dst_dir / "sub" / "b.txt").read_text(encoding="utf-8") == "B=1" - # Second run with same variables: no files should be reported as changed + # Second run with same variables: no fs should be reported as changed changed2 = d.copy_to(str(dst_dir), variables={"{{X}}": "1"}) assert changed2 == [] @@ -172,7 +172,7 @@ def test_directory_copy_to_detects_changes_via_variables(tmp_path: Path) -> None src_dir.mkdir() _create_sample_source_tree(src_dir) - d = files.Directory(source_directory=str(src_dir)) + d = fs.Directory(source_directory=str(src_dir)) # Initial materialization changed1 = d.copy_to(str(dst_dir), variables={"{{X}}": "alpha"}) @@ -181,7 +181,7 @@ def test_directory_copy_to_detects_changes_via_variables(tmp_path: Path) -> None str(dst_dir / "sub" / "b.txt"), } - # Change variables -> both files change + # Change variables -> both fs change changed2 = d.copy_to(str(dst_dir), variables={"{{X}}": "beta"}) assert set(changed2) == { str(dst_dir / "a.txt"), @@ -198,7 +198,7 @@ def test_directory_copy_to_dry_run(tmp_path: Path) -> None: src_dir.mkdir() _create_sample_source_tree(src_dir) - d = files.Directory(source_directory=str(src_dir)) + d = fs.Directory(source_directory=str(src_dir)) # First, actually materialize once d.copy_to(str(dst_dir), variables={"{{X}}": "1"}) @@ -230,7 +230,7 @@ def test_directory_copy_to_restores_working_directory(tmp_path: Path) -> None: src_dir.mkdir() _create_sample_source_tree(src_dir) - d = files.Directory(source_directory=str(src_dir)) + d = fs.Directory(source_directory=str(src_dir)) original_cwd = os.getcwd() try: