Coverage for src / marimushka / export.py: 100%
37 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-28 17:41 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-28 17:41 +0000
1"""Export module providing the public Python API.
3This module provides the main Python API for exporting marimo notebooks.
4For CLI usage, see the cli module.
6Example::
8 # Python API
9 from marimushka.export import main
10 main(notebooks="notebooks", apps="apps", output="_site")
12The exported files will be placed in the specified output directory (default: _site).
13"""
15from pathlib import Path
17from loguru import logger
19from . import __version__
20from .audit import get_audit_logger
21from .exceptions import ProgressCallback
22from .notebook import Kind, folder2notebooks
23from .orchestrator import generate_index
24from .validators import validate_template
27def main(
28 output: str | Path = "_site",
29 template: str | Path = Path(__file__).parent / "templates" / "tailwind.html.j2",
30 notebooks: str | Path = "notebooks",
31 apps: str | Path = "apps",
32 notebooks_wasm: str | Path = "notebooks",
33 sandbox: bool = True,
34 bin_path: str | Path | None = None,
35 parallel: bool = True,
36 max_workers: int = 4,
37 timeout: int = 300,
38 on_progress: ProgressCallback | None = None,
39) -> str:
40 """Export marimo notebooks and generate an index page.
42 Args:
43 output: Output directory for generated files. Defaults to "_site".
44 template: Path to Jinja2 template file. Defaults to built-in Tailwind template.
45 notebooks: Directory containing static notebooks. Defaults to "notebooks".
46 apps: Directory containing app notebooks. Defaults to "apps".
47 notebooks_wasm: Directory containing interactive notebooks. Defaults to "notebooks".
48 sandbox: Whether to run exports in isolated sandbox. Defaults to True.
49 bin_path: Custom path to uvx executable. Defaults to None.
50 parallel: Whether to export notebooks in parallel. Defaults to True.
51 max_workers: Maximum number of parallel workers. Defaults to 4.
52 timeout: Maximum time in seconds for each export. Defaults to 300.
53 on_progress: Optional callback for progress tracking. Called after each notebook export
54 with signature: on_progress(completed, total, notebook_name).
56 Returns:
57 Rendered HTML content as string, empty if no notebooks found.
59 Raises:
60 TemplateNotFoundError: If the template file does not exist.
61 TemplateInvalidError: If the template path is not a file.
62 TemplateRenderError: If the template fails to render.
63 IndexWriteError: If the index file cannot be written.
65 Example::
67 from marimushka.export import main
69 # Simple usage
70 main(notebooks="my-notebooks", apps="my-apps")
72 # With progress callback
73 def progress_handler(completed, total, name):
74 print(f"[{completed}/{total}] Exported {name}")
76 main(notebooks="my-notebooks", on_progress=progress_handler)
78 """
79 logger.info("Starting marimushka build process")
80 logger.info(f"Version of Marimushka: {__version__}")
81 output = output or "_site"
83 # Convert output_dir explicitly to Path
84 output_dir: Path = Path(output)
85 logger.info(f"Output directory: {output_dir}")
87 # Make sure the output directory exists
88 output_dir.mkdir(parents=True, exist_ok=True)
90 # Convert template to Path and validate early
91 template_file: Path = Path(template)
92 audit_logger = get_audit_logger()
93 validate_template(template_file, audit_logger)
95 logger.info(f"Using template file: {template_file}")
96 logger.info(f"Notebooks: {notebooks}")
97 logger.info(f"Apps: {apps}")
98 logger.info(f"Notebooks-wasm: {notebooks_wasm}")
99 logger.info(f"Sandbox: {sandbox}")
100 logger.info(f"Parallel: {parallel} (max_workers={max_workers})")
101 logger.info(f"Bin path: {bin_path}")
102 logger.info(f"Timeout: {timeout}s")
104 # Convert bin_path to Path if provided
105 bin_path_obj: Path | None = Path(bin_path) if bin_path else None
107 notebooks_data = folder2notebooks(folder=notebooks, kind=Kind.NB)
108 apps_data = folder2notebooks(folder=apps, kind=Kind.APP)
109 notebooks_wasm_data = folder2notebooks(folder=notebooks_wasm, kind=Kind.NB_WASM)
111 logger.info(f"# notebooks_data: {len(notebooks_data)}")
112 logger.info(f"# apps_data: {len(apps_data)}")
113 logger.info(f"# notebooks_wasm_data: {len(notebooks_wasm_data)}")
115 # Exit if no notebooks or apps were found
116 if not notebooks_data and not apps_data and not notebooks_wasm_data:
117 logger.warning("No notebooks or apps found!")
118 return ""
120 return generate_index(
121 output=output_dir,
122 template_file=template_file,
123 notebooks=notebooks_data,
124 apps=apps_data,
125 notebooks_wasm=notebooks_wasm_data,
126 sandbox=sandbox,
127 bin_path=bin_path_obj,
128 parallel=parallel,
129 max_workers=max_workers,
130 timeout=timeout,
131 on_progress=on_progress,
132 audit_logger=audit_logger,
133 )