File Tools

pymdtools.filetools provides high-level helpers for text files and local template folders. It builds on pymdtools.common for path normalization, file checks, encoding detection, backups, and writes.

Template Helpers

Template helpers resolve files under a template/ directory next to the current module or next to a caller-provided start_folder.

from pymdtools.filetools import get_template_file

html = get_template_file("emails/welcome.html", start_folder=".")

Template paths are intentionally constrained:

  • paths must be relative;

  • parent traversal with .. is rejected;

  • resolved files must remain inside the template/ directory.

FileName

FileName stores one normalized path and exposes convenient properties for the complete path, basename, parent directory, and suffix.

from pymdtools.filetools import FileName

name = FileName("docs/readme.txt")
name.filename = "README.md"
name.filename_ext = ".rst"

FileName only manipulates the stored path value. It does not create, move, or rename files on disk.

FileContent

FileContent extends FileName with an in-memory text buffer.

from pymdtools.filetools import FileContent

content = FileContent("README.md")
text = content.content or ""
content.content = text.replace("old", "new")
content.write()

When backup is enabled, writing over an existing file creates a backup first.

Public API

pymdtools.filetools

High-level helpers for working with template files and text file content.

This module builds on pymdtools.common instead of reimplementing low-level filesystem behavior. It provides:

  • get_template_file: read a file from a local template/ directory.

  • get_template_files_in_folder: list direct files under a template subfolder.

  • FileName: keep and edit a normalized file path by path/name/suffix.

  • FileContent: keep a file path together with an editable text buffer.

The module is intentionally text-oriented. Binary detection, encoding detection, atomic writes, backups, and path validation are delegated to pymdtools.common.

class pymdtools.filetools.FileContent(filename: str | PathLike[str] | Path | None = None, content: str | None = None, *, backup: bool = True, encoding: str | None = None)

Bases: FileName

File wrapper that stores text content and reads/writes it from disk.

FileContent extends FileName with an in-memory text buffer:

  • if instantiated with an existing filename and content is None, the file is read immediately;

  • setting content marks the object as needing a save;

  • read() reloads content from disk and clears save_needed;

  • write() writes the current content to disk and clears save_needed;

  • if backup is true, write() creates a numbered backup before overwriting an existing file.

content may be None to represent an empty/unloaded buffer, but write() requires actual text. Assigning any non-string, non-None value raises TypeError.

property backup: bool

Return whether writes create a backup before overwriting a file.

property content: str | None

Return the in-memory text content, or None if unloaded.

read(filename: str | PathLike[str] | Path | None = None, *, encoding: str | None = None) None

Read text content from disk into memory.

If filename is provided, it replaces the current stored path only after a successful read. encoding=None delegates encoding detection to common.get_file_content.

property save_needed: bool

Return whether the in-memory content should be written to disk.

write(filename: str | PathLike[str] | Path | None = None, *, encoding: str = 'utf-8', backup_ext: str = '.bak') None

Write the in-memory text content to disk.

If filename is provided, it replaces the current stored path only after a successful write. When backups are enabled and the target file already exists, a backup is created before writing the new content.

class pymdtools.filetools.FileName(filename: str | PathLike[str] | Path | None = None)

Bases: object

Utility object to manipulate a file path.

FileName keeps a normalized Path internally while preserving the historical public interface based on strings. It is useful when code needs to keep one file reference and update only one part of it:

  • full_filename: complete path, returned as str | None.

  • filename: basename with suffix, for example "report.md".

  • filename_path: parent directory, returned as str | None.

  • filename_ext: suffix, including the leading dot, for example ".md".

Assigning to these properties updates the stored path:

  • setting full_filename accepts any common.PathInput;

  • setting filename sanitizes the basename with common.get_valid_filename;

  • setting filename_path moves the stored file reference to another directory;

  • setting filename_ext replaces the suffix and requires a leading dot.

The object does not create, move, or rename files on disk. It only updates the path value it stores. Use is_file() and is_dir() to inspect the current filesystem state.

property filename: str | None

Return the basename, including suffix, or None.

property filename_ext: str | None

Return the file suffix, including the leading dot, or None.

property filename_path: str | None

Return the parent directory as a string, or None.

property full_filename: str | None

Return the complete normalized filename as a string, or None.

is_dir() bool

Return True when the stored path currently exists as a directory.

is_file() bool

Return True when the stored path currently exists as a file.

pymdtools.filetools.get_template_file(filename: str | PathLike[str] | Path, start_folder: str | PathLike[str] | Path | None = None) str

Load and return the content of a template file located under a template/ directory.

The lookup root is <base>/template. When start_folder is provided, base is that folder, or the parent folder when start_folder points to a file. When it is omitted, base is derived from this module’s own location.

filename must be relative to the template directory. Absolute paths, parent traversal with .., and resolved paths escaping the template directory are rejected.

Parameters:
  • filename – Template filename or relative path inside template/.

  • start_folder – Optional folder or file used to locate template/.

Returns:

The template file content.

Raises:
  • ValueError – If filename is empty, absolute, or escapes the template directory.

  • FileNotFoundError – If the template directory or file does not exist.

  • NotADirectoryError – If the template path is not a directory.

  • OSError – Propagated from the underlying file read operation.

pymdtools.filetools.get_template_files_in_folder(folder: str | PathLike[str] | Path, start_folder: str | PathLike[str] | Path | None = None) List[str]

List template files contained in template/<folder>.

Parameters:
  • folder – Subfolder name under the local template/ directory.

  • start_folder – Optional folder or file used to locate template/.

Returns:

A list of relative template paths (POSIX-style), e.g. [“emails/a.html”]. The result is sorted for determinism.

Raises:
  • ValueError – If folder is empty, absolute, or attempts path traversal.

  • FileNotFoundError – If the template folder does not exist.

  • NotADirectoryError – If the resolved template folder is not a directory.