ddp_utils.path_info

import ddp_utils.path_info

Provide path inspection, discovery, and filesystem mutation utilities.

PathInfo wraps pathlib.Path and adds search, project-root discovery, deletion, renaming, moving, and copying operations.

Examples

Inspect a path through the facade:

from ddp_utils.path_info import PathInfo

info = PathInfo("archive.tar.gz")
assert info.suffixes == [".tar", ".gz"]
ddp_utils.path_info.get_downloads_path() → Path

Return the conventional Downloads path under the current home folder.

This is a best-effort convention and does not query operating-system folder redirection settings.

Returns

Type

Description

Path

Path.home() / "Downloads".

Examples

Build a default download target:

target = get_downloads_path() / "report.pdf"
class ddp_utils.path_info.PathInfo(path: str | PathLike | Path)

Bases: object

Wrap one pathlib.Path with higher-level operations.

Parameters

Name

Type

Description

path

PathLike

String or path-like value to wrap.

Examples

Inspect and mutate a runtime path:

info = PathInfo("runtime/results.json")
if info.exists:
    print(info.stat)

Normalize and store a path-like value.

Parameters

Name

Type

Description

path

PathLike

String or path-like value.

Examples

Wrap a string path:

info = PathInfo("runtime/results.json")
classmethod from_current() → PathInfo

Create an instance for the immediate caller’s source file.

Returns

Type

Description

PathInfo

Path information for the caller filename reported by inspect.

Examples

Locate the module that requested path information:

caller_file = PathInfo.from_current()
static convert(path: str | PathLike | Path) → Path

Convert a supported path-like value to Path.

Parameters

Name

Type

Description

path

str | PathLike | Path

String or path-like value.

Returns

Type

Description

Path

path itself when already a Path; otherwise a new Path(str(path)).

Examples

Normalize a string path:

path = PathInfo.convert("runtime/results.json")
property raw: Path

Return the wrapped path.

Returns

Original normalized Path.

Examples

Pass the raw path to pathlib-aware code:

raw_path = info.raw
property raw_dir

Return the immediate parent of the wrapped path.

Returns

self.raw.parent.

Examples

Obtain a file’s containing directory:

directory = PathInfo("runtime/results.json").raw_dir
property resolved: str

Return a non-strict absolute path string.

Returns

Result of Path.resolve(strict=False) converted to text.

Examples

Resolve a path even before it exists:

absolute = PathInfo("future.txt").resolved
property name: str

Return the final path component including its suffixes.

Returns

Path.name.

Examples

Read a filename:

assert PathInfo("a/report.pdf").name == "report.pdf"
property suffix: str

Return the final filename suffix.

Returns

Path.suffix, including the leading dot when present.

Examples

Read the final suffix:

assert PathInfo("archive.tar.gz").suffix == ".gz"
property suffixes: List[str]

Return every filename suffix.

Returns

A mutable list copied from Path.suffixes.

Examples

Inspect a compound extension:

assert PathInfo("archive.tar.gz").suffixes == [".tar", ".gz"]
property stem: str

Return the final component without its last suffix.

Returns

Path.stem.

Examples

Read a filename stem:

assert PathInfo("report.pdf").stem == "report"
parent(levels: int = 1, absolute: bool = False, as_info: bool = False) → Path | PathInfo | None

Return an ancestor at the requested number of levels.

Parameters

Name

Type

Description

levels

int

Number of parents to traverse. Must be at least 1.

absolute

bool

Resolve the source path before traversing its parents.

as_info

bool

Wrap the result in PathInfo instead of returning a Path.

Returns

Type

Description

Path | PathInfo | None

Requested ancestor, or None when levels is invalid or the operation cannot be completed.

Examples

Obtain the grandparent as another wrapper:

root = PathInfo("a/b/file.txt").parent(levels=2, as_info=True)
property parts: Tuple[str, ...]

Return the individual path components as a tuple.

Returns

Components exposed by pathlib.PurePath.parts.

Examples

Inspect path components without modifying them:

components = PathInfo("reports/daily.json").parts
split() → List[str]

Return the individual path components as a list.

Returns

Type

Description

List[str]

A mutable list copied from parts.

Examples

Obtain a mutable component sequence:

components = PathInfo("reports/daily.json").split()
property exists: bool

Return whether the wrapped path exists.

Returns

True when the filesystem entry exists; otherwise False.

Examples

Guard a read operation:

if PathInfo("result.json").exists:
    print("ready")
property is_file: bool

Return whether the wrapped path is an existing regular file.

Returns

Result of pathlib.Path.is_file().

Examples

Distinguish a file from a directory:

is_report = PathInfo("result.json").is_file
property is_dir: bool

Return whether the wrapped path is an existing directory.

Returns

Result of pathlib.Path.is_dir().

Examples

Check a runtime directory:

is_runtime_dir = PathInfo(".runtime").is_dir
property as_posix: str

Return the wrapped path with forward-slash separators.

Returns

Result of pathlib.PurePath.as_posix().

Examples

Produce a portable display value:

display_path = PathInfo("reports/daily.json").as_posix
property stat: dict

Return basic filesystem metadata for the wrapped path.

Returns

Dictionary containing byte size and POSIX timestamps named created, modified, and accessed. A missing path returns {"error": "File not found"}.

Examples

Read the last modification time:

modified_at = PathInfo("result.json").stat.get("modified")
has_directory(directory_name: str) → bool

Check whether a named component occurs anywhere in the path.

Parameters

Name

Type

Description

directory_name

str

Component name to match case-insensitively.

Returns

Type

Description

bool

True when any component has the requested name.

Examples

Detect whether a path belongs to a runtime tree:

in_runtime = PathInfo("app/.runtime/data.json").has_directory(".RUNTIME")
delete() → None

Delete the wrapped file or directory when it exists.

Directories and all their contents are removed recursively. Missing paths are ignored.

Examples

Remove a disposable runtime tree:

PathInfo(".runtime/cache").delete()
clear_directory() → None

Remove every child while preserving the wrapped directory.

Existing child directories are removed recursively. A missing path or a non-directory path is ignored.

Examples

Empty a reusable cache directory:

PathInfo(".runtime/cache").clear_directory()
create_directory(parents: bool = False, exist_ok: bool = True) → None

Create the wrapped directory.

Parameters

Name

Type

Description

parents

bool

Create missing parent directories when True.

exist_ok

bool

Do not fail when the target directory already exists.

Raises

Exception

Description

FileExistsError

The target exists and exist_ok is False.

FileNotFoundError

A parent is missing and parents is False.

Examples

Create a nested runtime directory:

PathInfo(".runtime/cache").create_directory(parents=True)
search(pattern: str, search_folders: bool = False, deep: bool = False, as_info: bool = False) → List[Path | PathInfo]

Find matching files or directories below the wrapped directory.

Parameters

Name

Type

Description

pattern

str

Pattern accepted by pathlib.Path.glob().

search_folders

bool

Return directories instead of files.

deep

bool

Search recursively with pathlib.Path.rglob().

as_info

bool

Wrap each match in PathInfo.

Returns

Type

Description

List[Path | PathInfo]

Matching files or directories. Returns an empty list when the wrapped path is not a directory.

Examples

Find JSON files recursively:

files = PathInfo("reports").search("*.json", deep=True)
search_sorted(pattern: str, search_folders: bool = False, deep: bool = False, sort_by: str = 'mtime', reverse: bool = True, as_info: bool = False) → List[Path | PathInfo]

Find matches and order them by a filesystem timestamp.

Parameters

Name

Type

Description

pattern

str

Pattern accepted by search().

search_folders

bool

Return directories instead of files.

deep

bool

Search recursively.

sort_by

str

Timestamp field: "mtime", "ctime", or "atime". Unknown values fall back to "mtime".

reverse

bool

Put newer entries first when True.

as_info

bool

Wrap each match in PathInfo.

Returns

Type

Description

List[Path | PathInfo]

Matching entries ordered by the selected timestamp. Entries that cannot be inspected use timestamp 0.

Raises

Exception

Description

ValueError

If sort_by is not "mtime", "ctime" or "atime".

Examples

Retrieve the newest JSON report first:

reports = PathInfo("reports").search_sorted("*.json")
rename(new_name: str, on_conflict: str = 'overwrite') → PathInfo | None

Rename the wrapped entry within its current directory.

Parameters

Name

Type

Description

new_name

str

New file or directory name, not a full path.

on_conflict

str

"overwrite" deletes an existing destination; "uniquify" selects an available numbered name.

Returns

Type

Description

PathInfo | None

Wrapper for the renamed path, or None when the source is missing.

Raises

Exception

Description

ValueError

on_conflict is not a supported policy.

Examples

Preserve an old database under a timestamped name:

renamed = PathInfo("active.db").rename("active.previous.db")
move(destination: str | PathLike | Path, on_conflict: str = 'overwrite', create_parents: bool = True, as_file: bool = False) → PathInfo | None

Move the wrapped file or directory to a new destination.

Parameters

Name

Type

Description

destination

str | PathLike | Path

Target directory or full target path.

on_conflict

str

"overwrite" or "uniquify".

create_parents

bool

Create missing destination directories.

as_file

bool

Treat destination as an exact full file path.

Returns

Type

Description

PathInfo | None

Wrapper for the moved entry, or None when the source is missing.

Raises

Exception

Description

ValueError

on_conflict is not a supported policy.

Examples

Move a report into an archive directory:

moved = PathInfo("report.json").move("archive")
copy(destination: str | PathLike | Path, keep_permissions: bool = False, on_conflict: str = 'overwrite', create_parents: bool = True, as_file: bool = False) → PathInfo | None

Copy the wrapped file or directory to a new destination.

Parameters

Name

Type

Description

destination

str | PathLike | Path

Target directory or full target path.

keep_permissions

bool

Use shutil.copy2() for files when True; otherwise use shutil.copy().

on_conflict

str

"overwrite" or "uniquify".

create_parents

bool

Create missing destination directories.

as_file

bool

Treat destination as an exact full file path.

Returns

Type

Description

PathInfo | None

Wrapper for the copied entry, or None when the source is missing.

Raises

Exception

Description

ValueError

on_conflict is not a supported policy.

Examples

Copy a report without overwriting an existing archive:

copied = PathInfo("report.json").copy(
    "archive",
    on_conflict="uniquify",
)
static project_root(start: str | PathLike | Path | None = None, markers: Iterable[str] | None = None, extra_markers: Iterable[str] | None = None, skip_markers: Iterable[str] | None = None, fallback_to_cwd: bool = True, as_info: bool = False) → Path | PathInfo

Find the nearest ancestor containing a project marker.

The default marker sequence is index.py, pyproject.toml, setup.cfg, setup.py, .git, and requirements.txt.

Parameters

Name

Type

Description

start

str | PathLike | Path | None

File or directory from which to search. None uses the calling source file.

markers

Iterable[str] | None

Replacement base marker sequence. None uses the defaults.

extra_markers

Iterable[str] | None

Markers appended to the base sequence.

skip_markers

Iterable[str] | None

Markers removed from the effective sequence.

fallback_to_cwd

bool

Return Path.cwd() when no marker is found.

as_info

bool

Wrap the result in PathInfo.

Returns

Type

Description

Path | PathInfo

Nearest matching ancestor, or the current working directory when fallback is enabled.

Raises

Exception

Description

FileNotFoundError

No marker is found and fallback_to_cwd is False.

Examples

Locate a package root from a nested module:

root = PathInfo.project_root(
    start="src/package/module.py",
    markers=("pyproject.toml",),
)