Upload 173 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +57 -0
- .gitignore +163 -0
- .idea/pyscript-pwa-example.iml +25 -0
- README.md +26 -10
- app.py +50 -0
- readme-resources/screenshot.png +3 -0
- requirements.txt +1 -0
- static/css/site.css +121 -0
- static/images/icons/icon-128x128.png +0 -0
- static/images/icons/icon-144x144.png +0 -0
- static/images/icons/icon-152x152.png +0 -0
- static/images/icons/icon-192x192.png +0 -0
- static/images/icons/icon-384x384.png +0 -0
- static/images/icons/icon-512x512.png +0 -0
- static/images/icons/icon-72x72.png +0 -0
- static/images/icons/icon-96x96.png +0 -0
- static/images/weather/cloudy.png +0 -0
- static/images/weather/offline.png +0 -0
- static/images/weather/partlysunny.png +0 -0
- static/images/weather/rain.png +0 -0
- static/images/weather/sunny.png +0 -0
- static/js/pwa-scaffold.js +8 -0
- static/js/serviceWorker.js +52 -0
- static/js/site.js +0 -0
- static/manifest.json +43 -0
- static/pyodide/CLAPACK-3.2.1.zip +3 -0
- static/pyodide/Jinja2-3.1.1-py3-none-any.whl +3 -0
- static/pyodide/Logbook-1.5.3-cp310-cp310-emscripten_wasm32.whl +0 -0
- static/pyodide/MarkupSafe-2.1.1-cp310-cp310-emscripten_wasm32.whl +0 -0
- static/pyodide/PIL-9.1.0-cp310-cp310-emscripten_wasm32.whl +3 -0
- static/pyodide/Pygments-2.11.2-py3-none-any.whl +3 -0
- static/pyodide/asciitree-0.3.3-py3-none-any.whl +0 -0
- static/pyodide/astropy-5.0.4-cp310-cp310-emscripten_wasm32.whl +3 -0
- static/pyodide/atomicwrites-1.4.0-py2.py3-none-any.whl +0 -0
- static/pyodide/attrs-21.4.0-py2.py3-none-any.whl +0 -0
- static/pyodide/autograd-1.4-py3-none-any.whl +0 -0
- static/pyodide/autograd-tests.tar +3 -0
- static/pyodide/b2d-0.7.2-cp310-cp310-emscripten_wasm32.whl +3 -0
- static/pyodide/beautifulsoup4-4.11.0-py3-none-any.whl +0 -0
- static/pyodide/biopython-1.79-cp310-cp310-emscripten_wasm32.whl +3 -0
- static/pyodide/bleach-5.0.0-py3-none-any.whl +3 -0
- static/pyodide/bokeh-2.4.2-py3-none-any.whl +3 -0
- static/pyodide/boost_histogram-1.3.1-cp310-cp310-emscripten_wasm32.whl +3 -0
- static/pyodide/cffi-1.15.0-cp310-cp310-emscripten_wasm32.whl +3 -0
- static/pyodide/cffi_example-0.1-cp310-cp310-emscripten_wasm32.whl +3 -0
- static/pyodide/cloudpickle-2.0.0-py3-none-any.whl +0 -0
- static/pyodide/cmyt-1.0.4-py3-none-any.whl +0 -0
- static/pyodide/cmyt-tests.tar +3 -0
- static/pyodide/colorspacious-1.1.2-py2.py3-none-any.whl +0 -0
- static/pyodide/console.html +168 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,60 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
readme-resources/screenshot.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
static/pyodide/astropy-5.0.4-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
static/pyodide/b2d-0.7.2-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
static/pyodide/biopython-1.79-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
static/pyodide/bleach-5.0.0-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
static/pyodide/bokeh-2.4.2-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
static/pyodide/boost_histogram-1.3.1-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
static/pyodide/cffi_example-0.1-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
static/pyodide/cffi-1.15.0-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
static/pyodide/cryptography-3.4.8-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 46 |
+
static/pyodide/cytoolz-0.11.2-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 47 |
+
static/pyodide/distlib-0.3.4-py2.py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 48 |
+
static/pyodide/docutils-0.18.1-py2.py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 49 |
+
static/pyodide/fonts/DejaVuSans-Bold.ttf filter=lfs diff=lfs merge=lfs -text
|
| 50 |
+
static/pyodide/fonts/DejaVuSans-BoldOblique.ttf filter=lfs diff=lfs merge=lfs -text
|
| 51 |
+
static/pyodide/fonts/DejaVuSans-Oblique.ttf filter=lfs diff=lfs merge=lfs -text
|
| 52 |
+
static/pyodide/fonts/DejaVuSans.ttf filter=lfs diff=lfs merge=lfs -text
|
| 53 |
+
static/pyodide/fonts/DejaVuSansMono-Bold.ttf filter=lfs diff=lfs merge=lfs -text
|
| 54 |
+
static/pyodide/fonts/DejaVuSansMono-BoldOblique.ttf filter=lfs diff=lfs merge=lfs -text
|
| 55 |
+
static/pyodide/fonts/DejaVuSansMono-Oblique.ttf filter=lfs diff=lfs merge=lfs -text
|
| 56 |
+
static/pyodide/fonts/DejaVuSansMono.ttf filter=lfs diff=lfs merge=lfs -text
|
| 57 |
+
static/pyodide/fonts/DejaVuSerif-Bold.ttf filter=lfs diff=lfs merge=lfs -text
|
| 58 |
+
static/pyodide/fonts/DejaVuSerif-BoldItalic.ttf filter=lfs diff=lfs merge=lfs -text
|
| 59 |
+
static/pyodide/fonts/DejaVuSerif-Italic.ttf filter=lfs diff=lfs merge=lfs -text
|
| 60 |
+
static/pyodide/fonts/DejaVuSerif.ttf filter=lfs diff=lfs merge=lfs -text
|
| 61 |
+
static/pyodide/fonts/STIXGeneral.ttf filter=lfs diff=lfs merge=lfs -text
|
| 62 |
+
static/pyodide/fonts/STIXGeneralBol.ttf filter=lfs diff=lfs merge=lfs -text
|
| 63 |
+
static/pyodide/fonts/STIXGeneralBolIta.ttf filter=lfs diff=lfs merge=lfs -text
|
| 64 |
+
static/pyodide/fonts/STIXGeneralItalic.ttf filter=lfs diff=lfs merge=lfs -text
|
| 65 |
+
static/pyodide/fonttools-4.32.0-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 66 |
+
static/pyodide/freesasa-2.1.0-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 67 |
+
static/pyodide/future-0.18.2-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 68 |
+
static/pyodide/html5lib-1.1-py2.py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 69 |
+
static/pyodide/imageio-2.16.1-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 70 |
+
static/pyodide/jedi-0.18.1-py2.py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 71 |
+
static/pyodide/Jinja2-3.1.1-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 72 |
+
static/pyodide/joblib-1.1.0-py2.py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 73 |
+
static/pyodide/lxml-4.8.0-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 74 |
+
static/pyodide/matplotlib-3.5.1-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 75 |
+
static/pyodide/mne-1.0.0-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 76 |
+
static/pyodide/mpmath-1.2.1-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 77 |
+
static/pyodide/networkx-2.7.1-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 78 |
+
static/pyodide/nlopt-2.7.0-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 79 |
+
static/pyodide/nltk-3.7-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 80 |
+
static/pyodide/nose-1.3.7-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 81 |
+
static/pyodide/numcodecs-0.9.1-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 82 |
+
static/pyodide/numpy-1.22.3-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 83 |
+
static/pyodide/pandas-1.4.2-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 84 |
+
static/pyodide/parso-0.8.3-py2.py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 85 |
+
static/pyodide/patsy-0.5.2-py2.py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 86 |
+
static/pyodide/PIL-9.1.0-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 87 |
+
static/pyodide/pycparser-2.21-py2.py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 88 |
+
static/pyodide/pydantic-1.9.0-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 89 |
+
static/pyodide/pyerfa-2.0.0.1-cp310-cp310-emscripten_wasm32.whl filter=lfs diff=lfs merge=lfs -text
|
| 90 |
+
static/pyodide/Pygments-2.11.2-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
| 91 |
+
static/pyodide/pyodide.asm.data filter=lfs diff=lfs merge=lfs -text
|
| 92 |
+
static/pyodide/pytest-7.1.1-py3-none-any.whl filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Byte-compiled / optimized / DLL files
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.py[cod]
|
| 4 |
+
*$py.class
|
| 5 |
+
|
| 6 |
+
# C extensions
|
| 7 |
+
*.so
|
| 8 |
+
|
| 9 |
+
# Distribution / packaging
|
| 10 |
+
.Python
|
| 11 |
+
build/
|
| 12 |
+
develop-eggs/
|
| 13 |
+
dist/
|
| 14 |
+
downloads/
|
| 15 |
+
eggs/
|
| 16 |
+
.eggs/
|
| 17 |
+
lib/
|
| 18 |
+
lib64/
|
| 19 |
+
parts/
|
| 20 |
+
sdist/
|
| 21 |
+
var/
|
| 22 |
+
wheels/
|
| 23 |
+
share/python-wheels/
|
| 24 |
+
*.egg-info/
|
| 25 |
+
.installed.cfg
|
| 26 |
+
*.egg
|
| 27 |
+
MANIFEST
|
| 28 |
+
|
| 29 |
+
# PyInstaller
|
| 30 |
+
# Usually these files are written by a python script from a template
|
| 31 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
| 32 |
+
*.manifest
|
| 33 |
+
*.spec
|
| 34 |
+
|
| 35 |
+
# Installer logs
|
| 36 |
+
pip-log.txt
|
| 37 |
+
pip-delete-this-directory.txt
|
| 38 |
+
|
| 39 |
+
# Unit test / coverage reports
|
| 40 |
+
htmlcov/
|
| 41 |
+
.tox/
|
| 42 |
+
.nox/
|
| 43 |
+
.coverage
|
| 44 |
+
.coverage.*
|
| 45 |
+
.cache
|
| 46 |
+
nosetests.xml
|
| 47 |
+
coverage.xml
|
| 48 |
+
*.cover
|
| 49 |
+
*.py,cover
|
| 50 |
+
.hypothesis/
|
| 51 |
+
.pytest_cache/
|
| 52 |
+
cover/
|
| 53 |
+
|
| 54 |
+
# Translations
|
| 55 |
+
*.mo
|
| 56 |
+
*.pot
|
| 57 |
+
|
| 58 |
+
# Django stuff:
|
| 59 |
+
*.log
|
| 60 |
+
local_settings.py
|
| 61 |
+
db.sqlite3
|
| 62 |
+
db.sqlite3-journal
|
| 63 |
+
|
| 64 |
+
# Flask stuff:
|
| 65 |
+
instance/
|
| 66 |
+
.webassets-cache
|
| 67 |
+
|
| 68 |
+
# Scrapy stuff:
|
| 69 |
+
.scrapy
|
| 70 |
+
|
| 71 |
+
# Sphinx documentation
|
| 72 |
+
docs/_build/
|
| 73 |
+
|
| 74 |
+
# PyBuilder
|
| 75 |
+
.pybuilder/
|
| 76 |
+
target/
|
| 77 |
+
|
| 78 |
+
# Jupyter Notebook
|
| 79 |
+
.ipynb_checkpoints
|
| 80 |
+
|
| 81 |
+
# IPython
|
| 82 |
+
profile_default/
|
| 83 |
+
ipython_config.py
|
| 84 |
+
|
| 85 |
+
# pyenv
|
| 86 |
+
# For a library or package, you might want to ignore these files since the code is
|
| 87 |
+
# intended to run in multiple environments; otherwise, check them in:
|
| 88 |
+
# .python-version
|
| 89 |
+
|
| 90 |
+
# pipenv
|
| 91 |
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
| 92 |
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
| 93 |
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
| 94 |
+
# install all needed dependencies.
|
| 95 |
+
#Pipfile.lock
|
| 96 |
+
|
| 97 |
+
# poetry
|
| 98 |
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
| 99 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
| 100 |
+
# commonly ignored for libraries.
|
| 101 |
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
| 102 |
+
#poetry.lock
|
| 103 |
+
|
| 104 |
+
# pdm
|
| 105 |
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
| 106 |
+
#pdm.lock
|
| 107 |
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
| 108 |
+
# in version control.
|
| 109 |
+
# https://pdm.fming.dev/#use-with-ide
|
| 110 |
+
.pdm.toml
|
| 111 |
+
|
| 112 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
| 113 |
+
__pypackages__/
|
| 114 |
+
|
| 115 |
+
# Celery stuff
|
| 116 |
+
celerybeat-schedule
|
| 117 |
+
celerybeat.pid
|
| 118 |
+
|
| 119 |
+
# SageMath parsed files
|
| 120 |
+
*.sage.py
|
| 121 |
+
|
| 122 |
+
# Environments
|
| 123 |
+
.env
|
| 124 |
+
.venv
|
| 125 |
+
env/
|
| 126 |
+
venv/
|
| 127 |
+
ENV/
|
| 128 |
+
env.bak/
|
| 129 |
+
venv.bak/
|
| 130 |
+
|
| 131 |
+
# Spyder project settings
|
| 132 |
+
.spyderproject
|
| 133 |
+
.spyproject
|
| 134 |
+
|
| 135 |
+
# Rope project settings
|
| 136 |
+
.ropeproject
|
| 137 |
+
|
| 138 |
+
# mkdocs documentation
|
| 139 |
+
/site
|
| 140 |
+
|
| 141 |
+
# mypy
|
| 142 |
+
.mypy_cache/
|
| 143 |
+
.dmypy.json
|
| 144 |
+
dmypy.json
|
| 145 |
+
|
| 146 |
+
# Pyre type checker
|
| 147 |
+
.pyre/
|
| 148 |
+
|
| 149 |
+
# pytype static type analyzer
|
| 150 |
+
.pytype/
|
| 151 |
+
|
| 152 |
+
# Cython debug symbols
|
| 153 |
+
cython_debug/
|
| 154 |
+
|
| 155 |
+
# PyCharm
|
| 156 |
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
| 157 |
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
| 158 |
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
| 159 |
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
| 160 |
+
#.idea/
|
| 161 |
+
|
| 162 |
+
unused-wheels/
|
| 163 |
+
/.idea/workspace.xml
|
.idea/pyscript-pwa-example.iml
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
| 2 |
+
<module type="PYTHON_MODULE" version="4">
|
| 3 |
+
<component name="Flask">
|
| 4 |
+
<option name="enabled" value="true" />
|
| 5 |
+
</component>
|
| 6 |
+
<component name="NewModuleRootManager">
|
| 7 |
+
<content url="file://$MODULE_DIR$">
|
| 8 |
+
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
| 9 |
+
</content>
|
| 10 |
+
<orderEntry type="inheritedJdk" />
|
| 11 |
+
<orderEntry type="sourceFolder" forTests="false" />
|
| 12 |
+
</component>
|
| 13 |
+
<component name="PyDocumentationSettings">
|
| 14 |
+
<option name="format" value="PLAIN" />
|
| 15 |
+
<option name="myDocStringFormat" value="Plain" />
|
| 16 |
+
</component>
|
| 17 |
+
<component name="TemplatesService">
|
| 18 |
+
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
|
| 19 |
+
<option name="TEMPLATE_FOLDERS">
|
| 20 |
+
<list>
|
| 21 |
+
<option value="$MODULE_DIR$/templates" />
|
| 22 |
+
</list>
|
| 23 |
+
</option>
|
| 24 |
+
</component>
|
| 25 |
+
</module>
|
README.md
CHANGED
|
@@ -1,10 +1,26 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# pyscript PWA Example
|
| 2 |
+
|
| 3 |
+
This app shows how using a PWA (Progressive Web App) along with [pyscript](https://pyscript.net)
|
| 4 |
+
allows us to create Python-based web applications that install like regular applications and
|
| 5 |
+
(mostly) don't suffer from the large file downloads needed for Python's WebAssembly runtime.
|
| 6 |
+
|
| 7 |
+

|
| 8 |
+
|
| 9 |
+
To run the app, just start it as a Flask application (keep the app running for the web weather API).
|
| 10 |
+
|
| 11 |
+
```bash
|
| 12 |
+
|
| 13 |
+
python3 -m venv venv
|
| 14 |
+
. /venv/bin/activate
|
| 15 |
+
pip install -r requirements.txt
|
| 16 |
+
flask run
|
| 17 |
+
|
| 18 |
+
```
|
| 19 |
+
|
| 20 |
+
Then open 127.0.0.1:5000 and choose "install PWA". See
|
| 21 |
+
[these steps for Chrome](https://www.howtogeek.com/fyi/how-to-install-progressive-web-apps-pwas-in-chrome/),
|
| 22 |
+
google the actions if you are new to this in your browser.
|
| 23 |
+
|
| 24 |
+
Unfortunately, Mozilla gave up on this feature for Firefox browser.
|
| 25 |
+
|
| 26 |
+
If you have improvements for the PWA side of things, please open a PR. It's very bare-bones.
|
app.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import random
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
|
| 4 |
+
import flask
|
| 5 |
+
|
| 6 |
+
app = flask.Flask(__name__)
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
@app.get('/')
|
| 10 |
+
def index():
|
| 11 |
+
return flask.render_template('index.html')
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
@app.get('/weather/data')
|
| 15 |
+
def weather_data():
|
| 16 |
+
data = get_random_report()
|
| 17 |
+
return flask.jsonify(data)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
@app.get('/serviceWorker.js')
|
| 21 |
+
def worker():
|
| 22 |
+
js = Path(__file__).parent / 'static' / 'js' / 'serviceWorker.js'
|
| 23 |
+
text = js.read_text()
|
| 24 |
+
resp = flask.make_response(text)
|
| 25 |
+
resp.content_type = 'application/javascript'
|
| 26 |
+
resp.headers['Service-Worker-Allowed'] = '/'
|
| 27 |
+
|
| 28 |
+
return resp
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def get_random_report() -> dict:
|
| 32 |
+
reports = [
|
| 33 |
+
{
|
| 34 |
+
'report': 'Clear and beautify skies today.',
|
| 35 |
+
'sky': 'sunny',
|
| 36 |
+
'temp': random.randint(65, 88),
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
'report': 'Cloudy and a bit cool today.',
|
| 40 |
+
'sky': 'cloudy',
|
| 41 |
+
'temp': random.randint(48, 60),
|
| 42 |
+
},
|
| 43 |
+
{
|
| 44 |
+
'report': 'Are those icicles falling from the sky? Get inside.',
|
| 45 |
+
'sky': 'rain',
|
| 46 |
+
'temp': random.randint(33, 40),
|
| 47 |
+
}
|
| 48 |
+
]
|
| 49 |
+
|
| 50 |
+
return random.choice(reports)
|
readme-resources/screenshot.png
ADDED
|
Git LFS Details
|
requirements.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
flask
|
static/css/site.css
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
* {
|
| 2 |
+
margin: 0;
|
| 3 |
+
padding: 0;
|
| 4 |
+
box-sizing: border-box;
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
body {
|
| 8 |
+
background: #fdfdfd;
|
| 9 |
+
font-family: "Nunito", sans-serif;
|
| 10 |
+
font-size: 1rem;
|
| 11 |
+
overflow: hidden;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
html, body {
|
| 15 |
+
height: 100%;
|
| 16 |
+
min-height: 100%;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
main {
|
| 20 |
+
max-width: 900px;
|
| 21 |
+
margin: auto;
|
| 22 |
+
padding: 0.5rem;
|
| 23 |
+
text-align: center;
|
| 24 |
+
height: 80%;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
nav {
|
| 28 |
+
display: flex;
|
| 29 |
+
justify-content: space-between;
|
| 30 |
+
align-items: center;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
ul {
|
| 34 |
+
list-style: none;
|
| 35 |
+
display: flex;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
li {
|
| 39 |
+
margin-right: 1rem;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
h1 {
|
| 43 |
+
margin-bottom: 0.5rem;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
.container {
|
| 48 |
+
display: grid;
|
| 49 |
+
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
|
| 50 |
+
grid-gap: 1rem;
|
| 51 |
+
justify-content: center;
|
| 52 |
+
align-items: center;
|
| 53 |
+
margin: auto;
|
| 54 |
+
padding: 1rem 0;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
body.sunny {
|
| 59 |
+
background: #69caf8;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
body.cloudy {
|
| 63 |
+
background: #cbcaca;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
body.rain {
|
| 67 |
+
background: #607280;
|
| 68 |
+
color: white;
|
| 69 |
+
}
|
| 70 |
+
body.offline {
|
| 71 |
+
background: #e37f7f;
|
| 72 |
+
color: black;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
#weather {
|
| 76 |
+
margin-top: 100px;
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
#weather #image-container {
|
| 80 |
+
float: left;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
#weather #image {
|
| 84 |
+
width: 350px;
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
#weather #temp {
|
| 88 |
+
padding-top: 70px;
|
| 89 |
+
font-size: 100px;
|
| 90 |
+
font-weight: bold;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
#weather #forecast {
|
| 94 |
+
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
footer {
|
| 98 |
+
text-align: center;
|
| 99 |
+
height: 20%;
|
| 100 |
+
background-color: #444;
|
| 101 |
+
color: #aaa;
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
.footer-content {
|
| 105 |
+
padding-top: 40px;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
a {
|
| 110 |
+
cursor: pointer;
|
| 111 |
+
font-weight: bold;
|
| 112 |
+
text-decoration: none;
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
a:hover {
|
| 116 |
+
text-decoration: underline;
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
.hidden {
|
| 120 |
+
display: none;
|
| 121 |
+
}
|
static/images/icons/icon-128x128.png
ADDED
|
|
static/images/icons/icon-144x144.png
ADDED
|
|
static/images/icons/icon-152x152.png
ADDED
|
|
static/images/icons/icon-192x192.png
ADDED
|
|
static/images/icons/icon-384x384.png
ADDED
|
|
static/images/icons/icon-512x512.png
ADDED
|
|
static/images/icons/icon-72x72.png
ADDED
|
|
static/images/icons/icon-96x96.png
ADDED
|
|
static/images/weather/cloudy.png
ADDED
|
static/images/weather/offline.png
ADDED
|
static/images/weather/partlysunny.png
ADDED
|
static/images/weather/rain.png
ADDED
|
static/images/weather/sunny.png
ADDED
|
static/js/pwa-scaffold.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
if ("serviceWorker" in navigator) {
|
| 2 |
+
window.addEventListener("load", function () {
|
| 3 |
+
navigator.serviceWorker
|
| 4 |
+
.register("/serviceWorker.js")
|
| 5 |
+
.then(res => console.log("service worker registered", res))
|
| 6 |
+
.catch(err => console.log("service worker not registered", err))
|
| 7 |
+
})
|
| 8 |
+
}
|
static/js/serviceWorker.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const staticPyPWA = "dev-pypwa-v4"
|
| 2 |
+
const assets = [
|
| 3 |
+
// "",
|
| 4 |
+
// "/",
|
| 5 |
+
"/static/css/site.css",
|
| 6 |
+
"/static/js/site.js",
|
| 7 |
+
"/static/js/pwa-scaffold.js",
|
| 8 |
+
|
| 9 |
+
"/static/python/client.py",
|
| 10 |
+
"/static/python/weather_api.py",
|
| 11 |
+
|
| 12 |
+
"/static/pyscript/pyscript.css",
|
| 13 |
+
"/static/pyscript/pyscript.js",
|
| 14 |
+
"/static/pyscript/pyscript.py",
|
| 15 |
+
|
| 16 |
+
"/static/images/weather/cloudy.png",
|
| 17 |
+
"/static/images/weather/rain.png",
|
| 18 |
+
"/static/images/weather/offline.png",
|
| 19 |
+
"/static/images/weather/sunny.png",
|
| 20 |
+
|
| 21 |
+
"/static/pyodide/pyodide.js",
|
| 22 |
+
"/static/pyodide/packages.json",
|
| 23 |
+
"/static/pyodide/pyodide_py.tar",
|
| 24 |
+
"/static/pyodide/pyodide.asm.js",
|
| 25 |
+
"/static/pyodide/pyodide.asm.data",
|
| 26 |
+
"/static/pyodide/pyodide.asm.wasm",
|
| 27 |
+
"/static/pyodide/micropip-0.1-py3-none-any.whl",
|
| 28 |
+
"/static/pyodide/pyparsing-3.0.7-py3-none-any.whl",
|
| 29 |
+
"/static/pyodide/packaging-21.3-py3-none-any.whl",
|
| 30 |
+
"/static/pyodide/distutils.tar",
|
| 31 |
+
|
| 32 |
+
"/static/images/icons/icon-144x144.png",
|
| 33 |
+
]
|
| 34 |
+
|
| 35 |
+
self.addEventListener("install", installEvent => {
|
| 36 |
+
installEvent.waitUntil(
|
| 37 |
+
caches.open(staticPyPWA).then(cache => {
|
| 38 |
+
cache.addAll(assets).then(r => {
|
| 39 |
+
console.log("Cache assets downloaded");
|
| 40 |
+
}).catch(err => console.log("Error caching item", err))
|
| 41 |
+
console.log(`Cache ${staticPyPWA} opened.`);
|
| 42 |
+
}).catch(err => console.log("Error opening cache", err))
|
| 43 |
+
)
|
| 44 |
+
})
|
| 45 |
+
|
| 46 |
+
self.addEventListener("fetch", fetchEvent => {
|
| 47 |
+
fetchEvent.respondWith(
|
| 48 |
+
caches.match(fetchEvent.request).then(res => {
|
| 49 |
+
return res || fetch(fetchEvent.request)
|
| 50 |
+
}).catch(err => console.log("Cache fetch error: ", err))
|
| 51 |
+
)
|
| 52 |
+
})
|
static/js/site.js
ADDED
|
File without changes
|
static/manifest.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "PyPWA Weather",
|
| 3 |
+
"short_name": "PyPWA Weather",
|
| 4 |
+
"start_url": "/",
|
| 5 |
+
"display": "standalone",
|
| 6 |
+
"background_color": "#69caf8",
|
| 7 |
+
"theme_color": "#444444",
|
| 8 |
+
"orientation": "portrait-primary",
|
| 9 |
+
"icons": [
|
| 10 |
+
{
|
| 11 |
+
"src": "/static/images/icons/icon-72x72.png",
|
| 12 |
+
"type": "image/png", "sizes": "72x72"
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"src": "/static/images/icons/icon-96x96.png",
|
| 16 |
+
"type": "image/png", "sizes": "96x96"
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"src": "/static/images/icons/icon-128x128.png",
|
| 20 |
+
"type": "image/png","sizes": "128x128"
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"src": "/static/images/icons/icon-144x144.png",
|
| 24 |
+
"type": "image/png", "sizes": "144x144"
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"src": "/static/images/icons/icon-152x152.png",
|
| 28 |
+
"type": "image/png", "sizes": "152x152"
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"src": "/static/images/icons/icon-192x192.png",
|
| 32 |
+
"type": "image/png", "sizes": "192x192"
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"src": "/static/images/icons/icon-384x384.png",
|
| 36 |
+
"type": "image/png", "sizes": "384x384"
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"src": "/static/images/icons/icon-512x512.png",
|
| 40 |
+
"type": "image/png", "sizes": "512x512"
|
| 41 |
+
}
|
| 42 |
+
]
|
| 43 |
+
}
|
static/pyodide/CLAPACK-3.2.1.zip
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2662f266d19c2e684a0c7d67c045d3f0767447fe5c0eed3509bbd31a25e6ca31
|
| 3 |
+
size 1277110
|
static/pyodide/Jinja2-3.1.1-py3-none-any.whl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:63992624b74ec0ebe62b1c10b44aff5e6a85b0b84a8668d6b681a2478fd11cf7
|
| 3 |
+
size 132603
|
static/pyodide/Logbook-1.5.3-cp310-cp310-emscripten_wasm32.whl
ADDED
|
Binary file (93.3 kB). View file
|
|
|
static/pyodide/MarkupSafe-2.1.1-cp310-cp310-emscripten_wasm32.whl
ADDED
|
Binary file (12 kB). View file
|
|
|
static/pyodide/PIL-9.1.0-cp310-cp310-emscripten_wasm32.whl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:38d692b74bb4c0614796f1e2c9beb931f5a6a79853611d0d2a205445957752f2
|
| 3 |
+
size 852898
|
static/pyodide/Pygments-2.11.2-py3-none-any.whl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e735d55ccda6306fe3e36dc6c1867b97a45cf8aa20c4907b24df5eaa9dc63b24
|
| 3 |
+
size 1063665
|
static/pyodide/asciitree-0.3.3-py3-none-any.whl
ADDED
|
Binary file (5.05 kB). View file
|
|
|
static/pyodide/astropy-5.0.4-cp310-cp310-emscripten_wasm32.whl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:78f779cfda0210401459497cf8eb20077b720dea9eb27bd74b5dffc10a4da75b
|
| 3 |
+
size 6121279
|
static/pyodide/atomicwrites-1.4.0-py2.py3-none-any.whl
ADDED
|
Binary file (6.79 kB). View file
|
|
|
static/pyodide/attrs-21.4.0-py2.py3-none-any.whl
ADDED
|
Binary file (60.6 kB). View file
|
|
|
static/pyodide/autograd-1.4-py3-none-any.whl
ADDED
|
Binary file (47.6 kB). View file
|
|
|
static/pyodide/autograd-tests.tar
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:785d04b1a0b7288fcd318bda0343e418898aa12d42e9b5aff3dd3a1d67f76144
|
| 3 |
+
size 10240
|
static/pyodide/b2d-0.7.2-cp310-cp310-emscripten_wasm32.whl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:73317f7d55dd2e307db75cae21d27307ca57847b1b12547356fdf8e3422c8e69
|
| 3 |
+
size 308974
|
static/pyodide/beautifulsoup4-4.11.0-py3-none-any.whl
ADDED
|
Binary file (72 kB). View file
|
|
|
static/pyodide/biopython-1.79-cp310-cp310-emscripten_wasm32.whl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ed44cdce7d9b05e123a9cf9bea1defc9003257626cc2ad6e4ff5da0dbdcb8782
|
| 3 |
+
size 2203790
|
static/pyodide/bleach-5.0.0-py3-none-any.whl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8335829b36ae9ef324ff8f66b7191683e0bc962cf82d0cf5c2db5d300354e547
|
| 3 |
+
size 160294
|
static/pyodide/bokeh-2.4.2-py3-none-any.whl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:bfd2e2ff2cf64b10dfaa48ef2fd9e57622c8a7fec3d86cf737dbefac96c2a1f7
|
| 3 |
+
size 18470310
|
static/pyodide/boost_histogram-1.3.1-cp310-cp310-emscripten_wasm32.whl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7aafa2d98e202ae65cfa0d6f91965e262268f4e3c976c5aff04214dc10fc5efc
|
| 3 |
+
size 936253
|
static/pyodide/cffi-1.15.0-cp310-cp310-emscripten_wasm32.whl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8a78d2f60271ce07f3516c2247df10782376b88149c5608bc41367b3f257bba2
|
| 3 |
+
size 148396
|
static/pyodide/cffi_example-0.1-cp310-cp310-emscripten_wasm32.whl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:740611eac17de512fc711fad332e9146670e4244fd7ac8665af57e328d477eba
|
| 3 |
+
size 262492
|
static/pyodide/cloudpickle-2.0.0-py3-none-any.whl
ADDED
|
Binary file (25.7 kB). View file
|
|
|
static/pyodide/cmyt-1.0.4-py3-none-any.whl
ADDED
|
Binary file (28.9 kB). View file
|
|
|
static/pyodide/cmyt-tests.tar
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a7a5efd425ceced01b7d33b72be12548b944c63fb48b572ed77768db8c7ea476
|
| 3 |
+
size 20480
|
static/pyodide/colorspacious-1.1.2-py2.py3-none-any.whl
ADDED
|
Binary file (37.7 kB). View file
|
|
|
static/pyodide/console.html
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<script src="https://cdn.jsdelivr.net/npm/jquery"></script>
|
| 6 |
+
<script src="https://cdn.jsdelivr.net/npm/jquery.terminal@2.32.0/js/jquery.terminal.min.js"></script>
|
| 7 |
+
<script src="https://cdn.jsdelivr.net/npm/jquery.terminal@2.23.0/js/unix_formatting.min.js"></script>
|
| 8 |
+
<link
|
| 9 |
+
href="https://cdn.jsdelivr.net/npm/jquery.terminal@2.32.0/css/jquery.terminal.min.css"
|
| 10 |
+
rel="stylesheet"
|
| 11 |
+
/>
|
| 12 |
+
<script src="./pyodide.js"></script>
|
| 13 |
+
<style>
|
| 14 |
+
.terminal {
|
| 15 |
+
--size: 1.5;
|
| 16 |
+
--color: rgba(255, 255, 255, 0.8);
|
| 17 |
+
}
|
| 18 |
+
</style>
|
| 19 |
+
</head>
|
| 20 |
+
<body>
|
| 21 |
+
<script>
|
| 22 |
+
"use strict";
|
| 23 |
+
function sleep(s) {
|
| 24 |
+
return new Promise((resolve) => setTimeout(resolve, s));
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
async function main() {
|
| 28 |
+
globalThis.pyodide = await loadPyodide();
|
| 29 |
+
let namespace = pyodide.globals.get("dict")();
|
| 30 |
+
pyodide.runPython(
|
| 31 |
+
`
|
| 32 |
+
import sys
|
| 33 |
+
from pyodide import to_js
|
| 34 |
+
from pyodide.console import PyodideConsole, repr_shorten, BANNER
|
| 35 |
+
import __main__
|
| 36 |
+
BANNER = "Welcome to the Pyodide terminal emulator 🐍\\n" + BANNER
|
| 37 |
+
pyconsole = PyodideConsole(__main__.__dict__)
|
| 38 |
+
import builtins
|
| 39 |
+
async def await_fut(fut):
|
| 40 |
+
res = await fut
|
| 41 |
+
if res is not None:
|
| 42 |
+
builtins._ = res
|
| 43 |
+
return to_js([res], depth=1)
|
| 44 |
+
def clear_console():
|
| 45 |
+
pyconsole.buffer = []
|
| 46 |
+
`,
|
| 47 |
+
{ globals: namespace }
|
| 48 |
+
);
|
| 49 |
+
let repr_shorten = namespace.get("repr_shorten");
|
| 50 |
+
let banner = namespace.get("BANNER");
|
| 51 |
+
let await_fut = namespace.get("await_fut");
|
| 52 |
+
let pyconsole = namespace.get("pyconsole");
|
| 53 |
+
let clear_console = namespace.get("clear_console");
|
| 54 |
+
namespace.destroy();
|
| 55 |
+
|
| 56 |
+
let ps1 = ">>> ",
|
| 57 |
+
ps2 = "... ";
|
| 58 |
+
|
| 59 |
+
async function lock() {
|
| 60 |
+
let resolve;
|
| 61 |
+
let ready = term.ready;
|
| 62 |
+
term.ready = new Promise((res) => (resolve = res));
|
| 63 |
+
await ready;
|
| 64 |
+
return resolve;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
async function interpreter(command) {
|
| 68 |
+
let unlock = await lock();
|
| 69 |
+
term.pause();
|
| 70 |
+
// multiline should be split (useful when pasting)
|
| 71 |
+
for (const c of command.split("\n")) {
|
| 72 |
+
let fut = pyconsole.push(c);
|
| 73 |
+
term.set_prompt(fut.syntax_check === "incomplete" ? ps2 : ps1);
|
| 74 |
+
switch (fut.syntax_check) {
|
| 75 |
+
case "syntax-error":
|
| 76 |
+
term.error(fut.formatted_error.trimEnd());
|
| 77 |
+
continue;
|
| 78 |
+
case "incomplete":
|
| 79 |
+
continue;
|
| 80 |
+
case "complete":
|
| 81 |
+
break;
|
| 82 |
+
default:
|
| 83 |
+
throw new Error(`Unexpected type ${ty}`);
|
| 84 |
+
}
|
| 85 |
+
// In JavaScript, await automatically also awaits any results of
|
| 86 |
+
// awaits, so if an async function returns a future, it will await
|
| 87 |
+
// the inner future too. This is not what we want so we
|
| 88 |
+
// temporarily put it into a list to protect it.
|
| 89 |
+
let wrapped = await_fut(fut);
|
| 90 |
+
// complete case, get result / error and print it.
|
| 91 |
+
try {
|
| 92 |
+
let [value] = await wrapped;
|
| 93 |
+
if (value !== undefined) {
|
| 94 |
+
term.echo(
|
| 95 |
+
repr_shorten.callKwargs(value, {
|
| 96 |
+
separator: "\n[[;orange;]<long output truncated>]\n",
|
| 97 |
+
})
|
| 98 |
+
);
|
| 99 |
+
}
|
| 100 |
+
if (pyodide.isPyProxy(value)) {
|
| 101 |
+
value.destroy();
|
| 102 |
+
}
|
| 103 |
+
} catch (e) {
|
| 104 |
+
if (e.constructor.name === "PythonError") {
|
| 105 |
+
const message = fut.formatted_error || e.message;
|
| 106 |
+
term.error(message.trimEnd());
|
| 107 |
+
} else {
|
| 108 |
+
throw e;
|
| 109 |
+
}
|
| 110 |
+
} finally {
|
| 111 |
+
fut.destroy();
|
| 112 |
+
wrapped.destroy();
|
| 113 |
+
}
|
| 114 |
+
}
|
| 115 |
+
term.resume();
|
| 116 |
+
await sleep(10);
|
| 117 |
+
unlock();
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
let term = $("body").terminal(interpreter, {
|
| 121 |
+
greetings: banner,
|
| 122 |
+
prompt: ps1,
|
| 123 |
+
completionEscape: false,
|
| 124 |
+
completion: function (command, callback) {
|
| 125 |
+
callback(pyconsole.complete(command).toJs()[0]);
|
| 126 |
+
},
|
| 127 |
+
keymap: {
|
| 128 |
+
"CTRL+C": async function (event, original) {
|
| 129 |
+
clear_console();
|
| 130 |
+
term.enter();
|
| 131 |
+
term.echo("KeyboardInterrupt");
|
| 132 |
+
term.set_command("");
|
| 133 |
+
term.set_prompt(ps1);
|
| 134 |
+
},
|
| 135 |
+
TAB: (event, original) => {
|
| 136 |
+
const command = term.before_cursor();
|
| 137 |
+
// Disable completion for whitespaces.
|
| 138 |
+
if (command.trim() === "") {
|
| 139 |
+
term.insert("\t");
|
| 140 |
+
return false;
|
| 141 |
+
}
|
| 142 |
+
return original(event);
|
| 143 |
+
},
|
| 144 |
+
},
|
| 145 |
+
});
|
| 146 |
+
window.term = term;
|
| 147 |
+
pyconsole.stdout_callback = (s) => term.echo(s, { newline: false });
|
| 148 |
+
pyconsole.stderr_callback = (s) => {
|
| 149 |
+
term.error(s.trimEnd());
|
| 150 |
+
};
|
| 151 |
+
term.ready = Promise.resolve();
|
| 152 |
+
pyodide._api.on_fatal = async (e) => {
|
| 153 |
+
term.error(
|
| 154 |
+
"Pyodide has suffered a fatal error. Please report this to the Pyodide maintainers."
|
| 155 |
+
);
|
| 156 |
+
term.error("The cause of the fatal error was:");
|
| 157 |
+
term.error(e);
|
| 158 |
+
term.error("Look in the browser console for more details.");
|
| 159 |
+
await term.ready;
|
| 160 |
+
term.pause();
|
| 161 |
+
await sleep(15);
|
| 162 |
+
term.pause();
|
| 163 |
+
};
|
| 164 |
+
}
|
| 165 |
+
window.console_ready = main();
|
| 166 |
+
</script>
|
| 167 |
+
</body>
|
| 168 |
+
</html>
|