Skip to content

Commit

Permalink
create docs for GH pages
Browse files Browse the repository at this point in the history
  • Loading branch information
Cutwell committed Aug 9, 2023
1 parent 769fcc9 commit 1f7b928
Show file tree
Hide file tree
Showing 9 changed files with 297 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "docs/_sass/minimal-mistakes"]
path = docs/_sass/minimal-mistakes
url = https://github.com/mmistakes/minimal-mistakes.git
13 changes: 13 additions & 0 deletions docs/Cache.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
`python-web-io` works by re-evaluating the target script after each user interaction, to progress the script to the next `input()`, etc.
This means expensive functions may be called more than once per session.
To reduce latency, a cache decorator is made available through the `python_web_io` module.
The `@cache_to_file()` decorator accepts a string argument: `file_path`, which indicates where the cache (a `.pkl` file) should be stored.

```python3
import python_web_io as io

@io.cache_to_file('cache.pickle')
def expensive_function(arg):
# Calculate the result here
return result
```
98 changes: 98 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
The appearance of generated pages are customisable via a `config.toml` file.
Create a subdirectory `/.pythonwebio` relative to were the project will be called from, and create a `config.toml` file inside.
```
.
├── app.py
├── .envrc
└── .pythonwebio/
└── config.toml
```

## Example `.envrc`
If using a `config.toml` file in a non-default location (and deploying via `uvicorn`), set the config filepath via the `PYTHON_WEB_IO_CONFIG` environment variable.

```bash
# server env vars
export PYTHON_WEB_IO_SECRET=""
export PYTHON_WEB_IO_CONFIG=".pythonwebio/config.toml" # defaults to .pythonwebio/config.toml if not set
```

## Example `config.toml`
```TOML
[script]
filepath = "app.py"
entrypoint = "main"

[page]
name = "Python web I/O App"
icon = "🎯"
css = [
"https://unpkg.com/[email protected]/normalize.css",
"https://unpkg.com/simpledotcss/simple.min.css",
]

[about]
author = "Zachary"
profile = "https://github.com/Cutwell"
description = "Generate a webpage as a GUI for a Python script, and serve from anywhere."

[project]
homepage = "https://github.com/Cutwell/python-web-io"
license = "https://github.com/Cutwell/python-web-io/blob/main/LICENSE"
issues = "https://github.com/Cutwell/python-web-io/issues/new"

[server]
debug = false
```

## CLI
`python_web_io` is designed to be run (for production and development) using `uvicorn`. Use the [uvicorn settings](https://www.uvicorn.org/settings/) docs for a reference to setup your server.

For quick testing, `python_web_io` can also be ran as a Python script. Running directly spawns a `uvicorn` server with limited config options. Test mode is designed for evaluating multiple scripts quickly without editing a `config.toml` file, e.g.: testing the `/examples` scripts.

```bash
poetry run python_web_io --script="app.py" --config=".pythonwebio/config.toml" --host="localhost" --port=8000
```

|||
|:---:|:---|
|`--script`|Override `[script]` settings (format: `<filepath>:<entrypoint>`, e.g.: `app.py:main`) (default: None).|
|`--config`|Override the `PYTHON_WEB_IO_CONFIG` environment variable and default `.pythonwebio/config.toml` config filepaths (default: `.pythonwebio/config.toml`).|
|`--host`|Set the Uvicorn server host (default: `localhost`).|
|`--port`|Set the Uvicorn server port (default: `8000`).|

## `config.toml` Documentation
### `[script]`
|||
|:---:|:---|
|`filepath`|Rather than provide a script filepath via command line, an app filepath can also be defined here.|
|`entrypoint`|Python scripts using the typical `if __name__ == '__main__': main()` will not run, as this check will fail. To resolve this, a function name can be supplied as an entrypoint for the script, and will be called to begin execution.|

### `[page]`
|||
|:---:|:---|
|`name`|Webapp name, used as the website / tab title.|
|`icon`|Webapp icon, used in bookmarks and in the tab.|
|`css`|Drop-in CSS styling is supported and encouraged to customise a web-app to user preference. A curated list of drop-in stylesheets can be found [here](https://github.com/sw-yx/spark-joy/blob/master/README.md#drop-in-css-frameworks). This option can be a list of stylesheets or a single item.|

### `[about]`
These options populate the `About` modal, accessible from the page footer.
|||
|:---:|:---|
|`author`|Author's name / online alias.|
|`profile`|Author social link, e,g.: GitHub, Twitter, etc.|
|`description`|A short description to summarise the webapp.|

### `[project]`
These options populate the `Help` modal, accessible from the page footer.
|||
|:---:|:---|
|`homepage`|A link to the project homepage, for instance on GitHub.|
|`license`|A link to the license the project is distributed under.|
|`issues`|A link to a forum / issue tracker for reporting bugs users may encounter.|

### `[server]`
These options are for the underlying FastAPI server:
|||
|:---:|:---|
|`debug`|Boolean to enable debug mode.|
19 changes: 19 additions & 0 deletions docs/Home.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# <img src="https://raw.githubusercontent.com/Cutwell/python-web-io/main/.github/logo-40x38.png" style="width:40px;padding-right:10px;margin-bottom:-8px;" alt="Sticker of a cute yellow Python snake, representing the use of the Python programming language in this project."> Python Web I/O Website / Docs
Generate a webpage as a GUI for a Python script, and serve from anywhere.

[![PyPI](https://img.shields.io/pypi/v/python-web-io?style=flat-square)](https://pypi.org/project/python-web-io/)

Install `python-web-io` locally using:
```bash
pip install python-web-io
```

Or via `poetry` using:
```bash
poetry add python_web_io
```

If evaluating / testing `python-web-io`, install dependencies for the example apps using:
```bash
poetry add python_web_io --with examples
```
106 changes: 106 additions & 0 deletions docs/IO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
`input()` and `print()` are overridden to add "magic" features.

## `print()`

* `print()` does not have any new parameters.
* String inputs are evaluated into HTML using `markdownify`, meaning you can insert arbitrary HTML simply by printing the snippet, e.g.: `print("# Title") -> <p><h1>Title</h1></p>`.
* Each `print()` statement wraps it's contents in `<p>...</p>` tags. If inlining elements, etc., print these tags together, e.g.: `print("# Title", "<span> Inline subtitle</span>") -> <p><h1>Title</h1><span> Inline subtitle</span></p>`.
* Since strings are evaluated as raw HTML, this also allows use of `<img>`, `<style>` and `<script>` tags for more advanced app control (beware allowing unfiltered user input!).

### Examples
```python
# display some text wrapped in `small` HTML tags
print("<small>This is some subtext, it's not important.</small>")
```

```html
<small>This is some subtext, it's not important.</small>
```

```python
# inject a `style` tag into the page.
print("<style>#logo{height: 32px; width: 32px}</style>")
```

```html
<style>#logo{height: 32px; width: 32px}</style>
```

```python
# display an image from an external src
# control it's appearence (size, etc.) using the `logo` CSS id
print("<img id='logo' src='https://cdn2.iconfinder.com/data/icons/activity-5/50/1F3A8-artist-palette-1024.png'>")
```

```html
<img id='logo' src='https://cdn2.iconfinder.com/data/icons/activity-5/50/1F3A8-artist-palette-1024.png'>
```

## `input()`

* `input()` has several new (_optional_) parameters for controlling what type of input is displayed.
* By default, a textbox is used.
* By setting `type`, the `<input>` tag can be customised (see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input#input_types for a comprehensive list of supported types).
* By setting `options` (expecting a `list`) the `prompt` is used as a `<label>` and multiple `<input>`s of `type` (recommended types are `button`, `radio`) are created. Return value is whichever item from `option` list is selected.
* By setting `attrs`, you can set additional attributes, such as `class` and `id`. Pass a dictionary in the format `{attribute: value}`, e.g.: `{'id': "myelement", 'class': "myclass"}`.

### Custom attribute examples
```python
# return a number between 1-100
input("Pick a number between 1-100", type='range', attrs={'min': 0, 'max': 100})
```

```html
<label>Pick a number between 1-100</label>
<input type='range' min=0 max=100>
```

```python
# return a phone number, with client side validation for a correct pattern
input("Enter your telephone number", type='tel', attrs={'pattern': "[0-9]{3}-[0-9]{2}-[0-9]{3}"})
```

```html
<label>Enter your telephone number</label>
<input type='tel' pattern=[0-9]{3}-[0-9]{2}-[0-9]{3}>
```

## Custom option examples
For input types such as `button`, `radio` and `checkbox`, multiple inputs can be rendered at once. This is an optional argument for all inputs, but will only have an effect for these listed input types.

`button` and `radio` inputs can return a single option, or `None`, e.g.:
```python
# display 2 buttons
# return the selected option (or None if `submit` button pressed instead)
input("Do you like watermelon?", type='button', options=['yes', 'no'])
```

```html
<label>Do you like watermelon?</label>
<input type='submit' value='yes'> <input type='button' value='no'>
```

`checkbox` inputs can return any combination of options, or `None`, e.g.:
```python
# display 2 checkbox options
# if more than 1 item selected, return selected items as a list (or None if `submit` button pressed instead)
input("Which Sci-fi series do you like?", type='checkbox', options=['star wars', 'star trek'])
```

```html
<label>Which Sci-fi series do you like?</label>
<input type='checkbox' value='star wars'> <input type='checkbox' value='star trek'>
```

If an input is required (e.g.: `None` is not acceptable), set the `required` attribute, which will prevent form submission until an option is selected. E.g.:
```python
# display radio options (only 1 can be selected)
# return the selected option (`required` is set, so an option must be selected)
# if `submit` is pressed, the form will prompt the user to make a selection before being allowed to submit
input("What's your thoughts on Marmite?", type='radio', options=['love it', 'hate it'], attrs={'required': True})
```

```html
<label>What's your thoughts on Marmite?</label>
<input type='radio' value='love it' required> <input type='radio' value='hate it' required>
```
40 changes: 40 additions & 0 deletions docs/Quickstart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
After installing the project, some environment setup is required:

## Required setup
Create an `app.py` file containing your script, a `config.toml` setting the script filepath and entrypoint, and an `.envrc` file to store project secrets. (Note: remember to add `.envrc` to your `.gitignore`). Look for example apps in [`/examples`](https://github.com/Cutwell/python-web-io/tree/main/python-web-io/examples).
```
.
├── .envrc
├── config.toml
└── app.py
```

Create the following simple `config.toml`:
```toml
[script]
filepath = "app.py"
entrypoint = "main" # if your app has no entrypoint, remove this parameter.
```

Add the following environment variables to your `.envrc`. (Note: remember to activate the `.envrc` in your terminal using `direnv allow`)
```bash
# server env vars
export PYTHON_WEB_IO_SECRET=""
export PYTHON_WEB_IO_CONFIG="config.toml" # defaults to .pythonwebio/config.toml if not set
```

Generate a random key for `PYTHON_WEB_IO_SECRET` using this python command line snippet:
```bash
python -c 'import secrets; print(secrets.token_hex())'
```

If testing `wikipedia_assistant.py`, an OpenAI API key will also need to be set.
```bash
export OPENAI_API_KEY=""
```

## Running the webapp
We recommend running `python_web_io` using `uvicorn`:
```bash
poetry run uvicorn python_web_io.main:app
```
13 changes: 13 additions & 0 deletions docs/Serving local files.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
If you wish to serve local files, such as custom `.css` stylesheets or images, they will need to be placed in the `./static` folder, relative to the project root.
```
.
├── .envrc
├── app.py
├── .pythonwebio/
│ └── config.toml
└── static/
```

Files stored here can be referenced using a `/static/image.png`-like URL.

For security reasons (to prevent a malicious user accessing the entire server using a few `../../`), the underlying `FastAPI` server will not serve local files from outside this directory.
4 changes: 4 additions & 0 deletions docs/_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
remote_theme: "mmistakes/minimal-mistakes"
plugins:
- jekyll-seo-tag
- jekyll-remote-theme
1 change: 1 addition & 0 deletions docs/_sass/minimal-mistakes
Submodule minimal-mistakes added at 8a67ce

0 comments on commit 1f7b928

Please sign in to comment.