From 0f986d30d2c6801aa6a947c6c8ee452059a678bb Mon Sep 17 00:00:00 2001 From: pauleveritt Date: Mon, 17 Oct 2022 20:00:53 -0400 Subject: [PATCH 01/11] The loading of the local file wasn't needed. --- src/psc/gallery/examples/hello_world_py/index.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/psc/gallery/examples/hello_world_py/index.html b/src/psc/gallery/examples/hello_world_py/index.html index 8df36eb..ecc14e4 100644 --- a/src/psc/gallery/examples/hello_world_py/index.html +++ b/src/psc/gallery/examples/hello_world_py/index.html @@ -7,9 +7,7 @@ - - paths = ["hello_world.py"] - +

Hello Python ...

From 7b10927941805abf449cf8f6c0fbf9626d216775 Mon Sep 17 00:00:00 2001 From: pauleveritt Date: Sat, 22 Oct 2022 08:29:16 -0400 Subject: [PATCH 02/11] Pushing a flavor with a broken test, where the mock does self.document.values["calc"]. It's a good place to PR. --- poetry.lock | 242 +++++++----------- pyproject.toml | 1 + src/psc/fixtures.py | 49 ++++ .../interest_calculator/calculator.py | 24 ++ .../interest_calculator/compound-interest.png | Bin 0 -> 24982 bytes .../examples/interest_calculator/index.html | 96 +++++++ .../examples/interest_calculator/index.md | 5 + .../interest_calculator/simple-interest.png | Bin 0 -> 4544 bytes .../examples/interest_calculator/styles.css | 165 ++++++++++++ tests/examples/test_interest_calculator.py | 45 ++++ tests/test_fixtures.py | 34 +++ 11 files changed, 513 insertions(+), 148 deletions(-) create mode 100644 src/psc/gallery/examples/interest_calculator/calculator.py create mode 100644 src/psc/gallery/examples/interest_calculator/compound-interest.png create mode 100644 src/psc/gallery/examples/interest_calculator/index.html create mode 100644 src/psc/gallery/examples/interest_calculator/index.md create mode 100644 src/psc/gallery/examples/interest_calculator/simple-interest.png create mode 100644 src/psc/gallery/examples/interest_calculator/styles.css create mode 100644 tests/examples/test_interest_calculator.py diff --git a/poetry.lock b/poetry.lock index 5793f3e..11d6acb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -76,11 +76,11 @@ lxml = ["lxml"] [[package]] name = "black" -version = "22.8.0" +version = "22.10.0" description = "The uncompromising code formatter." category = "dev" optional = false -python-versions = ">=3.6.2" +python-versions = ">=3.7" [package.dependencies] click = ">=8.0.0" @@ -338,7 +338,7 @@ all = ["lxml", "chardet (>=2.2)", "genshi"] [[package]] name = "identify" -version = "2.5.5" +version = "2.5.6" description = "File identification library for Python" category = "dev" optional = false @@ -474,7 +474,7 @@ python-versions = ">=3.7" [[package]] name = "mypy" -version = "0.981" +version = "0.982" description = "Optional static typing for Python" category = "dev" optional = false @@ -604,7 +604,7 @@ test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytes [[package]] name = "playwright" -version = "1.26.1" +version = "1.27.1" description = "A high-level API to automate web browsers" category = "dev" optional = false @@ -613,7 +613,6 @@ python-versions = ">=3.7" [package.dependencies] greenlet = "1.1.3" pyee = "8.1.0" -websockets = "10.1" [[package]] name = "pluggy" @@ -808,7 +807,7 @@ unidecode = ["Unidecode (>=1.1.1)"] [[package]] name = "pytz" -version = "2022.2.1" +version = "2022.5" description = "World timezone definitions, modern and historical" category = "dev" optional = false @@ -816,7 +815,7 @@ python-versions = "*" [[package]] name = "pyupgrade" -version = "2.38.2" +version = "3.1.0" description = "A tool to automatically upgrade syntax for newer versions." category = "dev" optional = false @@ -864,7 +863,7 @@ docutils = ">=0.11,<1.0" [[package]] name = "rich" -version = "12.5.1" +version = "12.6.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" category = "main" optional = false @@ -902,7 +901,7 @@ python-versions = ">=3.5" [[package]] name = "safety" -version = "2.2.0" +version = "2.3.1" description = "Checks installed dependencies for known vulnerabilities and licenses." category = "dev" optional = false @@ -915,6 +914,10 @@ packaging = ">=21.0" requests = "*" "ruamel.yaml" = ">=0.17.21" +[package.extras] +github = ["pygithub (>=1.43.3)", "jinja2 (>=3.1.0)"] +gitlab = ["python-gitlab (>=1.3.0)"] + [[package]] name = "shellingham" version = "1.5.0" @@ -957,7 +960,7 @@ python-versions = ">=3.6" [[package]] name = "sphinx" -version = "5.2.3" +version = "5.3.0" description = "Python documentation generator" category = "dev" optional = false @@ -1124,11 +1127,11 @@ python-versions = "*" [[package]] name = "tokenize-rt" -version = "4.2.1" +version = "5.0.0" description = "A wrapper around the stdlib `tokenize` which roundtrips." category = "dev" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.7" [[package]] name = "toml" @@ -1204,7 +1207,7 @@ python-versions = "*" [[package]] name = "types-requests" -version = "2.28.11" +version = "2.28.11.2" description = "Typing stubs for requests" category = "dev" optional = false @@ -1215,7 +1218,7 @@ types-urllib3 = "<1.27" [[package]] name = "types-urllib3" -version = "1.26.25" +version = "1.26.25.1" description = "Typing stubs for urllib3" category = "dev" optional = false @@ -1223,7 +1226,7 @@ python-versions = "*" [[package]] name = "typing-extensions" -version = "4.3.0" +version = "4.4.0" description = "Backported and Experimental Type Hints for Python 3.7+" category = "dev" optional = false @@ -1282,14 +1285,6 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "websockets" -version = "10.1" -description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -category = "dev" -optional = false -python-versions = ">=3.7" - [[package]] name = "xdoctest" version = "1.1.0" @@ -1317,7 +1312,7 @@ all-strict = ["ipykernel (==6.0.0)", "IPython (==7.23.1)", "jupyter-client (==7. [metadata] lock-version = "1.1" python-versions = "^3.10" -content-hash = "792df2bb736dd532bf9aadb0cf167c47f4a8ea832ea11f0c127f8593e888fcf8" +content-hash = "62c24bf18d40370799e3dd94b3875eeabe1855e53bfe3c6e602618e9478e6f16" [metadata.files] alabaster = [ @@ -1345,29 +1340,27 @@ beautifulsoup4 = [ {file = "beautifulsoup4-4.11.1.tar.gz", hash = "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693"}, ] black = [ - {file = "black-22.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd"}, - {file = "black-22.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27"}, - {file = "black-22.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747"}, - {file = "black-22.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869"}, - {file = "black-22.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90"}, - {file = "black-22.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe"}, - {file = "black-22.8.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342"}, - {file = "black-22.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab"}, - {file = "black-22.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3"}, - {file = "black-22.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e"}, - {file = "black-22.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16"}, - {file = "black-22.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c"}, - {file = "black-22.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5"}, - {file = "black-22.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411"}, - {file = "black-22.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3"}, - {file = "black-22.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875"}, - {file = "black-22.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c"}, - {file = "black-22.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497"}, - {file = "black-22.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c"}, - {file = "black-22.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41"}, - {file = "black-22.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec"}, - {file = "black-22.8.0-py3-none-any.whl", hash = "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4"}, - {file = "black-22.8.0.tar.gz", hash = "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e"}, + {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"}, + {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"}, + {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"}, + {file = "black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"}, + {file = "black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"}, + {file = "black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"}, + {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"}, + {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"}, + {file = "black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"}, + {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"}, + {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"}, + {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"}, + {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"}, + {file = "black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"}, + {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"}, + {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"}, + {file = "black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"}, + {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"}, + {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"}, + {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"}, + {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"}, ] certifi = [ {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, @@ -1551,8 +1544,8 @@ html5lib = [ {file = "html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"}, ] identify = [ - {file = "identify-2.5.5-py2.py3-none-any.whl", hash = "sha256:ef78c0d96098a3b5fe7720be4a97e73f439af7cf088ebf47b620aeaa10fadf97"}, - {file = "identify-2.5.5.tar.gz", hash = "sha256:322a5699daecf7c6fd60e68852f36f2ecbb6a36ff6e6e973e0d2bb6fca203ee6"}, + {file = "identify-2.5.6-py2.py3-none-any.whl", hash = "sha256:b276db7ec52d7e89f5bc4653380e33054ddc803d25875952ad90b0f012cbcdaa"}, + {file = "identify-2.5.6.tar.gz", hash = "sha256:6c32dbd747aa4ceee1df33f25fed0b0f6e0d65721b15bd151307ff7056d50245"}, ] idna = [ {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, @@ -1633,30 +1626,30 @@ mdurl = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] mypy = [ - {file = "mypy-0.981-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4bc460e43b7785f78862dab78674e62ec3cd523485baecfdf81a555ed29ecfa0"}, - {file = "mypy-0.981-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:756fad8b263b3ba39e4e204ee53042671b660c36c9017412b43af210ddee7b08"}, - {file = "mypy-0.981-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a16a0145d6d7d00fbede2da3a3096dcc9ecea091adfa8da48fa6a7b75d35562d"}, - {file = "mypy-0.981-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce65f70b14a21fdac84c294cde75e6dbdabbcff22975335e20827b3b94bdbf49"}, - {file = "mypy-0.981-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e35d764784b42c3e256848fb8ed1d4292c9fc0098413adb28d84974c095b279"}, - {file = "mypy-0.981-cp310-cp310-win_amd64.whl", hash = "sha256:e53773073c864d5f5cec7f3fc72fbbcef65410cde8cc18d4f7242dea60dac52e"}, - {file = "mypy-0.981-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6ee196b1d10b8b215e835f438e06965d7a480f6fe016eddbc285f13955cca659"}, - {file = "mypy-0.981-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ad21d4c9d3673726cf986ea1d0c9fb66905258709550ddf7944c8f885f208be"}, - {file = "mypy-0.981-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d1debb09043e1f5ee845fa1e96d180e89115b30e47c5d3ce53bc967bab53f62d"}, - {file = "mypy-0.981-cp37-cp37m-win_amd64.whl", hash = "sha256:9f362470a3480165c4c6151786b5379351b790d56952005be18bdbdd4c7ce0ae"}, - {file = "mypy-0.981-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c9e0efb95ed6ca1654951bd5ec2f3fa91b295d78bf6527e026529d4aaa1e0c30"}, - {file = "mypy-0.981-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e178eaffc3c5cd211a87965c8c0df6da91ed7d258b5fc72b8e047c3771317ddb"}, - {file = "mypy-0.981-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:06e1eac8d99bd404ed8dd34ca29673c4346e76dd8e612ea507763dccd7e13c7a"}, - {file = "mypy-0.981-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa38f82f53e1e7beb45557ff167c177802ba7b387ad017eab1663d567017c8ee"}, - {file = "mypy-0.981-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:64e1f6af81c003f85f0dfed52db632817dabb51b65c0318ffbf5ff51995bbb08"}, - {file = "mypy-0.981-cp38-cp38-win_amd64.whl", hash = "sha256:e1acf62a8c4f7c092462c738aa2c2489e275ed386320c10b2e9bff31f6f7e8d6"}, - {file = "mypy-0.981-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b6ede64e52257931315826fdbfc6ea878d89a965580d1a65638ef77cb551f56d"}, - {file = "mypy-0.981-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eb3978b191b9fa0488524bb4ffedf2c573340e8c2b4206fc191d44c7093abfb7"}, - {file = "mypy-0.981-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77f8fcf7b4b3cc0c74fb33ae54a4cd00bb854d65645c48beccf65fa10b17882c"}, - {file = "mypy-0.981-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f64d2ce043a209a297df322eb4054dfbaa9de9e8738291706eaafda81ab2b362"}, - {file = "mypy-0.981-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2ee3dbc53d4df7e6e3b1c68ac6a971d3a4fb2852bf10a05fda228721dd44fae1"}, - {file = "mypy-0.981-cp39-cp39-win_amd64.whl", hash = "sha256:8e8e49aa9cc23aa4c926dc200ce32959d3501c4905147a66ce032f05cb5ecb92"}, - {file = "mypy-0.981-py3-none-any.whl", hash = "sha256:794f385653e2b749387a42afb1e14c2135e18daeb027e0d97162e4b7031210f8"}, - {file = "mypy-0.981.tar.gz", hash = "sha256:ad77c13037d3402fbeffda07d51e3f228ba078d1c7096a73759c9419ea031bf4"}, + {file = "mypy-0.982-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5085e6f442003fa915aeb0a46d4da58128da69325d8213b4b35cc7054090aed5"}, + {file = "mypy-0.982-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:41fd1cf9bc0e1c19b9af13a6580ccb66c381a5ee2cf63ee5ebab747a4badeba3"}, + {file = "mypy-0.982-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f793e3dd95e166b66d50e7b63e69e58e88643d80a3dcc3bcd81368e0478b089c"}, + {file = "mypy-0.982-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86ebe67adf4d021b28c3f547da6aa2cce660b57f0432617af2cca932d4d378a6"}, + {file = "mypy-0.982-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:175f292f649a3af7082fe36620369ffc4661a71005aa9f8297ea473df5772046"}, + {file = "mypy-0.982-cp310-cp310-win_amd64.whl", hash = "sha256:8ee8c2472e96beb1045e9081de8e92f295b89ac10c4109afdf3a23ad6e644f3e"}, + {file = "mypy-0.982-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58f27ebafe726a8e5ccb58d896451dd9a662a511a3188ff6a8a6a919142ecc20"}, + {file = "mypy-0.982-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6af646bd46f10d53834a8e8983e130e47d8ab2d4b7a97363e35b24e1d588947"}, + {file = "mypy-0.982-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7aeaa763c7ab86d5b66ff27f68493d672e44c8099af636d433a7f3fa5596d40"}, + {file = "mypy-0.982-cp37-cp37m-win_amd64.whl", hash = "sha256:724d36be56444f569c20a629d1d4ee0cb0ad666078d59bb84f8f887952511ca1"}, + {file = "mypy-0.982-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14d53cdd4cf93765aa747a7399f0961a365bcddf7855d9cef6306fa41de01c24"}, + {file = "mypy-0.982-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:26ae64555d480ad4b32a267d10cab7aec92ff44de35a7cd95b2b7cb8e64ebe3e"}, + {file = "mypy-0.982-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6389af3e204975d6658de4fb8ac16f58c14e1bacc6142fee86d1b5b26aa52bda"}, + {file = "mypy-0.982-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b35ce03a289480d6544aac85fa3674f493f323d80ea7226410ed065cd46f206"}, + {file = "mypy-0.982-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c6e564f035d25c99fd2b863e13049744d96bd1947e3d3d2f16f5828864506763"}, + {file = "mypy-0.982-cp38-cp38-win_amd64.whl", hash = "sha256:cebca7fd333f90b61b3ef7f217ff75ce2e287482206ef4a8b18f32b49927b1a2"}, + {file = "mypy-0.982-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a705a93670c8b74769496280d2fe6cd59961506c64f329bb179970ff1d24f9f8"}, + {file = "mypy-0.982-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75838c649290d83a2b83a88288c1eb60fe7a05b36d46cbea9d22efc790002146"}, + {file = "mypy-0.982-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:91781eff1f3f2607519c8b0e8518aad8498af1419e8442d5d0afb108059881fc"}, + {file = "mypy-0.982-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaa97b9ddd1dd9901a22a879491dbb951b5dec75c3b90032e2baa7336777363b"}, + {file = "mypy-0.982-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a692a8e7d07abe5f4b2dd32d731812a0175626a90a223d4b58f10f458747dd8a"}, + {file = "mypy-0.982-cp39-cp39-win_amd64.whl", hash = "sha256:eb7a068e503be3543c4bd329c994103874fa543c1727ba5288393c21d912d795"}, + {file = "mypy-0.982-py3-none-any.whl", hash = "sha256:1021c241e8b6e1ca5a47e4d52601274ac078a89845cfde66c6d5f769819ffa1d"}, + {file = "mypy-0.982.tar.gz", hash = "sha256:85f7a343542dc8b1ed0a888cdd34dca56462654ef23aa673907305b260b3d746"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, @@ -1692,13 +1685,13 @@ platformdirs = [ {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, ] playwright = [ - {file = "playwright-1.26.1-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:eabf81e932076be5afe8f198c13cde913db319ccb07a9c16ea13bd0d372b40b2"}, - {file = "playwright-1.26.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:ecd2d47a671d40f2c9f2fa70dec5c4e8f341194e7450e1483c787e02eecb6f61"}, - {file = "playwright-1.26.1-py3-none-macosx_11_0_universal2.whl", hash = "sha256:a04bb9f2b25ad00077c7816e51b2cc3edc9b5ae7ed864ab1efbc3037a16db868"}, - {file = "playwright-1.26.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:c3cc87fc738d7c7668d8e3a8086fca2c6f981d31e560cee5f89415d17160f7e5"}, - {file = "playwright-1.26.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b3a58cd903d21bf71b0361b8f1379bb9de8046ecf5a866f5d13bd815100099"}, - {file = "playwright-1.26.1-py3-none-win32.whl", hash = "sha256:1b06a0cd1d0c4ded1c5412129f9207d2589aa5ac86645cfa1a89690ef610228b"}, - {file = "playwright-1.26.1-py3-none-win_amd64.whl", hash = "sha256:9dfbb664a0d3865ec3db4cd636dab755c7bf5eeadcaf1d6abe9ab8c9c26c431f"}, + {file = "playwright-1.27.1-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:3b584bc23bfacfbfb91777663d2b68891d8a16c5c2228b4702c6a7d29c0ac364"}, + {file = "playwright-1.27.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:771d690aaa933bb40f60abbe7935979cfa9a5bec498bbc57cd87baf038348d2b"}, + {file = "playwright-1.27.1-py3-none-macosx_11_0_universal2.whl", hash = "sha256:db89faac3c535e289f8463b184ffd4523d97b5e959d97bae330d29522c5bfb9d"}, + {file = "playwright-1.27.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:5e7be8dc52b9e3340a08fd15b7d3cdd635efd51c0c62bd1edba55f0bfeea293c"}, + {file = "playwright-1.27.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c32bfbbb6e6529f7f7176551eda7061e9f205e19259052ef663dcae7109c1f12"}, + {file = "playwright-1.27.1-py3-none-win32.whl", hash = "sha256:464f3a0ea48aeb42adbdada88a91fd36d4311ae7020d2ab58f410c4c92e0ddfe"}, + {file = "playwright-1.27.1-py3-none-win_amd64.whl", hash = "sha256:fc8ce323cf116e27902f327cee1cba6fc0c5400e9281df8e53d3355de88336ba"}, ] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, @@ -1762,12 +1755,12 @@ python-slugify = [ {file = "python_slugify-6.1.2-py2.py3-none-any.whl", hash = "sha256:7b2c274c308b62f4269a9ba701aa69a797e9bca41aeee5b3a9e79e36b6656927"}, ] pytz = [ - {file = "pytz-2022.2.1-py2.py3-none-any.whl", hash = "sha256:220f481bdafa09c3955dfbdddb7b57780e9a94f5127e35456a48589b9e0c0197"}, - {file = "pytz-2022.2.1.tar.gz", hash = "sha256:cea221417204f2d1a2aa03ddae3e867921971d0d76f14d87abb4414415bbdcf5"}, + {file = "pytz-2022.5-py2.py3-none-any.whl", hash = "sha256:335ab46900b1465e714b4fda4963d87363264eb662aab5e65da039c25f1f5b22"}, + {file = "pytz-2022.5.tar.gz", hash = "sha256:c4d88f472f54d615e9cd582a5004d1e5f624854a6a27a6211591c251f22a6914"}, ] pyupgrade = [ - {file = "pyupgrade-2.38.2-py2.py3-none-any.whl", hash = "sha256:41bb9a9fd48fe57163b0dacffff433d6d5a63a0f7c2402918917b5f1a533342b"}, - {file = "pyupgrade-2.38.2.tar.gz", hash = "sha256:a5d778c9de0b53975c6a9eac2d0df5adfad244a9f7d7993d8a114223ebbda367"}, + {file = "pyupgrade-3.1.0-py2.py3-none-any.whl", hash = "sha256:77c6101a710be3e24804891e43388cedbee617258e93b09c8c5e58de08617758"}, + {file = "pyupgrade-3.1.0.tar.gz", hash = "sha256:7a8d393d85e15e0e2753e90b7b2e173b9d29dfd71e61f93d93e985b242627ed3"}, ] pyyaml = [ {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, @@ -1809,8 +1802,8 @@ restructuredtext-lint = [ {file = "restructuredtext_lint-1.4.0.tar.gz", hash = "sha256:1b235c0c922341ab6c530390892eb9e92f90b9b75046063e047cacfb0f050c45"}, ] rich = [ - {file = "rich-12.5.1-py3-none-any.whl", hash = "sha256:2eb4e6894cde1e017976d2975ac210ef515d7548bc595ba20e195fb9628acdeb"}, - {file = "rich-12.5.1.tar.gz", hash = "sha256:63a5c5ce3673d3d5fbbf23cd87e11ab84b6b451436f1b7f19ec54b6bc36ed7ca"}, + {file = "rich-12.6.0-py3-none-any.whl", hash = "sha256:a4eb26484f2c82589bd9a17c73d32a010b1e29d89f1604cd9bf3a2097b81bb5e"}, + {file = "rich-12.6.0.tar.gz", hash = "sha256:ba3a3775974105c221d31141f2c116f4fd65c5ceb0698657a11e9f295ec93fd0"}, ] "ruamel.yaml" = [ {file = "ruamel.yaml-0.17.21-py3-none-any.whl", hash = "sha256:742b35d3d665023981bd6d16b3d24248ce5df75fdb4e2924e93a05c1f8b61ca7"}, @@ -1844,8 +1837,8 @@ rich = [ {file = "ruamel.yaml.clib-0.2.6.tar.gz", hash = "sha256:4ff604ce439abb20794f05613c374759ce10e3595d1867764dd1ae675b85acbd"}, ] safety = [ - {file = "safety-2.2.0-py3-none-any.whl", hash = "sha256:b1a0f4c34fb41c502a7a5c54774c18376da382bc9d866ee26b39b2c747c0de40"}, - {file = "safety-2.2.0.tar.gz", hash = "sha256:6745de12acbd60a58001fe66cb540355187d7b991b30104d9ef14ff4e4826073"}, + {file = "safety-2.3.1-py3-none-any.whl", hash = "sha256:8f098d12b607db2756886280e85c28ece8db1bba4f45fc5f981f4663217bd619"}, + {file = "safety-2.3.1.tar.gz", hash = "sha256:6e6fcb7d4e8321098cf289f59b65051cafd3467f089c6e57c9f894ae32c23b71"}, ] shellingham = [ {file = "shellingham-1.5.0-py2.py3-none-any.whl", hash = "sha256:a8f02ba61b69baaa13facdba62908ca8690a94b8119b69f5ec5873ea85f7391b"}, @@ -1868,8 +1861,8 @@ soupsieve = [ {file = "soupsieve-2.3.2.post1.tar.gz", hash = "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d"}, ] sphinx = [ - {file = "Sphinx-5.2.3.tar.gz", hash = "sha256:5b10cb1022dac8c035f75767799c39217a05fc0fe2d6fe5597560d38e44f0363"}, - {file = "sphinx-5.2.3-py3-none-any.whl", hash = "sha256:7abf6fabd7b58d0727b7317d5e2650ef68765bbe0ccb63c8795fa8683477eaa2"}, + {file = "Sphinx-5.3.0.tar.gz", hash = "sha256:51026de0a9ff9fc13c05d74913ad66047e104f56a129ff73e174eb5c3ee794b5"}, + {file = "sphinx-5.3.0-py3-none-any.whl", hash = "sha256:060ca5c9f7ba57a08a1219e547b269fadf125ae25b06b9fa7f66768efb652d6d"}, ] sphinx-autobuild = [ {file = "sphinx-autobuild-2021.3.14.tar.gz", hash = "sha256:de1ca3b66e271d2b5b5140c35034c89e47f263f2cd5db302c9217065f7443f05"}, @@ -1913,8 +1906,8 @@ text-unidecode = [ {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, ] tokenize-rt = [ - {file = "tokenize_rt-4.2.1-py2.py3-none-any.whl", hash = "sha256:08a27fa032a81cf45e8858d0ac706004fcd523e8463415ddf1442be38e204ea8"}, - {file = "tokenize_rt-4.2.1.tar.gz", hash = "sha256:0d4f69026fed520f8a1e0103aa36c406ef4661417f20ca643f913e33531b3b94"}, + {file = "tokenize_rt-5.0.0-py2.py3-none-any.whl", hash = "sha256:c67772c662c6b3dc65edf66808577968fb10badfc2042e3027196bed4daf9e5a"}, + {file = "tokenize_rt-5.0.0.tar.gz", hash = "sha256:3160bc0c3e8491312d0485171dea861fc160a240f5f5766b72a1165408d10740"}, ] toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, @@ -1942,14 +1935,17 @@ types-beautifulsoup4 = [ {file = "types_beautifulsoup4-4.11.6-py3-none-any.whl", hash = "sha256:ac9dd1383481201ea07f27c5a43e7b1ee71caf9c720b7ae951db15d60d126e80"}, ] types-requests = [ - {file = "types-requests-2.28.11.tar.gz", hash = "sha256:7ee827eb8ce611b02b5117cfec5da6455365b6a575f5e3ff19f655ba603e6b4e"}, - {file = "types_requests-2.28.11-py3-none-any.whl", hash = "sha256:af5f55e803cabcfb836dad752bd6d8a0fc8ef1cd84243061c0e27dee04ccf4fd"}, + {file = "types-requests-2.28.11.2.tar.gz", hash = "sha256:fdcd7bd148139fb8eef72cf4a41ac7273872cad9e6ada14b11ff5dfdeee60ed3"}, + {file = "types_requests-2.28.11.2-py3-none-any.whl", hash = "sha256:14941f8023a80b16441b3b46caffcbfce5265fd14555844d6029697824b5a2ef"}, ] types-urllib3 = [ - {file = "types-urllib3-1.26.25.tar.gz", hash = "sha256:5aef0e663724eef924afa8b320b62ffef2c1736c1fa6caecfc9bc6c8ae2c3def"}, - {file = "types_urllib3-1.26.25-py3-none-any.whl", hash = "sha256:c1d78cef7bd581e162e46c20a57b2e1aa6ebecdcf01fd0713bb90978ff3e3427"}, + {file = "types-urllib3-1.26.25.1.tar.gz", hash = "sha256:a948584944b2412c9a74b9cf64f6c48caf8652cb88b38361316f6d15d8a184cd"}, + {file = "types_urllib3-1.26.25.1-py3-none-any.whl", hash = "sha256:f6422596cc9ee5fdf68f9d547f541096a20c2dcfd587e37c804c9ea720bf5cb2"}, +] +typing-extensions = [ + {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, + {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, ] -typing-extensions = [] urllib3 = [ {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, @@ -1966,56 +1962,6 @@ webencodings = [ {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, ] -websockets = [ - {file = "websockets-10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:38db6e2163b021642d0a43200ee2dec8f4980bdbda96db54fde72b283b54cbfc"}, - {file = "websockets-10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e1b60fd297adb9fc78375778a5220da7f07bf54d2a33ac781319650413fc6a60"}, - {file = "websockets-10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3477146d1f87ead8df0f27e8960249f5248dceb7c2741e8bbec9aa5338d0c053"}, - {file = "websockets-10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb01ea7b5f52e7125bdc3c5807aeaa2d08a0553979cf2d96a8b7803ea33e15e7"}, - {file = "websockets-10.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9fd62c6dc83d5d35fb6a84ff82ec69df8f4657fff05f9cd6c7d9bec0dd57f0f6"}, - {file = "websockets-10.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3bbf080f3892ba1dc8838786ec02899516a9d227abe14a80ef6fd17d4fb57127"}, - {file = "websockets-10.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5560558b0dace8312c46aa8915da977db02738ac8ecffbc61acfbfe103e10155"}, - {file = "websockets-10.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:667c41351a6d8a34b53857ceb8343a45c85d438ee4fd835c279591db8aeb85be"}, - {file = "websockets-10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:468f0031fdbf4d643f89403a66383247eb82803430b14fa27ce2d44d2662ca37"}, - {file = "websockets-10.1-cp310-cp310-win32.whl", hash = "sha256:d0d81b46a5c87d443e40ce2272436da8e6092aa91f5fbeb60d1be9f11eff5b4c"}, - {file = "websockets-10.1-cp310-cp310-win_amd64.whl", hash = "sha256:b68b6caecb9a0c6db537aa79750d1b592a841e4f1a380c6196091e65b2ad35f9"}, - {file = "websockets-10.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a249139abc62ef333e9e85064c27fefb113b16ffc5686cefc315bdaef3eefbc8"}, - {file = "websockets-10.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8877861e3dee38c8d302eee0d5dbefa6663de3b46dc6a888f70cd7e82562d1f7"}, - {file = "websockets-10.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e3872ae57acd4306ecf937d36177854e218e999af410a05c17168cd99676c512"}, - {file = "websockets-10.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b66e6d514f12c28d7a2d80bb2a48ef223342e99c449782d9831b0d29a9e88a17"}, - {file = "websockets-10.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9f304a22ece735a3da8a51309bc2c010e23961a8f675fae46fdf62541ed62123"}, - {file = "websockets-10.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:189ed478395967d6a98bb293abf04e8815349e17456a0a15511f1088b6cb26e4"}, - {file = "websockets-10.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:08a42856158307e231b199671c4fce52df5786dd3d703f36b5d8ac76b206c485"}, - {file = "websockets-10.1-cp37-cp37m-win32.whl", hash = "sha256:3ef6f73854cded34e78390dbdf40dfdcf0b89b55c0e282468ef92646fce8d13a"}, - {file = "websockets-10.1-cp37-cp37m-win_amd64.whl", hash = "sha256:89e985d40d407545d5f5e2e58e1fdf19a22bd2d8cd54d20a882e29f97e930a0a"}, - {file = "websockets-10.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:002071169d2e44ce8eb9e5ebac9fbce142ba4b5146eef1cfb16b177a27662657"}, - {file = "websockets-10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cfae282c2aa7f0c4be45df65c248481f3509f8c40ca8b15ed96c35668ae0ff69"}, - {file = "websockets-10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:97b4b68a2ddaf5c4707ae79c110bfd874c5be3c6ac49261160fb243fa45d8bbb"}, - {file = "websockets-10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c9407719f42cb77049975410490c58a705da6af541adb64716573e550e5c9db"}, - {file = "websockets-10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1d858fb31e5ac992a2cdf17e874c95f8a5b1e917e1fb6b45ad85da30734b223f"}, - {file = "websockets-10.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7bdd3d26315db0a9cf8a0af30ca95e0aa342eda9c1377b722e71ccd86bc5d1dd"}, - {file = "websockets-10.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e259be0863770cb91b1a6ccf6907f1ac2f07eff0b7f01c249ed751865a70cb0d"}, - {file = "websockets-10.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6b014875fae19577a392372075e937ebfebf53fd57f613df07b35ab210f31534"}, - {file = "websockets-10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:98de71f86bdb29430fd7ba9997f47a6b10866800e3ea577598a786a785701bb0"}, - {file = "websockets-10.1-cp38-cp38-win32.whl", hash = "sha256:3a02ab91d84d9056a9ee833c254895421a6333d7ae7fff94b5c68e4fa8095519"}, - {file = "websockets-10.1-cp38-cp38-win_amd64.whl", hash = "sha256:7d6673b2753f9c5377868a53445d0c321ef41ff3c8e3b6d57868e72054bfce5f"}, - {file = "websockets-10.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ddab2dc69ee5ae27c74dbfe9d7bb6fee260826c136dca257faa1a41d1db61a89"}, - {file = "websockets-10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:14e9cf68a08d1a5d42109549201aefba473b1d925d233ae19035c876dd845da9"}, - {file = "websockets-10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e4819c6fb4f336fd5388372cb556b1f3a165f3f68e66913d1a2fc1de55dc6f58"}, - {file = "websockets-10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05e7f098c76b0a4743716590bb8f9706de19f1ef5148d61d0cf76495ec3edb9c"}, - {file = "websockets-10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5bb6256de5a4fb1d42b3747b4e2268706c92965d75d0425be97186615bf2f24f"}, - {file = "websockets-10.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:888a5fa2a677e0c2b944f9826c756475980f1b276b6302e606f5c4ff5635be9e"}, - {file = "websockets-10.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6fdec1a0b3e5630c58e3d8704d2011c678929fce90b40908c97dfc47de8dca72"}, - {file = "websockets-10.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:531d8eb013a9bc6b3ad101588182aa9b6dd994b190c56df07f0d84a02b85d530"}, - {file = "websockets-10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0d93b7cadc761347d98da12ec1930b5c71b2096f1ceed213973e3cda23fead9c"}, - {file = "websockets-10.1-cp39-cp39-win32.whl", hash = "sha256:d9b245db5a7e64c95816e27d72830e51411c4609c05673d1ae81eb5d23b0be54"}, - {file = "websockets-10.1-cp39-cp39-win_amd64.whl", hash = "sha256:882c0b8bdff3bf1bd7f024ce17c6b8006042ec4cceba95cf15df57e57efa471c"}, - {file = "websockets-10.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:10edd9d7d3581cfb9ff544ac09fc98cab7ee8f26778a5a8b2d5fd4b0684c5ba5"}, - {file = "websockets-10.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa83174390c0ff4fc1304fbe24393843ac7a08fdd59295759c4b439e06b1536"}, - {file = "websockets-10.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:483edee5abed738a0b6a908025be47f33634c2ad8e737edd03ffa895bd600909"}, - {file = "websockets-10.1-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:816ae7dac2c6522cfa620947ead0ca95ac654916eebf515c94d7c28de5601a6e"}, - {file = "websockets-10.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1dafe98698ece09b8ccba81b910643ff37198e43521d977be76caf37709cf62b"}, - {file = "websockets-10.1.tar.gz", hash = "sha256:181d2b25de5a437b36aefedaf006ecb6fa3aa1328ec0236cdde15f32f9d3ff6d"}, -] xdoctest = [ {file = "xdoctest-1.1.0-py3-none-any.whl", hash = "sha256:da330c4dacee51f3c785820bc743188fb6f7c64c5fa1c54bff8836b3cf23d69b"}, {file = "xdoctest-1.1.0.tar.gz", hash = "sha256:0fd4fad7932f0a2f082dfdfb857dd6ca41603757586c39b1e5b4d333fc389f8a"}, diff --git a/pyproject.toml b/pyproject.toml index eb1504c..9013cf4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ typeguard = ">=2.13.3" xdoctest = { extras = ["colors"], version = ">=0.15.10" } myst-parser = { version = ">=0.16.1" } requests = "^2.28.1" +playwright = "^1.27" pytest-playwright = "^0.3.0" pytest-asyncio-cooperative = "^0.28.0" nox-poetry = "^1.0.1" diff --git a/src/psc/fixtures.py b/src/psc/fixtures.py index 73410e0..1340e80 100644 --- a/src/psc/fixtures.py +++ b/src/psc/fixtures.py @@ -1,6 +1,7 @@ """Automate some testing.""" from __future__ import annotations +import builtins from dataclasses import dataclass from dataclasses import field from mimetypes import guess_type @@ -180,3 +181,51 @@ def _route_handler(route: Route) -> None: # Don't spend 30 seconds on timeout page.set_default_timeout(12000) return page + + +@dataclass +class FakeDocument: + """Pretend to be a DOM that holds values at id's.""" + + values: dict[str, str] = field(default_factory=dict) + log: list[str] = field(default_factory=list) + + +@pytest.fixture +def fake_document() -> FakeDocument: + """Yield a document that cleans up.""" + yield FakeDocument() + + +@dataclass +class ElementNode: + value: str + document: FakeDocument + + def write(self, value: str) -> None: + """Collect anything that is written to the node.""" + self.document.log.append(value) + + def removeAttribute(self, name) -> None: + """Pretend to remove an attribute from this node.""" + pass + + +@dataclass +class ElementCallable: + document: FakeDocument + + def __call__(self, key: str) -> ElementNode: + value = self.document.values[key] + node = ElementNode(value, self.document) + return node + + +@pytest.fixture +def fake_element(fake_document) -> None: + """Install the stateful Element into builtins.""" + try: + builtins.Element = ElementCallable(fake_document) + yield + finally: + delattr(builtins, "Element") diff --git a/src/psc/gallery/examples/interest_calculator/calculator.py b/src/psc/gallery/examples/interest_calculator/calculator.py new file mode 100644 index 0000000..ae962c9 --- /dev/null +++ b/src/psc/gallery/examples/interest_calculator/calculator.py @@ -0,0 +1,24 @@ +def interest(*args, **kwargs): + # Signal that PyScript is alive by setting the ``Calculate`` + # button away from disabled. + ec = Element("calc") # noqa + + # Now get the various inputs + ep = Element("principal") # noqa + er = Element("interest_rate") # noqa + et = Element("time") # noqa + p = float(ep.value) + r = float(er.value) + t = float(et.value) + output1 = Element("simple_interest") # noqa + output2 = Element("compound_interest") # noqa + res1 = round(p + (p * r * t)) + res2 = round(p * ((1 + r) ** t)) + output1.write("simple interest: " + str(res1)) + output2.write("compound interest: " + str(res2)) + + +def setup(): + """When Pyodide starts up, enable the Calculate button.""" + ec = Element("calc") # noqa + ec.element.removeAttribute("disabled") diff --git a/src/psc/gallery/examples/interest_calculator/compound-interest.png b/src/psc/gallery/examples/interest_calculator/compound-interest.png new file mode 100644 index 0000000000000000000000000000000000000000..2a1c3457cca7f6801ea2dbec272f4a2bc9e3ed67 GIT binary patch literal 24982 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 SEdUKM0xflYwQ`lmul^5u0HM|Z literal 0 HcmV?d00001 diff --git a/src/psc/gallery/examples/interest_calculator/index.html b/src/psc/gallery/examples/interest_calculator/index.html new file mode 100644 index 0000000..e78c291 --- /dev/null +++ b/src/psc/gallery/examples/interest_calculator/index.html @@ -0,0 +1,96 @@ + + + + + + Interest Calculator + + + + + + +
+

Welcome to the Compound Calculator!

+
+ +
+ +
+

+ Welcome to the "Simple and Compound Interest Calculator!" +
+ "how does it work?" + to use the "Simple and Compound Interest Calculator", please enter the input data into the form. + after clicking "Calculate", your result will be shown at the bottom of the form. +

+ +
+
+ + + Compound Interest +
+ +
+ + + Simple Interest +
+
+
+ + +
+ +
+ +
+ +

+ +
+
+ + +

+ + + +
+ +
+ +
+ +
+ +
+ +
+ + + + + setup() + +
+ +
+ +
+ + + + diff --git a/src/psc/gallery/examples/interest_calculator/index.md b/src/psc/gallery/examples/interest_calculator/index.md new file mode 100644 index 0000000..35b0a54 --- /dev/null +++ b/src/psc/gallery/examples/interest_calculator/index.md @@ -0,0 +1,5 @@ +--- +title: Compound Interest Calculator +subtitle: The classic hello world, but in Python -- in a browser! +--- +The *body* description. diff --git a/src/psc/gallery/examples/interest_calculator/simple-interest.png b/src/psc/gallery/examples/interest_calculator/simple-interest.png new file mode 100644 index 0000000000000000000000000000000000000000..abba5f6dd25e1887048426e01a4554c4c2e694ea GIT binary patch literal 4544 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 None: + """Ensure the loaded interest function works correctly.""" + from psc.gallery.examples.interest_calculator.calculator import interest + + fake_document.values["principal"] = "100" + fake_document.values["interest_rate"] = "0.1" + fake_document.values["time"] = "10" + fake_document.values["simple_interest"] = "0.1" + fake_document.values["compound_interest"] = "0.1" + interest() + assert fake_document.log[0] == "simple interest: 200" + assert fake_document.log[1] == "compound interest: 259" + + +def test_interest_calculator(client_page: PageT) -> None: + """Test the static HTML for Antigravity.""" + soup = client_page("/gallery/examples/interest_calculator/") + title = soup.select_one("title") + assert title and title.text == "Compound Interest Calculator | PyScript Collective" + + +@pytest.mark.full +def test_interest_calculator_full(fake_page: Page) -> None: + """Use Playwright to do a test on Antigravity.""" + # Use `PWDEBUG=1` to run "head-ful" in Playwright test app + url = "http://fake/gallery/examples/interest_calculator/index.html" + fake_page.goto(url) + assert fake_page.title() == "Interest Calculator" + button = fake_page.wait_for_selector("#calc:enabled") + fake_page.get_by_text("Principal").fill("1000") + fake_page.get_by_text("Interest rate").fill("0.1") + fake_page.get_by_text("Time").fill("10") + si = fake_page.query_selector("#simple_interest") + ci = fake_page.query_selector("#compound_interest") + button.click() + assert si.text_content() == "simple interest: 2000" + assert ci.text_content() == "compound interest: 2594" diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index 0a43b53..f011923 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -133,3 +133,37 @@ def test_route_handler_fake_bad_path() -> None: cast(Route, dummy_route), ) assert dummy_route.status == "404" + + +def test_fake_element_not_installed() -> None: + """We don't request the fixture so it isn't available.""" + with pytest.raises(NameError): + Element # noqa + + +def test_fake_element_installed(fake_element) -> None: + """Element is available as ``fake_element`` installed it.""" + Element # noqa + + +def test_fake_element_find_element(fake_document, fake_element) -> None: + """The Element can get a value from the fake document.""" + fake_document.values["btn1"] = "value1" + button = Element("btn1") # noqa + assert button.value == "value1" + + +def test_fake_element_write(fake_document, fake_element) -> None: + """The Element can write a value that is captured.""" + fake_document.values["btn1"] = "value1" + button = Element("btn1") # noqa + button.write("Some Value") + assert fake_document.log[0] == "Some Value" + + +def test_fake_element_remove_attribute(fake_document, fake_element) -> None: + """The Element can pretend to remove an attribute.""" + fake_document.values["btn1"] = "value1" + button = Element("btn1") # noqa + button.removeAttribute("disabled") + assert fake_document.log == [] From 5a4bf0e6c5eb0ce2dadfb324578fc0946b445e79 Mon Sep 17 00:00:00 2001 From: Paul Everitt Date: Tue, 1 Nov 2022 09:27:10 -0400 Subject: [PATCH 03/11] PyCharm -> PyScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I do this all the time. Ugh. Co-authored-by: Fábio Rosado --- src/psc/pages/contributing.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psc/pages/contributing.html b/src/psc/pages/contributing.html index 6666ebf..79043a9 100644 --- a/src/psc/pages/contributing.html +++ b/src/psc/pages/contributing.html @@ -1,7 +1,7 @@ Contributing - +
From 14415f88ade69c13349b0b4b63e38df0260d96a2 Mon Sep 17 00:00:00 2001 From: FabioRosado Date: Wed, 2 Nov 2022 19:54:05 +0000 Subject: [PATCH 04/11] Small styling tweaks and contributing docs --- CONTRIBUTING.MD | 6 +++--- src/psc/gallery/examples/interest_calculator/index.html | 6 +++--- src/psc/gallery/examples/interest_calculator/styles.css | 5 +++++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.MD b/CONTRIBUTING.MD index 9cac9f1..8bc2a21 100644 --- a/CONTRIBUTING.MD +++ b/CONTRIBUTING.MD @@ -31,9 +31,9 @@ We try not to have strong boundaries in what kinds of contributions are accepted - Adding meta-data - 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. - - 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. + - 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). -TODO Add back in `See the example examples/hello_world.html` +TODO Add back in `See the example examples/hello_world.html` - Adding docs @@ -54,7 +54,7 @@ The PyScript Collective also welcomes contributions like blog posts, videos, vid The contributions in this topic are more similar to what an `awesome-page` would look like. -*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.* +_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._ #### Recommended guidelines for a resource diff --git a/src/psc/gallery/examples/interest_calculator/index.html b/src/psc/gallery/examples/interest_calculator/index.html index e78c291..530fd24 100644 --- a/src/psc/gallery/examples/interest_calculator/index.html +++ b/src/psc/gallery/examples/interest_calculator/index.html @@ -14,7 +14,7 @@

Welcome to the Compound Calculator!

-
+

@@ -45,7 +45,7 @@

Welcome to the Compound Calculator!

-
+
- Toroid Example + Hello World
From ed6c5382dbcf387b6658498468c082d6fe84fdb8 Mon Sep 17 00:00:00 2001 From: FabioRosado Date: Wed, 2 Nov 2022 20:12:50 +0000 Subject: [PATCH 06/11] Update var names and set button as disabled by default --- .../interest_calculator/calculator.py | 23 ++++++++++--------- .../examples/interest_calculator/styles.css | 4 ++++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/psc/gallery/examples/interest_calculator/calculator.py b/src/psc/gallery/examples/interest_calculator/calculator.py index ae962c9..c055562 100644 --- a/src/psc/gallery/examples/interest_calculator/calculator.py +++ b/src/psc/gallery/examples/interest_calculator/calculator.py @@ -1,24 +1,25 @@ def interest(*args, **kwargs): # Signal that PyScript is alive by setting the ``Calculate`` # button away from disabled. - ec = Element("calc") # noqa + calculate_button = Element("calc") # noqa + calculate_button.element.setAttribute("disabled") # Now get the various inputs - ep = Element("principal") # noqa - er = Element("interest_rate") # noqa - et = Element("time") # noqa - p = float(ep.value) - r = float(er.value) - t = float(et.value) + element_principal = Element("principal") # noqa + element_rate = Element("interest_rate") # noqa + element_time = Element("time") # noqa + principal = float(element_principal.value) + rate = float(element_rate.value) + time = float(element_time.value) output1 = Element("simple_interest") # noqa output2 = Element("compound_interest") # noqa - res1 = round(p + (p * r * t)) - res2 = round(p * ((1 + r) ** t)) + res1 = round(principal + (principal * rate * time)) + res2 = round(principal * ((1 + rate) ** time)) output1.write("simple interest: " + str(res1)) output2.write("compound interest: " + str(res2)) def setup(): """When Pyodide starts up, enable the Calculate button.""" - ec = Element("calc") # noqa - ec.element.removeAttribute("disabled") + calculate_button = Element("calc") # noqa + calculate_button.element.removeAttribute("disabled") diff --git a/src/psc/gallery/examples/interest_calculator/styles.css b/src/psc/gallery/examples/interest_calculator/styles.css index c2752f8..b76ae9d 100644 --- a/src/psc/gallery/examples/interest_calculator/styles.css +++ b/src/psc/gallery/examples/interest_calculator/styles.css @@ -63,6 +63,10 @@ img { border: 0; } +#form button:disabled, #form button[disabled] { + background-color: #0097e863; +} + header { height: 100px; } From f96b6fd1b9b5c445ac3bfbc73bf7f1b7554725f7 Mon Sep 17 00:00:00 2001 From: FabioRosado Date: Wed, 2 Nov 2022 20:20:49 +0000 Subject: [PATCH 07/11] More tweaks to interest calculator --- src/psc/gallery/examples/interest_calculator/calculator.py | 6 +++--- src/psc/gallery/examples/interest_calculator/index.html | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/psc/gallery/examples/interest_calculator/calculator.py b/src/psc/gallery/examples/interest_calculator/calculator.py index c055562..04caf36 100644 --- a/src/psc/gallery/examples/interest_calculator/calculator.py +++ b/src/psc/gallery/examples/interest_calculator/calculator.py @@ -2,7 +2,7 @@ def interest(*args, **kwargs): # Signal that PyScript is alive by setting the ``Calculate`` # button away from disabled. calculate_button = Element("calc") # noqa - calculate_button.element.setAttribute("disabled") + # calculate_button.element.setAttribute("disabled") # Now get the various inputs element_principal = Element("principal") # noqa @@ -15,8 +15,8 @@ def interest(*args, **kwargs): output2 = Element("compound_interest") # noqa res1 = round(principal + (principal * rate * time)) res2 = round(principal * ((1 + rate) ** time)) - output1.write("simple interest: " + str(res1)) - output2.write("compound interest: " + str(res2)) + output1.write(f"simple interest: {res1}") + output2.write(f"compound interest: {res2}") def setup(): diff --git a/src/psc/gallery/examples/interest_calculator/index.html b/src/psc/gallery/examples/interest_calculator/index.html index 530fd24..8f74cec 100644 --- a/src/psc/gallery/examples/interest_calculator/index.html +++ b/src/psc/gallery/examples/interest_calculator/index.html @@ -49,17 +49,17 @@

Welcome to the Compound Calculator!

+





From 43970ee866ef5108c42bb7525c82c4f17753e25e Mon Sep 17 00:00:00 2001 From: FabioRosado Date: Wed, 2 Nov 2022 20:27:53 +0000 Subject: [PATCH 08/11] update precommit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 020a43f..aaaa2a4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -53,7 +53,7 @@ repos: entry: pyupgrade language: system types: [python] - args: [--py37-plus] + args: [--py310-plus] - id: trailing-whitespace name: Trim Trailing Whitespace entry: trailing-whitespace-fixer From 1c870749ade1961483b7e2f0d5647b6e61ad5be9 Mon Sep 17 00:00:00 2001 From: FabioRosado Date: Fri, 4 Nov 2022 21:34:11 +0000 Subject: [PATCH 09/11] Fix pre-commit issues --- environment.yml | 2 +- src/psc/app.py | 2 +- src/psc/fixtures.py | 11 ++++++++--- .../examples/interest_calculator/calculator.py | 1 + tests/test_resources.py | 2 +- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/environment.yml b/environment.yml index 4e4bb33..0e1e2fc 100644 --- a/environment.yml +++ b/environment.yml @@ -3,7 +3,7 @@ channels: - conda-forge - microsoft dependencies: -- python=3.9 +- python=3.10 - pip=20.2.2 - pytest=7 - nodejs=16 diff --git a/src/psc/app.py b/src/psc/app.py index cb6e8ea..0921b56 100644 --- a/src/psc/app.py +++ b/src/psc/app.py @@ -1,8 +1,8 @@ """Provide a web server to browse the examples.""" import contextlib +from collections.abc import Iterator from pathlib import PurePath from typing import AsyncContextManager -from typing import Iterator from starlette.applications import Starlette from starlette.requests import Request diff --git a/src/psc/fixtures.py b/src/psc/fixtures.py index 1340e80..0ed3692 100644 --- a/src/psc/fixtures.py +++ b/src/psc/fixtures.py @@ -2,11 +2,11 @@ from __future__ import annotations import builtins +from collections.abc import Callable +from collections.abc import Generator from dataclasses import dataclass from dataclasses import field from mimetypes import guess_type -from typing import Callable -from typing import Generator from urllib.parse import urlparse import pytest @@ -199,6 +199,8 @@ def fake_document() -> FakeDocument: @dataclass class ElementNode: + """An element node.""" + value: str document: FakeDocument @@ -206,16 +208,19 @@ def write(self, value: str) -> None: """Collect anything that is written to the node.""" self.document.log.append(value) - def removeAttribute(self, name) -> None: + def removeAttribute(self, name) -> None: # noqa """Pretend to remove an attribute from this node.""" pass @dataclass class ElementCallable: + """A callable that returns an ElementNode.""" + document: FakeDocument def __call__(self, key: str) -> ElementNode: + """Return an ElementNode.""" value = self.document.values[key] node = ElementNode(value, self.document) return node diff --git a/src/psc/gallery/examples/interest_calculator/calculator.py b/src/psc/gallery/examples/interest_calculator/calculator.py index 04caf36..d9e1d70 100644 --- a/src/psc/gallery/examples/interest_calculator/calculator.py +++ b/src/psc/gallery/examples/interest_calculator/calculator.py @@ -1,4 +1,5 @@ def interest(*args, **kwargs): + """Main interest calculation function.""" # Signal that PyScript is alive by setting the ``Calculate`` # button away from disabled. calculate_button = Element("calc") # noqa diff --git a/tests/test_resources.py b/tests/test_resources.py index 8c701f0..ee1a6d9 100644 --- a/tests/test_resources.py +++ b/tests/test_resources.py @@ -90,7 +90,7 @@ def test_html_page() -> None: """Make an instance of a .html Page resource and test it.""" this_page = Page(path=PurePath("contributing")) assert this_page.title == "Contributing" - assert this_page.subtitle == "How to get involved in the PyCharm Collective." + assert this_page.subtitle == "How to get involved in the PyScript Collective." assert 'id="viewer"' in this_page.body From 84dc20cec5f5ed5c9b0b11d0ae444ec65808425a Mon Sep 17 00:00:00 2001 From: FabioRosado Date: Fri, 4 Nov 2022 22:10:51 +0000 Subject: [PATCH 10/11] Types --- src/psc/fixtures.py | 9 +++++---- .../examples/hello_world_py/hello_world.py | 2 +- tests/test_fixtures.py | 19 +++++++++++-------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/psc/fixtures.py b/src/psc/fixtures.py index 0ed3692..a4ae999 100644 --- a/src/psc/fixtures.py +++ b/src/psc/fixtures.py @@ -4,6 +4,7 @@ import builtins from collections.abc import Callable from collections.abc import Generator +from collections.abc import Iterable from dataclasses import dataclass from dataclasses import field from mimetypes import guess_type @@ -192,7 +193,7 @@ class FakeDocument: @pytest.fixture -def fake_document() -> FakeDocument: +def fake_document() -> Iterable[FakeDocument]: """Yield a document that cleans up.""" yield FakeDocument() @@ -208,7 +209,7 @@ def write(self, value: str) -> None: """Collect anything that is written to the node.""" self.document.log.append(value) - def removeAttribute(self, name) -> None: # noqa + def removeAttribute(self, name: str) -> None: # noqa """Pretend to remove an attribute from this node.""" pass @@ -227,10 +228,10 @@ def __call__(self, key: str) -> ElementNode: @pytest.fixture -def fake_element(fake_document) -> None: +def fake_element(fake_document: FakeDocument) -> None: # type: ignore [misc] """Install the stateful Element into builtins.""" try: - builtins.Element = ElementCallable(fake_document) + builtins.Element = ElementCallable(fake_document) #type: ignore [attr-defined] yield finally: delattr(builtins, "Element") diff --git a/src/psc/gallery/examples/hello_world_py/hello_world.py b/src/psc/gallery/examples/hello_world_py/hello_world.py index 4f4ef4f..d464d41 100644 --- a/src/psc/gallery/examples/hello_world_py/hello_world.py +++ b/src/psc/gallery/examples/hello_world_py/hello_world.py @@ -1,3 +1,3 @@ """Say Hello.""" -output = Element("output") +output = Element("output") #type: ignore output.write("From Python...") diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py index f011923..454dee3 100644 --- a/tests/test_fixtures.py +++ b/tests/test_fixtures.py @@ -11,6 +11,7 @@ from psc.fixtures import DummyRequest from psc.fixtures import DummyResponse from psc.fixtures import DummyRoute +from psc.fixtures import FakeDocument from psc.fixtures import MockTestClient from psc.fixtures import PageT from psc.fixtures import mocked_client_page @@ -18,6 +19,8 @@ from psc.here import STATIC +Element = cast("Unknown", "Element") + def test_test_client(test_client: TestClient) -> None: """Ensure fixture returns an initialized TestClient.""" assert test_client.app @@ -138,32 +141,32 @@ def test_route_handler_fake_bad_path() -> None: def test_fake_element_not_installed() -> None: """We don't request the fixture so it isn't available.""" with pytest.raises(NameError): - Element # noqa + Element # noqa -def test_fake_element_installed(fake_element) -> None: +def test_fake_element_installed(fake_element: function) -> None: """Element is available as ``fake_element`` installed it.""" - Element # noqa + Element # noqa -def test_fake_element_find_element(fake_document, fake_element) -> None: +def test_fake_element_find_element(fake_document: FakeDocument, fake_element: function) -> None: """The Element can get a value from the fake document.""" fake_document.values["btn1"] = "value1" button = Element("btn1") # noqa assert button.value == "value1" -def test_fake_element_write(fake_document, fake_element) -> None: +def test_fake_element_write(fake_document: FakeDocument, fake_element: function) -> None: """The Element can write a value that is captured.""" fake_document.values["btn1"] = "value1" - button = Element("btn1") # noqa + button = Element("btn1") # noqa button.write("Some Value") assert fake_document.log[0] == "Some Value" -def test_fake_element_remove_attribute(fake_document, fake_element) -> None: +def test_fake_element_remove_attribute(fake_document: FakeDocument, fake_element: function) -> None: """The Element can pretend to remove an attribute.""" fake_document.values["btn1"] = "value1" - button = Element("btn1") # noqa + button = Element("btn1") # noqa button.removeAttribute("disabled") assert fake_document.log == [] From 0904f0fa29b8f1b1a8a43fb6fc0980a764256c64 Mon Sep 17 00:00:00 2001 From: pauleveritt Date: Thu, 17 Nov 2022 19:34:17 -0500 Subject: [PATCH 11/11] Cleaned up the styling. Fixed an issue with a BOM that was messing up parsing of this example. --- .../examples/interest_calculator/index.html | 120 +++++++++--------- .../examples/interest_calculator/styles.css | 4 +- tests/examples/test_interest_calculator.py | 1 + tests/test_fixtures.py | 20 ++- 4 files changed, 70 insertions(+), 75 deletions(-) diff --git a/src/psc/gallery/examples/interest_calculator/index.html b/src/psc/gallery/examples/interest_calculator/index.html index 8f74cec..311aa2e 100644 --- a/src/psc/gallery/examples/interest_calculator/index.html +++ b/src/psc/gallery/examples/interest_calculator/index.html @@ -1,88 +1,83 @@ - - - + + - Interest Calculator + - -
-

Welcome to the Compound Calculator!

-
- -
- -
-

- Welcome to the "Simple and Compound Interest Calculator!" -
- "how does it work?" - to use the "Simple and Compound Interest Calculator", please enter the input data into the form. - after clicking "Calculate", your result will be shown at the bottom of the form. -

- -
-
- - - Compound Interest -
+
+
+
+

+ Welcome to the "Simple and Compound Interest Calculator!" +
+ "how does it work?" + to use the "Simple and Compound Interest Calculator", please enter the input data into the form. + after clicking "Calculate", your result will be shown at the bottom of the form. +

+ +
+
+ + + Compound Interest +
-
- - - Simple Interest +
+ + + Simple Interest +
-
-
+
-
+
-
- -

- -
-
+
+ +

+ +
+
- -

+ +

- + + +
+ +
+ +
-
- -
-
-
- - - - - setup() - -
+ + + + setup() + +
+