add preview server

This commit is contained in:
Daniel Fichtinger 2025-06-21 20:06:52 -04:00
parent 296b3d2385
commit d8b491bc33
5 changed files with 97 additions and 1 deletions

View file

@ -12,7 +12,9 @@ dependencies = [
"jinja2>=3.1.6", "jinja2>=3.1.6",
"marko[codehilite]>=2.1.4", "marko[codehilite]>=2.1.4",
"python-frontmatter>=1.1.0", "python-frontmatter>=1.1.0",
"starlette>=0.47.1",
"typer>=0.16.0", "typer>=0.16.0",
"uvicorn>=0.34.3",
] ]
[project.scripts] [project.scripts]
@ -42,6 +44,7 @@ typeCheckingMode = "recommended"
reportExplicitAny = false reportExplicitAny = false
reportAny = false reportAny = false
reportUnusedCallResult = false reportUnusedCallResult = false
reportCallInDefaultInitializer = false
allowedUntypedLibraries = ["frontmatter"] allowedUntypedLibraries = ["frontmatter"]
[tool.ruff] [tool.ruff]

View file

@ -1,6 +1,6 @@
import typer import typer
from pathlib import Path from pathlib import Path
from zona import builder from zona import builder, server
app = typer.Typer() app = typer.Typer()
@ -15,6 +15,14 @@ def build(in_dir: str | None = None, out_dir: str | None = None):
builder.build(Path(in_dir), items) builder.build(Path(in_dir), items)
@app.command()
def serve(dir: Path = Path("public")):
if not dir.exists():
raise typer.BadParameter(f"Directory {dir} does not exist.")
typer.echo(f"Serving files from {dir}")
server.serve(dir)
@app.command() @app.command()
def init(): def init():
# init will populate the current directory with # init will populate the current directory with

View file

@ -9,6 +9,7 @@ class ZonaRenderer(HTMLRenderer):
@override @override
def render_link(self, element: Link): def render_link(self, element: Link):
href = element.dest href = element.dest
assert isinstance(href, str)
if href.endswith(".md") and not href.startswith("http"): if href.endswith(".md") and not href.startswith("http"):
href = href[:-3] + ".html" href = href[:-3] + ".html"
body: Any = self.render_children(element) body: Any = self.render_children(element)

13
src/zona/server.py Normal file
View file

@ -0,0 +1,13 @@
from starlette.applications import Starlette
from starlette.staticfiles import StaticFiles
import typer
import uvicorn
from pathlib import Path
def serve(dir: Path, host: str = "localhost", port: int = 8000):
app = Starlette()
app.mount("/", StaticFiles(directory=dir, html=True), name="zona")
typer.echo(f"Preview server running at http://{host}:{port}")
uvicorn.run(app, host=host, port=port, log_level="warning")

71
uv.lock generated
View file

@ -2,6 +2,20 @@ version = 1
revision = 2 revision = 2
requires-python = ">=3.12" requires-python = ">=3.12"
[[package]]
name = "anyio"
version = "4.9.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "idna" },
{ name = "sniffio" },
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" },
]
[[package]] [[package]]
name = "basedpyright" name = "basedpyright"
version = "1.29.4" version = "1.29.4"
@ -44,6 +58,24 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600, upload-time = "2025-02-05T09:27:24.345Z" }, { url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600, upload-time = "2025-02-05T09:27:24.345Z" },
] ]
[[package]]
name = "h11"
version = "0.16.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
]
[[package]]
name = "idna"
version = "3.10"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
]
[[package]] [[package]]
name = "iniconfig" name = "iniconfig"
version = "2.1.0" version = "2.1.0"
@ -282,6 +314,28 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
] ]
[[package]]
name = "sniffio"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
]
[[package]]
name = "starlette"
version = "0.47.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0a/69/662169fdb92fb96ec3eaee218cf540a629d629c86d7993d9651226a6789b/starlette-0.47.1.tar.gz", hash = "sha256:aef012dd2b6be325ffa16698f9dc533614fb1cebd593a906b90dc1025529a79b", size = 2583072, upload-time = "2025-06-21T04:03:17.337Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/82/95/38ef0cd7fa11eaba6a99b3c4f5ac948d8bc6ff199aabd327a29cc000840c/starlette-0.47.1-py3-none-any.whl", hash = "sha256:5e11c9f5c7c3f24959edbf2dffdc01bba860228acf657129467d8a7468591527", size = 72747, upload-time = "2025-06-21T04:03:15.705Z" },
]
[[package]] [[package]]
name = "typer" name = "typer"
version = "0.16.0" version = "0.16.0"
@ -306,6 +360,19 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" }, { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" },
] ]
[[package]]
name = "uvicorn"
version = "0.34.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "h11" },
]
sdist = { url = "https://files.pythonhosted.org/packages/de/ad/713be230bcda622eaa35c28f0d328c3675c371238470abdea52417f17a8e/uvicorn-0.34.3.tar.gz", hash = "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a", size = 76631, upload-time = "2025-06-01T07:48:17.531Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/6d/0d/8adfeaa62945f90d19ddc461c55f4a50c258af7662d34b6a3d5d1f8646f6/uvicorn-0.34.3-py3-none-any.whl", hash = "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885", size = 62431, upload-time = "2025-06-01T07:48:15.664Z" },
]
[[package]] [[package]]
name = "zona" name = "zona"
version = "0.1.0" version = "0.1.0"
@ -315,7 +382,9 @@ dependencies = [
{ name = "jinja2" }, { name = "jinja2" },
{ name = "marko", extra = ["codehilite"] }, { name = "marko", extra = ["codehilite"] },
{ name = "python-frontmatter" }, { name = "python-frontmatter" },
{ name = "starlette" },
{ name = "typer" }, { name = "typer" },
{ name = "uvicorn" },
] ]
[package.dev-dependencies] [package.dev-dependencies]
@ -331,7 +400,9 @@ requires-dist = [
{ name = "jinja2", specifier = ">=3.1.6" }, { name = "jinja2", specifier = ">=3.1.6" },
{ name = "marko", extras = ["codehilite"], specifier = ">=2.1.4" }, { name = "marko", extras = ["codehilite"], specifier = ">=2.1.4" },
{ name = "python-frontmatter", specifier = ">=1.1.0" }, { name = "python-frontmatter", specifier = ">=1.1.0" },
{ name = "starlette", specifier = ">=0.47.1" },
{ name = "typer", specifier = ">=0.16.0" }, { name = "typer", specifier = ">=0.16.0" },
{ name = "uvicorn", specifier = ">=0.34.3" },
] ]
[package.metadata.requires-dev] [package.metadata.requires-dev]