# Canonical Webteam Flask-Base
Flask extension that applies common configurations to all of webteam's flask apps.
## Usage
```python3
from canonicalwebteam.flask_base.app import FlaskBase
app = FlaskBase(__name__, "app.name")
```
Or:
```python3
from canonicalwebteam.flask_base.app import FlaskBase
app = FlaskBase(
__name__,
"app.name",
template_404="404.html",
template_500="500.html",
favicon_url="/static/favicon.ico",
)
```
## Local development
For local development, it's best to test this module with one of our website projects like [ubuntu.com](https://github.com/canonical-web-and-design/ubuntu.com/). For more information, follow [this guide (internal only)](https://discourse.canonical.com/t/how-to-run-our-python-modules-for-local-development/308).
## Features
### Per route metrics
If a statsd-client is configured (which is enabled by default with 12f apps), FlaskBase will automatically add per route metrics. Including error counts, request counts, and response times.
### ProxyFix
FlaskBase includes [ProxyFix](https://werkzeug.palletsprojects.com/en/3.0.x/middleware/proxy_fix/) to avoid SSL stripping on redirects.
### Redirects and deleted paths
FlaskBase uses [yaml-responses](https://github.com/canonical-web-and-design/canonicalwebteam.yaml-responses) to allow easy configuration of redirects and return of deleted responses, by creating `redirects.yaml`, `permanent-redirects.yaml` and `deleted.yaml` in the site root directory.
### Error templates
`FlaskBase` can optionally use templates to generate the `404` and `500` error responses:
```python3
app = FlaskBase(
__name__,
"app.name",
template_404="404.html",
template_500="500.html",
)
```
This will lead to e.g. `http://localhost/non-existent-path` returning a `404` status with the contents of `templates/404.html`.
### Redirect /favicon.ico
`FlaskBase` can optionally provide redirects for the commonly queried paths `/favicon.ico`, `/robots.txt` and `/humans.txt` to sensible locations:
```python3
from canonicalwebteam.flask_base.app import FlaskBase
app = FlaskBase(
__name__,
"app.name",
template_404="404.html",
template_500="500.html",
favicon_url="/static/favicon.ico",
robots_url="/static/robots.txt",
humans_url="/static/humans.txt"
)
```
This will lead to e.g. `http://localhost/favicon.ico` returning a `302` redirect to `http://localhost/static/favicon.ico`.
### Clear trailing slashes
Automatically clears all trailing slashes from all routes.
### Jinja2 helpers
You get two jinja2 helpers to use in your templates from flask-base:
- `now` is a function that outputs the current date in the passed [format](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes) - `{{ now('%Y') }}` -> `YYYY`
- `versioned_static` is a function that fingerprints the passed asset - `{{ versioned_static('asset.js') }}` -> `static/asset?v=asset-hash`
### HTTP headers
You get the following headers automatically set:
- `X-Content-Type-Options: NOSNIFF`
- `Permissions-Policy: interest-cohort=()`
- `X-Frame-Options: SAMEORIGIN`, which can be excluded with `exclude_xframe_options_header` decorator
- `Cache-Control` if `response.cache_control.*` not set and according to static asset versioning (see `versioned_static` above)
### `security.txt`, `robots.txt` and `humans.txt`
If you create a `security.txt`, `robots.txt` or `humans.txt` in the root of your project, these will be served at `/.well-known/security.txt`, `/robots.txt` and `/humans.txt` respectively.
### `/_status/check` endpoint
Automatically adds the `/_status/check` endpoint which is used by content-caches for backend health checking or e.g. by k8s for checking the status of pods.
### Custom gunicorn gevent worker
Included is a custom gunicorn gevent worker designed to handle SIGINT and SIGTERM gracefully, by closing all client connections and logging the stacktrace before exiting.
#### Usage
Run gunicorn in the usual way, but specify the worker class as LogWorker.
```bash
gunicorn webapp.app:app \
-k canonicalwebteam.flask_base.worker.LogWorker
```
### Planned features
- Add support for open telemetry tracing. Using opentelemetry-instrumentation-flask and opentelemetry-exporter-otlp.
## Tests
To run the tests execute `SECRET_KEY=fake python3 -m unittest discover tests`.
Raw data
{
"_id": null,
"home_page": "https://github.com/canonical-web-and-design/canonicalwebteam.flask-base",
"name": "canonicalwebteam.flask-base",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": null,
"author": "Canonical webteam",
"author_email": "webteam@canonical.com",
"download_url": "https://files.pythonhosted.org/packages/a0/ac/f9e12ec89fc35304e5ae10ef5c26b79d607289b07f5d5e072fb26585657e/canonicalwebteam_flask_base-3.0.0.tar.gz",
"platform": null,
"description": "# Canonical Webteam Flask-Base\n\nFlask extension that applies common configurations to all of webteam's flask apps.\n\n## Usage\n\n```python3\nfrom canonicalwebteam.flask_base.app import FlaskBase\n\napp = FlaskBase(__name__, \"app.name\")\n```\n\nOr:\n\n```python3\nfrom canonicalwebteam.flask_base.app import FlaskBase\n\napp = FlaskBase(\n __name__,\n \"app.name\",\n template_404=\"404.html\",\n template_500=\"500.html\",\n favicon_url=\"/static/favicon.ico\",\n)\n```\n\n## Local development\n\nFor local development, it's best to test this module with one of our website projects like [ubuntu.com](https://github.com/canonical-web-and-design/ubuntu.com/). For more information, follow [this guide (internal only)](https://discourse.canonical.com/t/how-to-run-our-python-modules-for-local-development/308).\n\n## Features\n\n### Per route metrics\n\nIf a statsd-client is configured (which is enabled by default with 12f apps), FlaskBase will automatically add per route metrics. Including error counts, request counts, and response times.\n\n\n### ProxyFix\n\nFlaskBase includes [ProxyFix](https://werkzeug.palletsprojects.com/en/3.0.x/middleware/proxy_fix/) to avoid SSL stripping on redirects.\n\n### Redirects and deleted paths\n\nFlaskBase uses [yaml-responses](https://github.com/canonical-web-and-design/canonicalwebteam.yaml-responses) to allow easy configuration of redirects and return of deleted responses, by creating `redirects.yaml`, `permanent-redirects.yaml` and `deleted.yaml` in the site root directory.\n\n### Error templates\n\n`FlaskBase` can optionally use templates to generate the `404` and `500` error responses:\n\n```python3\napp = FlaskBase(\n __name__,\n \"app.name\",\n template_404=\"404.html\",\n template_500=\"500.html\",\n)\n```\n\nThis will lead to e.g. `http://localhost/non-existent-path` returning a `404` status with the contents of `templates/404.html`.\n\n### Redirect /favicon.ico\n\n`FlaskBase` can optionally provide redirects for the commonly queried paths `/favicon.ico`, `/robots.txt` and `/humans.txt` to sensible locations:\n\n```python3\nfrom canonicalwebteam.flask_base.app import FlaskBase\n\napp = FlaskBase(\n __name__,\n \"app.name\",\n template_404=\"404.html\",\n template_500=\"500.html\",\n favicon_url=\"/static/favicon.ico\",\n robots_url=\"/static/robots.txt\",\n humans_url=\"/static/humans.txt\"\n)\n```\n\nThis will lead to e.g. `http://localhost/favicon.ico` returning a `302` redirect to `http://localhost/static/favicon.ico`.\n\n### Clear trailing slashes\n\nAutomatically clears all trailing slashes from all routes.\n\n### Jinja2 helpers\n\nYou get two jinja2 helpers to use in your templates from flask-base:\n\n- `now` is a function that outputs the current date in the passed [format](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes) - `{{ now('%Y') }}` -> `YYYY`\n- `versioned_static` is a function that fingerprints the passed asset - `{{ versioned_static('asset.js') }}` -> `static/asset?v=asset-hash`\n\n### HTTP headers\n\nYou get the following headers automatically set:\n\n- `X-Content-Type-Options: NOSNIFF`\n- `Permissions-Policy: interest-cohort=()`\n- `X-Frame-Options: SAMEORIGIN`, which can be excluded with `exclude_xframe_options_header` decorator\n- `Cache-Control` if `response.cache_control.*` not set and according to static asset versioning (see `versioned_static` above)\n\n### `security.txt`, `robots.txt` and `humans.txt`\n\nIf you create a `security.txt`, `robots.txt` or `humans.txt` in the root of your project, these will be served at `/.well-known/security.txt`, `/robots.txt` and `/humans.txt` respectively.\n\n### `/_status/check` endpoint\n\nAutomatically adds the `/_status/check` endpoint which is used by content-caches for backend health checking or e.g. by k8s for checking the status of pods.\n\n### Custom gunicorn gevent worker\n\nIncluded is a custom gunicorn gevent worker designed to handle SIGINT and SIGTERM gracefully, by closing all client connections and logging the stacktrace before exiting.\n\n#### Usage\nRun gunicorn in the usual way, but specify the worker class as LogWorker.\n\n```bash\ngunicorn webapp.app:app \\\n -k canonicalwebteam.flask_base.worker.LogWorker\n```\n\n### Planned features\n\n- Add support for open telemetry tracing. Using opentelemetry-instrumentation-flask and opentelemetry-exporter-otlp.\n\n## Tests\n\nTo run the tests execute `SECRET_KEY=fake python3 -m unittest discover tests`.\n\n",
"bugtrack_url": null,
"license": null,
"summary": "Flask extension that applies common configurationsto all of webteam's flask apps.",
"version": "3.0.0",
"project_urls": {
"Homepage": "https://github.com/canonical-web-and-design/canonicalwebteam.flask-base"
},
"split_keywords": [],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "75d01ce2f034fb1a574457c77aae639715eb152cb7edbf63fdcdda080e7d46bb",
"md5": "2d34762c685631aae041aba4ecb3844d",
"sha256": "9d9b4d9ea0f4c092886b2070e530f3763db468df80cf5ac7ac2b25e78a2e2ec1"
},
"downloads": -1,
"filename": "canonicalwebteam_flask_base-3.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "2d34762c685631aae041aba4ecb3844d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 21573,
"upload_time": "2025-08-01T07:54:35",
"upload_time_iso_8601": "2025-08-01T07:54:35.977005Z",
"url": "https://files.pythonhosted.org/packages/75/d0/1ce2f034fb1a574457c77aae639715eb152cb7edbf63fdcdda080e7d46bb/canonicalwebteam_flask_base-3.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "a0acf9e12ec89fc35304e5ae10ef5c26b79d607289b07f5d5e072fb26585657e",
"md5": "4cb8598b7c4d11cde07dede859821fca",
"sha256": "0c83d258fdb39e963799f6b7283fa3f28705662cb4f23428eb934acbdc7ab193"
},
"downloads": -1,
"filename": "canonicalwebteam_flask_base-3.0.0.tar.gz",
"has_sig": false,
"md5_digest": "4cb8598b7c4d11cde07dede859821fca",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 19855,
"upload_time": "2025-08-01T07:54:37",
"upload_time_iso_8601": "2025-08-01T07:54:37.170660Z",
"url": "https://files.pythonhosted.org/packages/a0/ac/f9e12ec89fc35304e5ae10ef5c26b79d607289b07f5d5e072fb26585657e/canonicalwebteam_flask_base-3.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-01 07:54:37",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "canonical-web-and-design",
"github_project": "canonicalwebteam.flask-base",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "canonicalwebteam.flask-base"
}