Skip to content

Commit 6e31573

Browse files
authored
Merge pull request #31 from pyscript/meg-interest-calculator
Meg interest calculator
2 parents 399bd27 + 8c548f4 commit 6e31573

20 files changed

+506
-136
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ repos:
5353
entry: pyupgrade
5454
language: system
5555
types: [python]
56-
args: [--py37-plus]
56+
args: [--py310-plus]
5757
- id: trailing-whitespace
5858
name: Trim Trailing Whitespace
5959
entry: trailing-whitespace-fixer

CONTRIBUTING.MD

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ We try not to have strong boundaries in what kinds of contributions are accepted
3131
- Adding meta-data
3232

3333
- adding tags to your example will help us organize this repository in a much more meaningful way. Example tags come at the beginning of your main `HTML` file in the form of a comment.
34-
- you're also welcome to add your email or name or other forms of contact information in the header at the beginning of the file.
34+
- you're also welcome to add your email or name or other forms of contact information in the header at the beginning of the file. For reference see the [example](examples/hello_world.html).
3535

36-
TODO Add back in `See the example examples/hello_world.html`
36+
TODO Add back in `See the example examples/hello_world.html`
3737

3838
- Adding docs
3939

@@ -54,7 +54,7 @@ The PyScript Collective also welcomes contributions like blog posts, videos, vid
5454

5555
The contributions in this topic are more similar to what an `awesome-page` would look like.
5656

57-
*If you want to add a new kind of contribution that wasn't laid out on the [README](index) yet, feel free to do so.*
57+
_If you want to add a new kind of contribution that wasn't laid out on the [README](index) yet, feel free to do so._
5858

5959
#### Recommended guidelines for a resource
6060

environment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ channels:
33
- conda-forge
44
- microsoft
55
dependencies:
6-
- python=3.9
6+
- python=3.10
77
- pip=20.2.2
88
- pytest=7
99
- nodejs=16

poetry.lock

Lines changed: 58 additions & 120 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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ typeguard = ">=2.13.3"
5050
xdoctest = { extras = ["colors"], version = ">=0.15.10" }
5151
myst-parser = { version = ">=0.16.1" }
5252
requests = "^2.28.1"
53+
playwright = "^1.27"
5354
pytest-playwright = "^0.3.0"
5455
pytest-asyncio-cooperative = "^0.28.0"
5556
nox-poetry = "^1.0.1"

src/psc/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""Provide a web server to browse the examples."""
22
import contextlib
3+
from collections.abc import Iterator
34
from pathlib import PurePath
45
from typing import AsyncContextManager
5-
from typing import Iterator
66

77
from starlette.applications import Starlette
88
from starlette.requests import Request

src/psc/fixtures.py

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
"""Automate some testing."""
22
from __future__ import annotations
33

4+
import builtins
5+
from collections.abc import Callable
6+
from collections.abc import Generator
7+
from collections.abc import Iterable
48
from dataclasses import dataclass
59
from dataclasses import field
610
from mimetypes import guess_type
7-
from typing import Callable
8-
from typing import Generator
911
from urllib.parse import urlparse
1012

1113
import pytest
@@ -180,3 +182,56 @@ def _route_handler(route: Route) -> None:
180182
# Don't spend 30 seconds on timeout
181183
page.set_default_timeout(12000)
182184
return page
185+
186+
187+
@dataclass
188+
class FakeDocument:
189+
"""Pretend to be a DOM that holds values at id's."""
190+
191+
values: dict[str, str] = field(default_factory=dict)
192+
log: list[str] = field(default_factory=list)
193+
194+
195+
@pytest.fixture
196+
def fake_document() -> Iterable[FakeDocument]:
197+
"""Yield a document that cleans up."""
198+
yield FakeDocument()
199+
200+
201+
@dataclass
202+
class ElementNode:
203+
"""An element node."""
204+
205+
value: str
206+
document: FakeDocument
207+
208+
def write(self, value: str) -> None:
209+
"""Collect anything that is written to the node."""
210+
self.document.log.append(value)
211+
212+
def removeAttribute(self, name: str) -> None: # noqa
213+
"""Pretend to remove an attribute from this node."""
214+
pass
215+
216+
217+
@dataclass
218+
class ElementCallable:
219+
"""A callable that returns an ElementNode."""
220+
221+
document: FakeDocument
222+
223+
def __call__(self, key: str) -> ElementNode:
224+
"""Return an ElementNode."""
225+
value = self.document.values[key]
226+
node = ElementNode(value, self.document)
227+
return node
228+
229+
230+
@pytest.fixture
231+
def fake_element(fake_document: FakeDocument) -> None: # type: ignore [misc]
232+
"""Install the stateful Element into builtins."""
233+
try:
234+
builtins.Element = ElementCallable(fake_document) #type: ignore [attr-defined]
235+
yield
236+
finally:
237+
delattr(builtins, "Element")
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Say Hello."""
2-
output = Element("output")
2+
output = Element("output") #type: ignore
33
output.write("From Python...")

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
<link rel="stylesheet" href="hello_world.css">
88
</head>
99
<body>
10-
<py-config src="../py_config.toml">
11-
paths = ["hello_world.py"]
12-
</py-config>
10+
<py-config src="../py_config.toml"></py-config>
1311
<main>
1412
<h1>Hello Python ...</h1>
1513
<div id="output"></div>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
def interest(*args, **kwargs):
2+
"""Main interest calculation function."""
3+
# Signal that PyScript is alive by setting the ``Calculate``
4+
# button away from disabled.
5+
calculate_button = Element("calc") # noqa
6+
# calculate_button.element.setAttribute("disabled")
7+
8+
# Now get the various inputs
9+
element_principal = Element("principal") # noqa
10+
element_rate = Element("interest_rate") # noqa
11+
element_time = Element("time") # noqa
12+
principal = float(element_principal.value)
13+
rate = float(element_rate.value)
14+
time = float(element_time.value)
15+
output1 = Element("simple_interest") # noqa
16+
output2 = Element("compound_interest") # noqa
17+
res1 = round(principal + (principal * rate * time))
18+
res2 = round(principal * ((1 + rate) ** time))
19+
output1.write(f"simple interest: {res1}")
20+
output2.write(f"compound interest: {res2}")
21+
22+
23+
def setup():
24+
"""When Pyodide starts up, enable the Calculate button."""
25+
calculate_button = Element("calc") # noqa
26+
calculate_button.element.removeAttribute("disabled")
Loading
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>Interest Calculator</title>
5+
<link rel="icon" type="image/png" href="../../../favicon.png">
6+
<link rel="stylesheet" href="styles.css"/>
7+
<script defer src="../../../pyscript/pyscript.js"></script>
8+
</head>
9+
<body>
10+
11+
<section class="calculator-demo">
12+
<section class="calculator-inner">
13+
<div class="flexelement" id="first_div">
14+
<p id="first_p">
15+
Welcome to the "Simple and Compound Interest Calculator!"
16+
<br/>
17+
<strong>"how does it work?"</strong>
18+
to use the "Simple and Compound Interest Calculator", please enter the input data into the form.
19+
after clicking "Calculate", your result will be shown at the bottom of the form.
20+
</p>
21+
22+
<div style="margin-left: 15%;">
23+
<div style="width: 100%;">
24+
<input type="radio" name='expander' id="expander-1">
25+
<label class="expander_label" for="expander-1">Compound Interest Formula &#187;</label>
26+
<img src="compound-interest.png" alt="Compound Interest"
27+
style="height: 200px;"/>
28+
</div>
29+
30+
<div style="margin-top: 25px;">
31+
<input type="radio" name='expander' id="expander-2">
32+
<label class="expander_label" for="expander-2">Simple Interest Formula &#187;</label>
33+
<img src="simple-interest.png" alt="Simple Interest"
34+
style="height: 150px;"/>
35+
</div>
36+
</div>
37+
</div>
38+
39+
40+
<div class="flexelement">
41+
42+
<div id="form">
43+
44+
<div>
45+
<label>Principal
46+
<input id="principal" type="number" step="1" , style="color: black; min-height: 60px;"/></label>
47+
<br/><br>
48+
<label>Interest rate
49+
<input id="interest_rate" type="number" step="0.1" style="color: black; min-height: 60px;"
50+
placeholder="Decimal, f.e. 0.8"/>
51+
</label>
52+
<br>
53+
<br/>
54+
55+
<label>Time
56+
<input id="time" type="number" step="1" min="0" style="color: black; min-height: 60px;"
57+
placeholder="in years"/></label>
58+
<br> <br/>
59+
60+
<button py-click="interest()" id="calc" style="min-height: 60px;" disabled>Calculate</button>
61+
62+
<div style="margin-top: 2%;">
63+
<span id="simple_interest"></span>
64+
<br/>
65+
<span id="compound_interest"></span>
66+
</div>
67+
68+
</div>
69+
70+
</div>
71+
72+
</div>
73+
74+
<py-config src="../py_config.toml"></py-config>
75+
<py-script src="calculator.py"></py-script>
76+
<py-script>
77+
setup()
78+
</py-script>
79+
</section>
80+
</section>
81+
82+
<footer>
83+
<p id="footer_p">
84+
Thank you for using the "Simple and Compound
85+
Interest Calculator!", powered by PyScript!
86+
</p>
87+
</footer>
88+
89+
</body>
90+
91+
</html>
92+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
title: Compound Interest Calculator
3+
subtitle: The classic hello world, but in Python -- in a browser!
4+
---
5+
The *body* description.
Loading

0 commit comments

Comments
 (0)