Core¶
Configuration models used by the LATEX renderer.
CommonConfig
build_dir(Path | None)- Base directory for LATEX artifacts. Provide an absolute or project-relative path to override the default export root that books inherit when they do not specify one.
save_html(bool)- Persist the intermediate HTML render next to the PDF to aid troubleshooting before LATEX compilation.
mermaid_config(Path | None)- Path to a Mermaid configuration file. Point to a
.jsonor.mermaiddocument to customise diagram rendering. project_dir(Path | None)- MkDocs project root used to resolve relative paths when copying additional assets.
- BCP 47 language code forwarded to LATEX for hyphenation, translations, and
- metadata localisation.
legacy_latex_accents(bool)- When
True, escape accented characters, ligatures, and typographic punctuation using legacy LATEX macros. WhenFalse, keep Unicode glyphs compatible with LuaLaTeX/XeLaTeX (default). language(str | None)- BCP 47 language code forwarded to LATEX for hyphenation, translations, and metadata localisation.
CoverConfig
name(str)- Identifier of the cover template to apply. The value must match a template declared in the cover bundle.
color(str | None)- Primary colour override applied by the cover template.
logo(str | None)- Project-relative path to a logo asset displayed on the cover.
BookConfig
root(str | None)- Navigation entry treated as the starting point for the book. Use it when the root differs from the first MkDocs page.
title(str | None)- Title displayed on the cover and in output metadata. Falls back to
site_namewhen omitted. subtitle(str | None)- Optional subtitle appended to the cover and metadata.
author(str | None)- Primary author string rendered in the book metadata.
year(int | None)- Publication year to freeze in the output when
site_dateis not supplied. email(str | None)- Contact address printed in the credits.
folder(Path | None)- Output directory for the rendered book. Defaults to a slug of the title when not provided.
frontmatter(list[str])- MkDocs page titles moved before the main matter.
backmatter(list[str])- MkDocs page titles grouped into the appendices.
base_level(int)- Heading offset applied to align section numbering with the template expectations.
copy_files(dict[str, str])- Mapping of glob patterns to destination paths for copying additional assets alongside the book.
index_is_foreword(bool)- Treat the
indexpage as a foreword, typically removing numbering. drop_title_index(bool)- Suppress the
indexpage heading when it acts as a foreword. cover(CoverConfig)- Nested configuration controlling the book cover.
LaTeXConfig
enabled(bool)- Toggle LATEX generation without discarding configuration.
books(list[BookConfig])- Collection of books to produce, inheriting defaults from
CommonConfig. clean_assets(bool)- Remove stale assets from
build_dirto avoid accumulating unused files.
BookConfig ¶
Bases: CommonConfig
Configuration for an individual book.
set_folder ¶
set_folder() -> BookConfig
Populate the output folder from the book title when missing.
Source code in src/texsmith/core/config.py
157 158 159 160 161 162 | |
CommonConfig ¶
Bases: BaseModel
Common configuration propagated to each book.
CoverConfig ¶
Bases: BaseModel
Metadata used to render book covers.
LaTeXConfig ¶
Bases: CommonConfig
Configuration for LATEX taken from mkdocs.yml.
add_extra ¶
add_extra(**extra_data: Any) -> None
Allow consumers to attach additional attributes at runtime.
Source code in src/texsmith/core/config.py
188 189 190 191 | |
propagate ¶
propagate() -> LaTeXConfig
Propagate common values to nested book configurations.
Source code in src/texsmith/core/config.py
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | |
Rendering context primitives shared across the LATEX pipeline.
AssetRegistry
dataclass
¶
AssetRegistry(
output_root: Path,
assets_map: MutableMapping[str, Path] = dict(),
copy_assets: bool = True,
)
Centralised registry for rendered assets.
get ¶
get(key: str) -> Path
Retrieve a previously registered artefact.
Source code in src/texsmith/core/context.py
144 145 146 147 148 149 | |
items ¶
items() -> Iterable[tuple[str, Path]]
Iterate over registered assets yielding key/path pairs.
Source code in src/texsmith/core/context.py
151 152 153 | |
latex_path ¶
latex_path(path: Path | str) -> str
Return a LATEX-friendly path for an artefact.
Source code in src/texsmith/core/context.py
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | |
lookup ¶
lookup(key: str) -> Path | None
Return a previously registered artefact when available.
Source code in src/texsmith/core/context.py
139 140 141 142 | |
register ¶
register(key: str, artefact: Path | str) -> Path
Register a generated artefact and return its resolved path.
Source code in src/texsmith/core/context.py
131 132 133 134 135 136 137 | |
DocumentState
dataclass
¶
DocumentState(
abbreviations: dict[str, str] = dict(),
acronym_keys: dict[str, str] = dict(),
acronyms: dict[str, tuple[str, str]] = dict(),
acronym_entry_groups: dict[str, str] = dict(),
acronym_groups: list[tuple[str, str]] = list(),
glossary: dict[str, dict[str, Any]] = dict(),
snippets: dict[str, dict[str, Any]] = dict(),
headings: list[dict[str, Any]] = list(),
has_index_entries: bool = False,
requires_shell_escape: bool = False,
counters: dict[str, int] = dict(),
bibliography: dict[str, dict[str, Any]] = dict(),
citations: list[str] = list(),
footnotes: dict[str, str] = dict(),
index_entries: list[tuple[str, ...]] = list(),
pygments_styles: dict[str, str] = dict(),
script_usage: list[dict[str, Any]] = list(),
fallback_summary: list[dict[str, Any]] = list(),
callouts_used: bool = False,
)
In-memory state accumulated while rendering a document.
add_heading ¶
add_heading(
*, level: int, text: str, ref: str | None = None
) -> None
Track heading metadata to power table-of-contents generation.
Source code in src/texsmith/core/context.py
97 98 99 | |
next_counter ¶
next_counter(key: str = 'default') -> int
Increment and return the named counter.
Source code in src/texsmith/core/context.py
101 102 103 104 105 | |
peek_counter ¶
peek_counter(key: str = 'default') -> int
Return the current value of the named counter without modifying it.
Source code in src/texsmith/core/context.py
107 108 109 | |
record_citation ¶
record_citation(key: str) -> None
Track citation keys used throughout the document.
Source code in src/texsmith/core/context.py
115 116 117 118 119 120 | |
register_snippet ¶
register_snippet(key: str, payload: dict[str, Any]) -> None
Cache snippet metadata to render later in the pipeline.
Source code in src/texsmith/core/context.py
93 94 95 | |
remember_abbreviation ¶
remember_abbreviation(term: str, description: str) -> str
Track abbreviation definitions while ensuring consistency.
Source code in src/texsmith/core/context.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | |
remember_acronym ¶
remember_acronym(term: str, description: str) -> str
Register an acronym definition keyed by a normalised identifier.
Source code in src/texsmith/core/context.py
48 49 50 | |
remember_glossary ¶
remember_glossary(key: str, entry: dict[str, Any]) -> None
Record a glossary entry keyed by its identifier.
Source code in src/texsmith/core/context.py
89 90 91 | |
reset_counter ¶
reset_counter(key: str) -> None
Clear the named counter if it has been tracked.
Source code in src/texsmith/core/context.py
111 112 113 | |
RenderContext
dataclass
¶
RenderContext(
config: BookConfig,
formatter: LaTeXFormatter,
document: Any,
assets: AssetRegistry,
state: DocumentState = DocumentState(),
runtime: dict[str, Any] = dict(),
)
Shared context passed to every handler during rendering.
RenderContextLike ¶
Bases: Protocol
Structural surface shared by RenderContext and the writer state.
The LATEX writer threads its own WriterState through helpers that were
historically typed against :class:RenderContext (font-script rendering,
image/asset storage, DOI resolution). Both expose the same attributes, so
those helpers depend on this protocol rather than a concrete class.
Context objects used during document conversion.
ConversionContext
dataclass
¶
ConversionContext(
document: Document,
request: ConversionRequest,
output_dir: Path,
language: str,
generation: GenerationStrategy,
template_runtime: TemplateRuntime | None = None,
template_overrides: dict[str, Any] = dict(),
slot_requests: dict[str, str] = dict(),
bibliography_collection: BibliographyCollection
| None = None,
bibliography_map: dict[str, dict[str, Any]] = dict(),
config: BookConfig | None = None,
template_binding: TemplateBinding | None = None,
)
Per-document resolved state for the conversion pipeline.
The context is built in two successive phases:
- :func:
resolve_conversion_context(in :mod:.conversion.execution) fills the inputs derived from the document, request and front matter. At this point :attr:configand :attr:template_bindingare stillNonebecause no template has been chosen yet. - :func:
bind_template(in :mod:.conversion.templates) resolves the selected template and populates the binding-dependent fields.
Per-slot render flags (slot_options) are read from
document.slot_options on demand rather than copied here, to avoid
duplicating state that the :class:Document already owns.
GenerationStrategy
dataclass
¶
GenerationStrategy(
copy_assets: bool = True,
convert_assets: bool = False,
hash_assets: bool = False,
persist_manifest: bool = False,
)
Rendering strategy toggles shared across conversion workflows.
Shared conversion primitives exposed by the core package.
ConversionRequest
dataclass
¶
ConversionRequest(
documents: Sequence[Path] = tuple(),
bibliography_files: Sequence[Path] = list(),
front_matter: Mapping[str, Any] | None = None,
front_matter_path: Path | None = None,
slot_assignments: Mapping[
Path, Sequence[SlotAssignment]
] = dict(),
selector: str = "article.md-content__inner",
full_document: bool = False,
base_level: int = 0,
strip_heading_all: bool = False,
strip_heading_first_document: bool = False,
promote_title: bool = True,
suppress_title: bool = False,
numbered: bool = True,
markdown_extensions: Sequence[str] = list(),
template: str | None = None,
render_dir: Path | None = None,
template_options: Mapping[str, Any] = dict(),
embed_fragments: bool = False,
enable_fragments: Sequence[str] = tuple(),
disable_fragments: Sequence[str] = tuple(),
parser: str | None = None,
copy_assets: bool = True,
convert_assets: bool = False,
hash_assets: bool = False,
manifest: bool = False,
persist_debug_html: bool = False,
language: str | None = None,
http_user_agent: str | None = None,
legacy_latex_accents: bool = False,
diagrams_backend: str | None = None,
emitter: DiagnosticEmitter | None = None,
)
Immutable description of conversion inputs and engine settings.
copy ¶
copy() -> ConversionRequest
Create a deep copy to avoid cross-run mutations.
Source code in src/texsmith/core/conversion/models.py
63 64 65 66 67 68 69 70 71 72 | |
InputKind ¶
Bases: Enum
Supported input modalities handled by the conversion pipeline.
SlotAssignment
dataclass
¶
SlotAssignment(
slot: str, selector: str | None, include_document: bool
)
Directive mapping a document onto a template slot.
SlotOptions
dataclass
¶
SlotOptions(flatten: bool = False)
Per-slot rendering flags parsed from front matter.
UnsupportedInputError ¶
Bases: Exception
Raised when a CLI input argument cannot be processed.
coerce_slot_selector ¶
coerce_slot_selector(payload: Any) -> str | None
Normalise a selector definition coming from front matter.
Source code in src/texsmith/core/conversion/inputs.py
76 77 78 79 80 81 82 83 84 85 86 | |
extract_content ¶
extract_content(html: str, selector: str) -> str
Extract and return the inner HTML for the first element matching selector.
Source code in src/texsmith/core/conversion/inputs.py
445 446 447 448 449 450 451 452 453 454 455 | |
extract_front_matter_bibliography ¶
extract_front_matter_bibliography(
front_matter: Mapping[str, Any] | None,
) -> dict[str, InlineBibliographyEntry]
Return inline bibliography entries declared in the document front matter.
Source code in src/texsmith/core/conversion/inputs.py
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | |
extract_front_matter_slots ¶
extract_front_matter_slots(
front_matter: Mapping[str, Any],
) -> tuple[dict[str, str], dict[str, SlotOptions]]
Return front-matter slot selectors alongside their per-slot options.
Source code in src/texsmith/core/conversion/inputs.py
150 151 152 153 154 155 | |
parse_slot_mapping ¶
parse_slot_mapping(
raw: Any,
) -> tuple[dict[str, str], dict[str, SlotOptions]]
Parse slot mappings together with their per-slot options.
Accepts the three front-matter shapes {name: selector},
[{target/slot: ..., label: ...}] and the bare "name:selector"
string form. Returns a (selectors, options) tuple where options
only contains entries whose values differ from the SlotOptions
defaults, so callers can ignore it when they don't care.
Source code in src/texsmith/core/conversion/inputs.py
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | |
Diagnostics emitters¶
texsmith.core.diagnostics defines the DiagnosticEmitter protocol plus a few
stock implementations. Pass any emitter into ConversionService,
convert_documents, or TemplateSession to intercept warnings, errors, and
structured events.
| Emitter | Description | Typical usage |
|---|---|---|
CliEmitter (texsmith.ui.cli.diagnostics) |
Rich-powered emitter used by the Typer CLI. Respects -v and --debug, paints warnings as panels, and streams structured events to the diagnostics sidebar. |
Default when running texsmith. Import it in automation scripts when you want human-friendly output. |
LoggingEmitter |
Forwards warning, error, and event calls to the standard logging module. |
Daemons, notebooks, or services that rely on existing logging policy. |
NullEmitter |
No-op implementation. Useful when you want silent conversions or plan to capture diagnostics out-of-band. | Unit tests and benchmarking. |
Emitters expose a debug_enabled flag so downstream handlers can decide whether
to include stack traces or expensive state dumps. Implement your own to route
diagnostics to metrics systems or structured loggers.
Diagnostic abstractions shared across the conversion pipeline.
DiagnosticEmitter ¶
Bases: Protocol
Interface used to surface warnings, errors, and structured events.
LoggingEmitter ¶
LoggingEmitter(
*,
logger_obj: Logger | None = None,
debug_enabled: bool = False,
)
Emitter that forwards diagnostics to the standard logging module.
Source code in src/texsmith/core/diagnostics.py
44 45 46 47 48 | |
NullEmitter ¶
Emitter that ignores every diagnostic.
format_event_message ¶
format_event_message(
name: str, payload: Mapping[str, Any]
) -> str | None
Return a human-friendly summary for selected diagnostic events.
Source code in src/texsmith/core/diagnostics.py
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | |
Custom exception hierarchy for the LATEX rendering pipeline.
AssetMissingError ¶
Bases: LatexRenderingError
Raised when an expected asset cannot be located or generated.
InvalidNodeError ¶
Bases: LatexRenderingError
Raised when a handler receives an unexpected DOM node shape.
LatexRenderingError ¶
Bases: RuntimeError
Base exception for LATEX rendering failures.
TransformerExecutionError ¶
Bases: LatexRenderingError
Raised when an external converter fails to execute properly.
exception_hint ¶
exception_hint(exc: BaseException) -> str | None
Return the most specific message available for an exception chain.
Source code in src/texsmith/core/exceptions.py
38 39 40 41 | |
exception_messages ¶
exception_messages(exc: BaseException) -> list[str]
Return the collected message chain for an exception and its causes.
Source code in src/texsmith/core/exceptions.py
22 23 24 25 26 27 28 29 30 31 32 33 34 35 | |
LATEX escaping — single source of truth lives in the LATEX writer.
Escaping is a backend responsibility, so the canonical implementation moved to
:mod:texsmith.writers.latex.escaper. This module re-exports it so existing
importers (templates, fonts, extensions, legacy handler helpers) keep a stable
import path without duplicating the logic.
escape_latex_chars ¶
escape_latex_chars(
text: str, *, legacy_accents: bool = False
) -> str
Escape LATEX special characters leveraging pylatexenc.
Source code in src/texsmith/writers/latex/escaper.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | |
Abstractions for invoking Docker containers safely.
DockerLimits
dataclass
¶
DockerLimits(
cpus: float | int | None = None,
memory: str | None = None,
pids_limit: int | None = None,
)
Runtime constraints for Docker containers.
DockerRunRequest
dataclass
¶
DockerRunRequest(
image: str,
args: Sequence[str] = tuple(),
mounts: Sequence[VolumeMount] = tuple(),
environment: Mapping[str, str] = dict(),
workdir: str | None = None,
user: str | None = None,
use_host_user: bool = True,
remove: bool = True,
limits: DockerLimits | None = None,
network: str | None = None,
extra_args: Sequence[str] = tuple(),
)
Full request payload for a Docker execution.
DockerRunner ¶
DockerRunner(executable: str | None = None)
Utility class encapsulating Docker invocations.
Source code in src/texsmith/adapters/docker.py
53 54 55 | |
is_available ¶
is_available() -> bool
Return True when Docker can be located.
Source code in src/texsmith/adapters/docker.py
57 58 59 60 61 62 | |
reset ¶
reset() -> None
Clear cached executable lookup results.
Source code in src/texsmith/adapters/docker.py
64 65 66 | |
run ¶
run(
request: DockerRunRequest,
*,
capture_output: bool = True,
text: bool = True,
) -> subprocess.CompletedProcess[str]
Execute Docker with the supplied request.
Source code in src/texsmith/adapters/docker.py
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | |
VolumeMount
dataclass
¶
VolumeMount(
source: Path | str, target: str, read_only: bool = False
)
Bind mount configuration.
is_docker_available ¶
is_docker_available() -> bool
Check if Docker can be executed.
Source code in src/texsmith/adapters/docker.py
209 210 211 | |
run_container ¶
run_container(
image: str,
args: Sequence[str] = (),
*,
mounts: Sequence[VolumeMount] = (),
environment: Mapping[str, str] | None = None,
workdir: str | None = None,
user: str | None = None,
use_host_user: bool = True,
limits: DockerLimits | None = None,
network: str | None = None,
remove: bool = True,
extra_args: Sequence[str] = (),
capture_output: bool = True,
text: bool = True,
) -> subprocess.CompletedProcess[str]
Execute Docker using the shared runner.
Source code in src/texsmith/adapters/docker.py
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | |