all2md.utils.inputs

Utilities for uniform input handling across all2md modules.

This module provides standardized input validation and conversion functions that are used across all conversion modules in all2md. This ensures consistent behavior when handling different input types (paths, file-like objects, bytes, etc.) and provides clear error messages for unsupported inputs.

The functions in this module handle the conversion between different input types and perform validation to ensure that inputs are suitable for the requested conversion operations.

Functions

  • validate_and_convert_input: Main input validation and conversion function

  • is_path_like: Check if input is path-like (string or Path object)

  • is_file_like: Check if input is a file-like object

  • escape_markdown_special: Escape special Markdown characters in text

  • format_special_text: Format special text (underline, superscript, subscript)

  • format_markdown_heading: Format headings in hash or underline style

all2md.utils.inputs.is_path_like(obj: Any) bool

Check if an object is path-like (string or pathlib.Path).

Parameters:

obj (Any) – Object to check

Returns:

True if object is path-like, False otherwise

Return type:

bool

Examples

>>> is_path_like("document.pdf")
True
>>> is_path_like(Path("document.pdf"))
True
>>> is_path_like(BytesIO(b"data"))
False
all2md.utils.inputs.is_file_like(obj: Any) bool

Check if an object is file-like (has read method).

Parameters:

obj (Any) – Object to check

Returns:

True if object appears to be file-like, False otherwise

Return type:

bool

Examples

>>> from io import BytesIO
>>> is_file_like(BytesIO(b"data"))
True
>>> is_file_like("not_file_like")
False
all2md.utils.inputs.validate_page_range(pages: list[int] | str | None, max_pages: int | None = None) list[int] | None

Validate and normalize a page range specification.

All page numbers are 1-based (like “page 1”, “page 2”) and converted to 0-based internally.

Parameters:
  • pages (list[int], str, or None) – Page specification (1-based): - list[int]: List of page numbers [1, 2, 3] - str: Page range string, e.g. “1-3,5,10-” - None: Use all pages

  • max_pages (int or None, optional) – Maximum number of pages available for validation

Returns:

Validated list of 0-based page indices, or None if input was None

Return type:

list[int] or None

Raises:

PageRangeError – If page numbers are invalid or out of range

Examples

>>> validate_page_range([1, 2, 3], max_pages=5)
[0, 1, 2]
>>> validate_page_range("1-3,5", max_pages=10)
[0, 1, 2, 4]
>>> validate_page_range("10-", max_pages=12)
[9, 10, 11]
>>> validate_page_range([0], max_pages=5)
Traceback (most recent call last):
...
all2md.exceptions.PageRangeError: Invalid page number: 0. Pages must be >= 1.
all2md.utils.inputs.validate_and_convert_input(input_data: str | Path | BinaryIO | BytesIO | StringIO | bytes | Any, supported_types: list[str] | None = None, require_binary: bool = False) tuple[Any, str]

Validate input and convert to appropriate format for processing.

This function handles the common pattern of accepting different input types (paths, file-like objects, bytes, document objects) and converting them to a format suitable for the conversion functions.

Parameters:
  • input_data (InputType) – Input data to validate and convert

  • supported_types (list[str] or None, optional) – List of supported input type names for error messages

  • require_binary (bool, default False) – Whether the input must be in binary mode (vs text mode)

Returns:

Tuple of (converted_input, input_type_description) where input_type_description is one of: “path”, “file”, “bytes”, “object”

Return type:

tuple[Any, str]

Raises:

Examples

>>> # Path input
>>> data, type_desc = validate_and_convert_input("document.pdf")
>>> print(type_desc)
path
>>> # File-like input
>>> from io import BytesIO
>>> data, type_desc = validate_and_convert_input(BytesIO(b"content"))
>>> print(type_desc)
file
all2md.utils.inputs.escape_markdown_special(text: str, escape_chars: str | None = None) str

Escape special Markdown characters in text to prevent formatting.

Parameters:
  • text (str) – Text containing potential Markdown special characters

  • escape_chars (str or None, optional) – Characters to escape. If None, uses default set from constants

Returns:

Text with special characters escaped with backslashes

Return type:

str

Examples

>>> escape_markdown_special("This *should* not be italic")
'This \\*should\\* not be italic'
>>> escape_markdown_special("Link: [text](url)")
'Link: \\[text\\]\\(url\\)'
all2md.utils.inputs.format_special_text(text: str, format_type: str, mode: str = 'html') str

Format special text (underline, superscript, subscript) according to mode.

Parameters:
  • text (str) – Text content to format

  • format_type ({"underline", "superscript", "subscript"}) – Type of special formatting to apply

  • mode ({"html", "markdown", "ignore"}, default "html") – Output format mode: - “html”: Use HTML tags (<u>, <sup>, <sub>) - “markdown”: Use Markdown-style syntax (__, ^, ~) - “ignore”: Return plain text without formatting

Returns:

Formatted text according to the specified mode

Return type:

str

Examples

>>> format_special_text("underlined", "underline", "html")
'<u>underlined</u>'
>>> format_special_text("superscript", "superscript", "markdown")
'^superscript^'
>>> format_special_text("subscript", "subscript", "ignore")
'subscript'
all2md.utils.inputs.format_markdown_heading(text: str, level: int, use_hash: bool = True) str

Format a heading in Markdown using either hash or underline style.

This function formats only the heading itself, without adding trailing blank lines. Block-level spacing should be handled by the caller (e.g., document renderers that add spacing between block elements).

Parameters:
  • text (str) – The heading text content

  • level (int) – The heading level (1-6 for hash style, 1-2 for underline style)

  • use_hash (bool, default True) – Whether to use hash-style headings (# Heading) or underline style (Headingn=======)

Returns:

Formatted heading string ending with a single newline

Return type:

str

Examples

>>> format_markdown_heading("Main Title", 1, use_hash=True)
'# Main Title\n'
>>> format_markdown_heading("Main Title", 1, use_hash=False)
'Main Title\n==========\n'
>>> format_markdown_heading("Subtitle", 2, use_hash=False)
'Subtitle\n--------\n'

Notes

For underline style: - Level 1 headings use ‘=’ characters for underline - Level 2+ headings use ‘-’ characters for underline - Only levels 1-2 are supported for underline style; higher levels fall back to hash style

For hash style: - Supports levels 1-6 (# to ######) - Levels beyond 6 are clamped to 6

Spacing between blocks should be handled externally. This function does NOT add trailing blank lines to avoid conflicts with document-level spacing logic.

all2md.utils.inputs.parse_page_ranges(page_spec: str, total_pages: int) list[int]

Parse page range specification into list of 0-based page indices.

Supports various formats: - “1-3” → [0, 1, 2] - “5” → [4] - “10-” → [9, 10, …, total_pages-1] - “1-3,5,10-” → combined ranges - “5-3” → [2, 3, 4] (automatically swaps to “3-5”)

Reversed ranges (where start > end) are automatically corrected by swapping the values. For example, “10-5” is treated as “5-10”.

Parameters:
  • page_spec (str) – Page range specification (1-based page numbers)

  • total_pages (int) – Total number of pages in document

Returns:

Sorted list of 0-based page indices

Return type:

list of int

Examples

>>> parse_page_ranges("1-3,5", 10)
[0, 1, 2, 4]
>>> parse_page_ranges("8-", 10)
[7, 8, 9]
>>> parse_page_ranges("10-5", 10)
[4, 5, 6, 7, 8, 9]