Skip to content

Commit 76f3c4d

Browse files
committed
09: Build/downloader tool.
1 parent 5b0f087 commit 76f3c4d

27 files changed

+555
-32820
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,6 @@ node_modules/
142142
/dist/
143143
/docs/_build/
144144
/src/psc/pyodide/
145+
!/src/psc/pyodide/README.md
145146
/src/psc/pyscript/
147+
!/src/psc/pyscript/README.md

TODO.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# TODO
2+
3+
## Now
4+
5+
## Eventually
6+
7+
- Upgrade mypy
8+
- Remove type hints from examples
9+
- Add another example
10+
- Get nox to work with downloaded pyodide/pyscript
11+
- Get rid of Poetry
12+
13+
## Done
14+
15+
- Add a build step for the downloader
16+
- Upgrade to latest PyScript

poetry.lock

Lines changed: 202 additions & 169 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Jinja2 = "^3.1.2"
6060
types-requests = "^2.28.10"
6161

6262
[tool.poetry.scripts]
63-
psc = "psc.__main__:main"
63+
psc = "psc.__main__:app"
6464

6565
[tool.coverage.paths]
6666
source = ["src", "*/site-packages"]

src/psc/__init__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""PyScript Collective."""
22

3-
__all__ = [
4-
"app",
5-
]
6-
7-
from .app import app
3+
# __all__ = [
4+
# "app",
5+
# ]
6+
#
7+
# from .app import app

src/psc/__main__.py

Lines changed: 104 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,121 @@
11
"""Command-line interface for PSC."""
2+
import os
3+
import tarfile
4+
from pathlib import Path
5+
from shutil import copytree
6+
from tempfile import TemporaryDirectory
27

38
import typer
49
import uvicorn
10+
from starlette.testclient import TestClient
11+
from urllib3 import HTTPResponse
12+
from urllib3 import PoolManager
13+
14+
from psc.here import HERE
15+
from psc.resources import get_resources
516

617

718
app = typer.Typer()
819

920

21+
def rmtree(root: Path) -> None:
22+
"""Recursively remove everything in the target path."""
23+
for p in root.iterdir():
24+
if p.is_dir():
25+
rmtree(p)
26+
else:
27+
p.unlink()
28+
29+
root.rmdir()
30+
31+
32+
@app.command()
33+
def download(
34+
dry_run: bool = typer.Option(False, "--dry-run")
35+
) -> None: # pragma: no cover
36+
"""Download Pyodide and PyScript distributions into project dir."""
37+
# Get Pyodide first
38+
pyodide_url_prefix = "https://github.com/pyodide/pyodide/releases/download"
39+
pyodide_url = f"{pyodide_url_prefix}/0.21.3/pyodide-build-0.21.3.tar.bz2"
40+
http = PoolManager()
41+
pyodide_request: HTTPResponse = http.request("GET", pyodide_url) # type: ignore
42+
with TemporaryDirectory() as tmp_dir_name:
43+
os.chdir(tmp_dir_name)
44+
tmp_dir = Path(tmp_dir_name)
45+
temp_file = tmp_dir / "pyodide.tar.bz2"
46+
temp_file.write_bytes(pyodide_request.data)
47+
tar = tarfile.open(temp_file)
48+
tar.extractall()
49+
target = HERE / "pyodide"
50+
if not dry_run:
51+
copytree(tmp_dir / "pyodide", target, dirs_exist_ok=True)
52+
print("Downloaded Pyodide")
53+
54+
# Next, PyScript
55+
pyscript_url = "https://pyscript.net/latest/pyscript.js"
56+
pyscript_request: HTTPResponse = http.request("GET", pyscript_url) # type: ignore
57+
if not dry_run:
58+
target = HERE / "pyscript"
59+
if not dry_run:
60+
with open(target / "pyscript.js", "wb") as pyscript_output:
61+
pyscript_output.write(pyscript_request.data)
62+
63+
print("Downloaded PyScript")
64+
65+
66+
@app.command()
67+
def build() -> None: # pragma: no cover
68+
"""Write the export to a public directory."""
69+
print("Building to the public directory")
70+
71+
# If the target directory exists, remove it, then copy everything
72+
# under src/psc to the target
73+
public = HERE.parent.parent / "dist/public"
74+
if public.exists():
75+
rmtree(public)
76+
copytree(HERE, public)
77+
78+
# Setup test client async with our app
79+
from psc.app import app as web_app
80+
81+
with TestClient(web_app) as test_client:
82+
# Render the home page then write to the output directory
83+
response = test_client.get("/")
84+
assert response.status_code == 200
85+
html = response.text
86+
output = public / "index.html"
87+
output.write_text(html)
88+
89+
# Same for gallery page
90+
response = test_client.get("/gallery/index.html")
91+
assert response.status_code == 200
92+
html = response.text
93+
# output = public / "gallery/index.html"
94+
with open(public / "gallery/index.html", "w") as f:
95+
f.write(html)
96+
97+
# Now for each page
98+
resources = get_resources()
99+
for page in resources.pages.values():
100+
response = test_client.get(f"/pages/{page.path.stem}.html")
101+
output = public / f"pages/{page.path.stem}.html"
102+
output.write_text(response.text)
103+
104+
# And for each example
105+
for example in resources.examples.values():
106+
url = f"/gallery/examples/{example.path.stem}/index.html"
107+
response = test_client.get(url)
108+
output = public / f"gallery/examples/{example.path.stem}/index.html"
109+
output.write_text(response.text)
110+
111+
112+
# @app.callback(invoke_without_command=True)
10113
@app.command()
11-
def main(dry_run: bool = typer.Option(False, "--dry-run")) -> None: # pragma: no cover
114+
def start(dry_run: bool = typer.Option(False, "--dry-run")) -> None: # pragma: no cover
12115
"""Default command, used to start the server."""
13116
# If running from the test, we don't want to actually start server
14117
if dry_run:
15118
print("Skipping server startup")
16119
else:
17120
print("Starting server")
18121
uvicorn.run("psc:app", port=3000, log_level="info") # pragma: no cover
19-
20-
21-
if __name__ == "__main__": # pragma: no cover
22-
app()

src/psc/app.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@ async def favicon(request: Request) -> FileResponse:
3232
async def homepage(request: Request) -> _TemplateResponse:
3333
"""Handle the home page."""
3434
index_file = HERE / "index.html"
35+
root_path = "."
3536

3637
return templates.TemplateResponse(
3738
"homepage.jinja2",
3839
dict(
3940
title="Home Page",
4041
main=index_file.read_text(),
42+
root_path=root_path,
4143
request=request,
4244
),
4345
)
@@ -46,12 +48,14 @@ async def homepage(request: Request) -> _TemplateResponse:
4648
async def gallery(request: Request) -> _TemplateResponse:
4749
"""Handle the gallery listing page."""
4850
these_examples: Iterator[Example] = request.app.state.resources.examples.values()
51+
root_path = ".."
4952

5053
return templates.TemplateResponse(
5154
"gallery.jinja2",
5255
dict(
5356
title="Gallery",
5457
examples=these_examples,
58+
root_path=root_path,
5559
request=request,
5660
),
5761
)
@@ -99,10 +103,10 @@ async def content_page(request: Request) -> _TemplateResponse:
99103
Route("/favicon.png", favicon),
100104
Route("/gallery/index.html", gallery),
101105
Route("/gallery", gallery),
102-
Route("/gallery/{example_name}/index.html", example),
103-
Route("/gallery/{example_name}/", example),
104-
Route("/pages/{page_name}", content_page),
105-
Mount("/gallery", StaticFiles(directory=HERE / "examples")),
106+
Route("/gallery/examples/{example_name}/index.html", example),
107+
Route("/gallery/examples/{example_name}/", example),
108+
Route("/pages/{page_name}.html", content_page),
109+
Mount("/gallery", StaticFiles(directory=HERE / "gallery")),
106110
Mount("/static", StaticFiles(directory=HERE / "static")),
107111
Mount("/pyscript", StaticFiles(directory=PYSCRIPT)),
108112
Mount("/pyodide", StaticFiles(directory=PYODIDE)),

src/psc/fixtures.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,5 +178,5 @@ def _route_handler(route: Route) -> None:
178178
page.route("**", _route_handler)
179179

180180
# Don't spend 30 seconds on timeout
181-
page.set_default_timeout(8000)
181+
page.set_default_timeout(12000)
182182
return page

src/psc/gallery/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Gallery of examples, contributors, and more."""

src/psc/examples/hello_world/index.html renamed to src/psc/gallery/examples/hello_world/index.html

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,33 @@
55

66
<!DOCTYPE html>
77
<html lang="en">
8-
<head>
8+
<head>
99
<meta charset="utf-8">
1010
<meta name="viewport" content="width=device-width,initial-scale=1">
1111

1212
<title>Hello World</title>
13-
<meta name="subtitle" content="The classic hello world, but in Python -- in a browser!" >
13+
<meta name="subtitle" content="The classic hello world, but in Python -- in a browser!">
1414

15-
<link rel="icon" type="image/png" href="../../favicon.png">
16-
<script defer src="../../pyscript/pyscript.js"></script>
15+
<link rel="icon" type="image/png" href="../../../favicon.png">
16+
<script defer src="../../../pyscript/pyscript.js"></script>
1717
<link rel="stylesheet" href="hello_world.css">
1818
<script defer src="hello_world.js"></script>
19-
</head>
19+
</head>
2020

2121
<body>
2222
<py-config>
23-
autoclose_loader: true
24-
runtimes:
25-
- src: "../../pyodide/pyodide.js"
26-
name: pyodide-0.20
27-
lang: python
23+
autoclose_loader = true
24+
25+
[[runtimes]]
26+
src = "../../../pyodide/pyodide.js"
2827
</py-config>
2928
<main>
3029
<h1>Hello ...</h1>
3130
<div id="output"></div>
3231
</main>
3332
<h6>More Info</h6>
3433
<py-script>
35-
pyscript.write("output", "...world")
34+
pyscript.write("output", "...world")
3635
</py-script>
3736
</body>
3837
</html>

src/psc/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
<h1>PyScript Collective</h1>
33
<h2>Examples</h2>
44
<ul>
5-
<li><a href="examples/hello_world/index.html">Hello World</a></li>
5+
<li><a href="gallery/hello_world/index.html">Hello World</a></li>
66
</ul>
77
</main>

src/psc/pyodide/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The pyodide sources will be downloaded into here when you run the
2+
download step.

src/psc/pyscript/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The pyscript sources will be downloaded into here when you run the
2+
download step.

0 commit comments

Comments
 (0)