Skip to content

Commit e999286

Browse files
committed
Up through antigravity example.
1 parent 48da4d9 commit e999286

20 files changed

+326
-145
lines changed

poetry.lock

Lines changed: 30 additions & 119 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
@@ -16,7 +16,7 @@ classifiers = [
1616
Changelog = "https://github.com/pauleveritt/psc/releases"
1717

1818
[tool.poetry.dependencies]
19-
python = "^3.7"
19+
python = "^3.10"
2020
click = ">=8.0.1"
2121
nox = "^2022.1.7"
2222
typer = { extras = ["all"], version = "^0.6.1" }
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>Altair Visualization</title>
5+
<link rel="icon" type="image/png" href="../../../favicon.png">
6+
<script defer src="../../../pyscript/pyscript.js"></script>
7+
</head>
8+
<body>
9+
<py-config src="../py_config.toml">
10+
packages=[
11+
"altair",
12+
"pandas",
13+
"vega_datasets"
14+
]
15+
</py-config>
16+
<div id="altair" style="width: 100%; height: 100%"></div>
17+
<py-script output="altair">
18+
import altair as alt
19+
from vega_datasets import data
20+
21+
source = data.movies.url
22+
23+
pts = alt.selection(type="single", encodings=['x'])
24+
25+
rect = alt.Chart(data.movies.url).mark_rect().encode(
26+
alt.X('IMDB_Rating:Q', bin=True),
27+
alt.Y('Rotten_Tomatoes_Rating:Q', bin=True),
28+
alt.Color('count()',
29+
scale=alt.Scale(scheme='greenblue'),
30+
legend=alt.Legend(title='Total Records')
31+
)
32+
)
33+
34+
circ = rect.mark_point().encode(
35+
alt.ColorValue('grey'),
36+
alt.Size('count()',
37+
legend=alt.Legend(title='Records in Selection')
38+
)
39+
).transform_filter(
40+
pts
41+
)
42+
43+
bar = alt.Chart(source).mark_bar().encode(
44+
x='Major_Genre:N',
45+
y='count()',
46+
color=alt.condition(pts, alt.ColorValue("steelblue"), alt.ColorValue("grey"))
47+
).properties(
48+
width=550,
49+
height=200
50+
).add_selection(pts)
51+
52+
alt.vconcat(
53+
rect + circ,
54+
bar
55+
).resolve_legend(
56+
color="independent",
57+
size="independent"
58+
)
59+
</py-script>
60+
</body>
61+
</html>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
title: Altair Visualization
3+
subtitle: Declarative statistical visualization library.
4+
---
5+
Visualizing the IMDB ranking.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""Animate the xkcd comic."""
2+
import random
3+
import sys
4+
5+
from js import DOMParser
6+
from js import document
7+
from js import setInterval
8+
from pyodide.ffi import create_proxy
9+
from pyodide.http import open_url
10+
11+
12+
class Antigravity:
13+
"""Implement antigravity."""
14+
15+
url = "./antigravity.svg"
16+
17+
def __init__(self, target=None, interval=10, append=True, fly=False):
18+
"""Construct antigravity."""
19+
target = target or sys.stdout._out
20+
self.target = (
21+
document.getElementById(target) if isinstance(target, str) else target
22+
)
23+
doc = DOMParser.new().parseFromString(
24+
open_url(self.url).read(), "image/svg+xml"
25+
)
26+
self.node = doc.documentElement
27+
if append:
28+
self.target.append(self.node)
29+
else:
30+
self.target.replaceChildren(self.node)
31+
self.xoffset, self.yoffset = 0, 0
32+
self.interval = interval
33+
if fly:
34+
self.fly()
35+
36+
def fly(self):
37+
"""Schedule a taking off-and-fly."""
38+
setInterval(create_proxy(self.move), self.interval)
39+
40+
def move(self):
41+
"""Move the item."""
42+
char = self.node.getElementsByTagName("g")[1]
43+
char.setAttribute("transform", f"translate({self.xoffset}, {-self.yoffset})")
44+
self.xoffset += random.normalvariate(0, 1) / 20
45+
if self.yoffset < 50:
46+
self.yoffset += 0.1
47+
else:
48+
self.yoffset += random.normalvariate(0, 1) / 20
49+
50+
51+
_auto = Antigravity(append=True)
52+
fly = _auto.fly

src/psc/gallery/examples/antigravity/antigravity.svg

Lines changed: 72 additions & 0 deletions
Loading
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>xkcd Antigravity</title>
5+
<link rel="icon" type="image/png" href="../../../favicon.png">
6+
<script defer src="../../../pyscript/pyscript.js"></script>
7+
</head>
8+
<body>
9+
<py-config src="../py_config.toml">
10+
paths = ["./antigravity.py"]
11+
</py-config>
12+
<strong>Based on xkcd: antigravity https://xkcd.com/353/.</strong>
13+
<py-script>
14+
import antigravity
15+
16+
antigravity.fly()
17+
</py-script>
18+
19+
</body>
20+
</html>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
title: xkcd Antigravity
3+
subtitle: We can fly!
4+
---
5+
Based on the [xkcd antigravity](https://xkcd.com/353/)

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
<!DOCTYPE html>
22
<html lang="en">
33
<head>
4-
<meta charset="utf-8">
5-
<meta name="viewport" content="width=device-width,initial-scale=1">
6-
74
<title>Hello World</title>
8-
95
<link rel="icon" type="image/png" href="../../../favicon.png">
106
<script defer src="../../../pyscript/pyscript.js"></script>
117
<link rel="stylesheet" href="hello_world.css">
12-
<script defer src="hello_world.js"></script>
138
</head>
149
<body>
1510
<py-config src="../py_config.toml"></py-config>

src/psc/gallery/examples/hello_world/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
title: Hello World
33
subtitle: The classic hello world, but in Python -- in a browser!
44
---
5-
The *body* description.
5+
The *body* description.

src/psc/gallery/examples/hello_world_py/index.html

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,11 @@
1-
<!--
2-
contributor: example@contributor.me
3-
tags: example-tag, another-example
4-
-->
5-
61
<!DOCTYPE html>
72
<html lang="en">
83
<head>
9-
<meta charset="utf-8">
10-
<meta name="viewport" content="width=device-width,initial-scale=1">
11-
124
<title>Hello World Python</title>
13-
145
<link rel="icon" type="image/png" href="../../../favicon.png">
156
<script defer src="../../../pyscript/pyscript.js"></script>
167
<link rel="stylesheet" href="hello_world.css">
17-
<script defer src="hello_world.js"></script>
188
</head>
19-
209
<body>
2110
<py-config src="../py_config.toml">
2211
paths = ["hello_world.py"]

src/psc/gallery/examples/hello_world_py/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
title: Hello World Python
33
subtitle: The hello world example, but in a .py file.
44
---
5-
The *body* description.
5+
The *body* description.

src/psc/resources.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"""
55
from dataclasses import dataclass
66
from dataclasses import field
7-
from pathlib import Path
87
from pathlib import PurePath
98
from typing import cast
109

@@ -15,6 +14,7 @@
1514

1615
from psc.here import HERE
1716

17+
1818
EXCLUSIONS = ("pyscript.css", "pyscript.js", "favicon.png")
1919

2020

tests/examples/test_altair.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""Test the ``Altair`` example."""
2+
import pytest
3+
from playwright.sync_api import Page
4+
5+
from psc.fixtures import PageT
6+
7+
8+
def test_altair(client_page: PageT) -> None:
9+
"""Test the static HTML for Altair."""
10+
soup = client_page("/gallery/examples/altair/")
11+
title = soup.select_one("title")
12+
assert title and title.text == "Altair Visualization | PyScript Collective"
13+
14+
15+
@pytest.mark.full
16+
def test_altair_full(fake_page: Page) -> None:
17+
"""Use Playwright to do a test on Altair."""
18+
# Use `PWDEBUG=1` to run "head-ful" in Playwright test app
19+
url = "http://fake/gallery/examples/altair/index.html"
20+
fake_page.goto(url)
21+
assert fake_page.title() == "Altair Visualization"
22+
element = fake_page.wait_for_selector(".chart-wrapper")
23+
if element:
24+
assert element.get_attribute("role") == "graphics-document"

tests/examples/test_antigravity.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""Test the ``Antigravity`` example."""
2+
import pytest
3+
from playwright.sync_api import Page
4+
5+
from psc.fixtures import PageT
6+
7+
8+
def test_antigravity(client_page: PageT) -> None:
9+
"""Test the static HTML for Antigravity."""
10+
soup = client_page("/gallery/examples/antigravity/")
11+
title = soup.select_one("title")
12+
assert title and title.text == "xkcd Antigravity | PyScript Collective"
13+
14+
15+
@pytest.mark.full
16+
def test_antigravity_full(fake_page: Page) -> None:
17+
"""Use Playwright to do a test on Antigravity."""
18+
# Use `PWDEBUG=1` to run "head-ful" in Playwright test app
19+
url = "http://fake/gallery/examples/antigravity/index.html"
20+
fake_page.goto(url)
21+
assert fake_page.title() == "xkcd Antigravity"
22+
element = fake_page.wait_for_selector("#svg8")
23+
if element:
24+
assert element.get_attribute("id") == "svg8"

tests/examples/test_hello_world.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ def test_hello_world_full(fake_page: Page) -> None:
1818
# Use `PWDEBUG=1` to run "head-ful" in Playwright test app
1919
url = "http://fake/gallery/examples/hello_world/index.html"
2020
fake_page.goto(url)
21+
assert fake_page.title() == "Hello World"
2122
element = fake_page.wait_for_selector("text=...world")
2223
if element:
2324
assert element.text_content() == "...world"

tests/examples/test_hello_world_py.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
"""Test the ``Hello World`` in Python file example."""
2+
import builtins
3+
from dataclasses import dataclass
4+
from typing import cast
5+
26
import pytest
37
from playwright.sync_api import Page
48

@@ -12,12 +16,36 @@ def test_hello_world(client_page: PageT) -> None:
1216
assert title and title.text == "Hello World Python | PyScript Collective"
1317

1418

19+
@dataclass
20+
class FakeElement:
21+
"""Stub out the usage of PyScript's injected Element."""
22+
23+
target_name: str
24+
result: str | None = None
25+
26+
def write(self, value: str) -> None:
27+
"""Store what you were told to display."""
28+
self.result = value
29+
30+
31+
def test_hello_world_python() -> None:
32+
"""Unit test the hello_world.py that is loaded."""
33+
try:
34+
builtins.Element = FakeElement
35+
from psc.gallery.examples.hello_world_py.hello_world import output
36+
finally:
37+
delattr(builtins, "Element")
38+
39+
assert cast(FakeElement, output).result == "From Python..."
40+
41+
1542
@pytest.mark.full
1643
def test_hello_world_full(fake_page: Page) -> None:
1744
"""Use Playwright to do a test on Hello World."""
1845
# Use `PWDEBUG=1` to run "head-ful" in Playwright test app
1946
url = "http://fake/gallery/examples/hello_world_py/index.html"
2047
fake_page.goto(url)
48+
assert fake_page.title() == "Hello World Python"
2149
element = fake_page.wait_for_selector("text=From Python...")
2250
if element:
2351
assert element.text_content() == "From Python..."

tests/test_generic_example.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
"""Test machinery common to all gallery examples."""
2-
import pytest
3-
from bs4 import element
4-
from playwright.sync_api import Page
52
from starlette.testclient import TestClient
63

74
from psc.fixtures import PageT
@@ -24,7 +21,6 @@ def test_hello_world(client_page: PageT) -> None:
2421

2522
# See if extra_head got filled, then resolve those
2623
assert soup.find_all("link", href="hello_world.css")
27-
assert soup.find_all("script", src="hello_world.js")
2824

2925
# Ensure the ``<main>`` got filled
3026
assert soup.select_one("main")

tests/test_main.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
"""Test cases for the __main__ module."""
2-
import pytest
32
from typer.testing import CliRunner
43

54
from psc.__main__ import app

tests/test_resources.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ def test_example() -> None:
7676
== "The classic hello world, but in Python -- in a browser!"
7777
)
7878
assert "hello_world.css" in this_example.extra_head
79-
assert "hello_world.js" in this_example.extra_head
8079
assert "<h1>Hello ...</h1>" in this_example.body
8180

8281

0 commit comments

Comments
 (0)