{"id":21274811,"url":"https://github.com/maayanlab/appyter","last_synced_at":"2025-07-11T06:34:38.810Z","repository":{"id":37954363,"uuid":"246416456","full_name":"MaayanLab/appyter","owner":"MaayanLab","description":"jinja2-enabled jupyter notebooks","archived":false,"fork":false,"pushed_at":"2024-05-22T20:47:29.000Z","size":45192,"stargazers_count":34,"open_issues_count":29,"forks_count":6,"subscribers_count":8,"default_branch":"main","last_synced_at":"2024-05-22T21:56:31.034Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://maayanlab.github.io/appyter/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MaayanLab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-10T21:55:15.000Z","updated_at":"2024-05-29T21:39:32.528Z","dependencies_parsed_at":"2024-05-07T21:23:15.741Z","dependency_job_id":"95082a2e-2b6c-4229-a5c6-488f4d1e1cbe","html_url":"https://github.com/MaayanLab/appyter","commit_stats":{"total_commits":1368,"total_committers":3,"mean_commits":456.0,"dds":"0.0029239766081871066","last_synced_commit":"00d3d21e722e7d7053e8a695cd36011c171d5d32"},"previous_names":[],"tags_count":232,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaayanLab%2Fappyter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaayanLab%2Fappyter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaayanLab%2Fappyter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaayanLab%2Fappyter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MaayanLab","download_url":"https://codeload.github.com/MaayanLab/appyter/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225703550,"owners_count":17510924,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-21T09:25:44.372Z","updated_at":"2025-07-11T06:34:38.804Z","avatar_url":"https://github.com/MaayanLab.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Appyter\nThis module enables you to turn your jupyter notebook into a jinja2 template-driven web application. Or just parse for other purposes.\n\n## Installation\nNOTE: This application uses modern python features including async await (3.5) and fstrings (3.6), to ensure you have the best experience please use python \u003e= 3.8.\n\n```bash\n# Install package from pip\npip3 install --upgrade appyter\n\n# OR Install package from github repository main\npip3 install --upgrade git+https://github.com/Maayanlab/appyter.git\n```\n\n## Usage\nAppyter enables you to serve that notebook on an executable webapp.\n\n`appyter jupyter_notebook.ipynb`\n\nIf for some reason, `appyter` doesn't end up discoverable in your PATH, you can use `python3 -m appyter` instead.\n\n- A dotenv file (`.env`) or environment variables can be use to configure HOST (APPYTER_HOST), PORT (APPYTER_PORT), and PREFIX (APPYTER_PREFIX) of the webserver.\n- Some pre-configured profiles can be used for styling the form (`--profile=profile_name`) see `appyter/profiles`\n- In debug mode (`--debug`), changes to the notebook will automatically update the webapp.\n- Custom fields can be used by putting them in the directory of execution with the following format:\n  - `./fields/YourField.py`: Python Field Implementation\n- The templates used natively by the application can be modified to provide your own look and feel:\n  - `./templates/head.jinja2`: Custom head (title, CSS, scripts)\n  - `./templates/form.jinja2`: Custom form handling\n  - `./templates/fields/StringField.jinja2`: Override field style\n- Custom jinja2 filters can be added if necessary\n  - `./filters/your_filter.py`: Python jinja2 filter (function)\n- Custom externally-referenced resources (i.e. images) can be put under the static directory\n  - `./static/img/your_image.png`: Reference in templates with `{{ url_for('static', path='img/your_image.png') %}` when expected to be displayed on the site\n  - `./static/python_file.txt`: Reference in templates with `{{ url_for('static', path='python_file.txt', public=True) }}` when expected to be available when running the appyter\n- Custom blueprints to additionally mount with flask\n  - `./blueprints/your_app/__init__.py`: `your_app = Blueprint('your_app', __name__)`\n\n\n## Creating an Appyter\n\nCreate a standard python jupyter notebook, make the first cell:\n```\n#%%appyter init\nfrom appyter import magic\nmagic.init(lambda _=globals: _())\n```\n\nNormal cells are allowed, you also have access to jinja2-rendered cells:\n```\n%%appyter {cell_type}\n```\n\nSupported cell_types:\n- `markdown`: Substitute jinja2 template variables, render as a markdown cell\n- `hide`: Substitute jinja2 template variables, show it rendered in your notebook with the default values, but when executing publicly, don't show/execute the cell.\n- `code_exec`: Substitute jinja2 template variables, render as python, show it rendered in your notebook with the default values and execute it\n- `code_eval`: Substitute jinja2 template variables, render as python, show it rendered in your notebook with the default values and execute it, \"eval\" the last line of the cell and display the result.\n\n## Discussion\nConsider the following notebook:\n\n```\n%%appyter markdown\n# {{ StringField(name='title', label='Title', default='My Title').render_value }}\n\n{{ TextField(name='description', label='Description', default='My description').render_value }}\n```\n\n```\n%%appyter code_eval\n{% set number_1 = IntField(name='number_1', label='First Number', min=0, max=10, default=5) %}\n{% set number_2 = IntField(name='number_2', label='Second Number', min=0, max=10, default=5) %}\n{% set op = ChoiceField(\n  name='operator',\n  label='Operator',\n  choices={\n    'add': '+',\n    'subtract': '-',\n    'multiply': '*',\n    'divide': '/',\n    'power': '**',\n  },\n  default='add',\n) %}\nanswer = {{ number_1 }} {{ op }} {{ number_2 }}\n```\n\nThis can be parsed in various ways:\n\n```python\n# Parse variables alone\nassert parse_variables(appyter) == {\n  'number_1': IntField(name='number_1', label='First Number', min=0, max=10, default=5),\n  'number_2': IntField(name='number_2', label='Second Number', min=0, max=10, default=5),\n  'operator': ChoiceField(\n    name='operator',\n    label='Operator',\n    choices={\n      'add': '+',\n      'subtract': '-',\n      'multiply': '*',\n      'divide': '/',\n      'power': '**'\n    },\n    default='add'\n  ),\n}\n\n# Render jupyter notebook with variables substituted\nassert render_jupyter(appyter, {\n  'title': 'Test',\n  'description': '',\n  'number_1': 0,\n  'number_2': 5,\n  'operator': 'subtract',\n}) == '''\n---\n# Test\n\n---\nanswer = 0 - 5\n---\n''' # in valid ipynb syntax\n\n# Render web UI\nassert render_html(appyter) == '''\n\u003cform id=\"notebook\"\u003e\n  Title: \u003cinput type=\"string\" name=\"title\"\u003e\u003c/input\u003e\n  Description: \u003ctextarea name=\"description\"\u003e\u003c/textarea\u003e\n  First Number: \u003cinput type=\"number\" name=\"number_1\" min=0 max=10\u003e\u003c/input\u003e\n  Second Number: \u003cinput type=\"number\" name=\"number_2\" min=0 max=10\u003e\u003c/input\u003e\n  Operator: \u003cselect name=\"operator\"\u003e\n    \u003coption value=\"add\"\u003eadd\u003c/option\u003e\n    \u003coption value=\"subtract\"\u003esubtract\u003c/option\u003e\n    \u003coption value=\"divide\"\u003edivide\u003c/option\u003e\n    \u003coption value=\"power\"\u003epower\u003c/option\u003e\n  \u003c/select\u003e\n  \u003cinput type=\"submit\" text=\"Submit\"\u003e\u003c/input\u003e\n\u003c/form\u003e\n\u003cscript src=\"./appyter.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  document.getElementById(\"notebook\").on('submit', appyter.submit)\n\u003c/script\u003e\n'''\n\n# Web UI Renderer\nassert render_html_renderer(appyter, {\n  'title': 'Test',\n  'description': '',\n  'number_1': 0,\n  'number_2': 5,\n  'operator': 'subtract',\n}) == '''\n\u003cdiv id=\"notebook\"\u003e\u003c/div\u003e\n\u003cscript src=\"./appyter.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  document.on('load', function () {\n    appyter.render(\n      document.getElementById(\"notebook\"),\n      {\n        \"title\": \"Test\",\n        \"description\": \"\",\n        \"number_1\": 0,\n        \"number_2\": 5,\n        \"operator\": \"subtract\",\n      }\n    )\n  })\n\u003c/script\u003e\n'''\n```\n\n`appyter` can be used to get these conversions, it can also be used to host standalone webapps using these mechanisms.\n\n## Development\n\n### Testing\n\n`pytest` is used for python testing. It can be invoked as follows:\n\n```bash\n# it is also prudent to test other protocols such as s3 (production) \u0026 sbfs (CAVATICA)\nexport FSSPEC_URI='memory://'\npytest --log-cli-level=DEBUG appyter\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaayanlab%2Fappyter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaayanlab%2Fappyter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaayanlab%2Fappyter/lists"}