diff --git a/src/pyscript/_generator.py b/src/pyscript/_generator.py index a0eda3b..24b81bc 100644 --- a/src/pyscript/_generator.py +++ b/src/pyscript/_generator.py @@ -3,18 +3,28 @@ import jinja2 -_env = jinja2.Environment(loader=jinja2.PackageLoader("pyscript")) +_cwd_loader = jinja2.FileSystemLoader(Path.cwd().resolve()) +_package_loader = jinja2.PackageLoader("pyscript") +_env = jinja2.Environment(loader=jinja2.ChoiceLoader([_cwd_loader, _package_loader])) -def string_to_html(input_str: str, title: str, output_path: Path) -> None: +def string_to_html( + input_str: str, title: str, template_name: Optional[str], output_path: Path +) -> None: """Write a Python script string to an HTML file template.""" - template = _env.get_template("basic.html") + template_name = template_name or "basic.html" + template = _env.get_template(template_name) with output_path.open("w") as fp: fp.write(template.render(code=input_str, title=title)) -def file_to_html(input_path: Path, title: str, output_path: Optional[Path]) -> None: +def file_to_html( + input_path: Path, + title: str, + template_name: Optional[str], + output_path: Optional[Path], +) -> None: """Write a Python script string to an HTML file template.""" output_path = output_path or input_path.with_suffix(".html") with input_path.open("r") as fp: - string_to_html(fp.read(), title, output_path) + string_to_html(fp.read(), title, template_name, output_path) diff --git a/src/pyscript/cli.py b/src/pyscript/cli.py index d193dcd..aa1468e 100644 --- a/src/pyscript/cli.py +++ b/src/pyscript/cli.py @@ -55,6 +55,7 @@ def version() -> None: ) _show_option = typer.Option(None, help="Open output file in web browser.") _title_option = typer.Option(None, help="Add title to HTML file.") +_template_option = typer.Option(None, help="Path to a user-provided template.") class Abort(typer.Abort): @@ -70,6 +71,7 @@ def wrap( command: Optional[str] = _command_option, show: Optional[bool] = _show_option, title: Optional[str] = _title_option, + template: Optional[str] = _template_option, ) -> None: """Wrap a Python script inside an HTML file.""" title = title or "PyScript App" @@ -94,10 +96,10 @@ def wrap( raise Abort("Must provide an output file or use `--show` option") if input_file is not None: - file_to_html(input_file, title, output) + file_to_html(input_file, title, template, output) if command: - string_to_html(command, title, output) + string_to_html(command, title, template, output) assert output is not None diff --git a/tests/test_cli.py b/tests/test_cli.py index 2a7efad..0945e5c 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -8,6 +8,7 @@ from mypy_extensions import VarArg from typer.testing import CliRunner, Result +import pyscript from pyscript import __version__ from pyscript.cli import app @@ -23,6 +24,8 @@ def invoke_cli(tmp_path: Path, monkeypatch: "MonkeyPatch") -> CLIInvoker: runner = CliRunner() monkeypatch.chdir(tmp_path) + # We also need to patch the template filesystem loader to use the new CWD + monkeypatch.setattr(pyscript._generator._cwd_loader, "searchpath", [tmp_path]) def f(*args: str) -> Result: return runner.invoke(app, args) @@ -167,3 +170,27 @@ def test_wrap_title( assert f"\n{command}\n" in html_text assert f"{expected_title}" in html_text + + +@pytest.fixture() +def user_template(tmp_path: Path) -> str: + name = "user_template.html" + with (tmp_path / name).open("w") as fp: + fp.write("User template") + return name + + +def test_wrap_user_template( + invoke_cli: CLIInvoker, tmp_path: Path, user_template: str +) -> None: + command = 'print("Hello World!")' + result = invoke_cli( + "wrap", "-c", command, "-o", "output.html", "--template", user_template + ) + assert result.exit_code == 0 + + expected_html_path = tmp_path / "output.html" + with expected_html_path.open() as fp: + html_text = fp.read() + + assert "User template" in html_text