Skip to content

Commit f988b7a

Browse files
committed
Apply the new pypackage cookiecutter template
1 parent 32077ed commit f988b7a

33 files changed

+768
-696
lines changed

.cookiecutter.json

-15
This file was deleted.

.cookiecutter/cookiecutter.json

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"template": "https://github.com/hypothesis/cookiecutters",
3+
"checkout": null,
4+
"directory": "pypackage",
5+
"ignore": ["src/h_assets/core.py", "tests/unit/h_assets/core_test.py"],
6+
"extra_context": {
7+
"name": "h-assets",
8+
"package_name": "h_assets",
9+
"slug": "h-assets",
10+
"short_description": "Pyramid views for serving collections of compiled static assets (eg. bundles of JavaScript and CSS).",
11+
"python_versions": "3.9.4,3.8.9",
12+
"github_owner": "hypothesis",
13+
"copyright_holder": "Hypothesis",
14+
"visibility": "public",
15+
"console_script": "no",
16+
"devdata": "no",
17+
"services": "no",
18+
"dependabot_pip_interval": "monthly",
19+
"__entry_point": "h-assets",
20+
"__github_url": "https://github.com/hypothesis/h-assets",
21+
"__pypi_url": "https://pypi.org/project/h-assets"
22+
}
23+
}

.cookiecutter/includes/README/head.md

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
2+
Compared to Pyramid's builtin [static asset
3+
functionality](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/assets.html)
4+
, this provides a convenient way to serve assets based on certain assumptions
5+
about how assets are generated and opinions about how they should be served:
6+
7+
- The assets are assumed to be compiled artefacts in an output directory
8+
populated by frontend build tooling, rather than source files inside the
9+
Python package. Typically Hypothesis applications use a `build` directory in
10+
the root of the repository.
11+
- Cache busting is always enabled and is done via query strings. These query
12+
strings are checked, if present, when serving a request to avoid responses
13+
being stored under the wrong keys in downstream caches.
14+
- It is assumed that compressing bytes (eg. with gzip or Brotli) will be
15+
handled by a service like Cloudflare, not the Python application.
16+
17+
Additionally h-assets provides a way to define collections (_bundles_) of
18+
assets and methods to generate cache-busted URLs for all assets in the bundle.
19+
This is useful for example to render all the `<script>` or `<style>` tags that
20+
are needed by a certain part of a site.
21+
22+
## Usage
23+
24+
Using h-assets in a Pyramid project involves three steps:
25+
26+
1. Prepare the compiled assets for use with h-assets
27+
2. During Pyramid application configuration, create an asset `Environment`
28+
to handle asset URL generation and register a view to serve assets from that
29+
environment
30+
3. Expose the URL-generation methods from the asset `Environment` to your
31+
templating system so that templates can generate asset URLs
32+
33+
### Preparing assets for use with h-assets
34+
35+
1. Set up a process to compile or copy assets from source files into an
36+
output directory. Conventionally Hypothesis projects use a folder called
37+
`build` in the repository root.
38+
2. In the output directory generate a JSON manifest file (eg. `manifest.json`)
39+
that maps asset paths to URLs with cache-busting query strings. Example content:
40+
41+
```json
42+
{
43+
"scripts/app.bundle.js": "scripts/app.bundle.js?abcdef",
44+
"scripts/vendor.bundle.js": "scripts/vendor.bundle.js?xyz123"
45+
}
46+
```
47+
48+
Any format is allowed for the cache-buster. Hypothesis projects typically use
49+
the first few characters of a hash (eg. SHA-1) of the file's contents.
50+
51+
3. Create an INI file (eg. `assets.ini`) that defines collections ("bundles")
52+
of assets that are used together. Example content:
53+
54+
```ini
55+
[bundles]
56+
57+
frontend_apps_js =
58+
scripts/browser_check.bundle.js
59+
scripts/frontend_apps.bundle.js
60+
61+
frontend_apps_css =
62+
styles/frontend_apps.css
63+
```
64+
65+
### Registering a Pyramid view to serve assets
66+
67+
To serve assets using h-assets, a Pyramid view needs to be created using the
68+
`assets_view` function.
69+
70+
In the Pyramid app configuration, define a route where the URL is a base URL
71+
followed by a `*subpath`:
72+
73+
```py
74+
def includeme(config):
75+
config.add_route("assets", "/assets/*subpath")
76+
```
77+
78+
To register the view associated with this route, first create an `Environment`
79+
to handle generation of asset URLs. Then use `assets_view` to create the view
80+
callable for use with `config.add_view`:
81+
82+
```py
83+
import os.path
84+
85+
from h_assets import Environment, assets_view
86+
87+
88+
def includeme(config):
89+
# This assumes the following repository structure:
90+
# build/ - Compiled frontend assets
91+
# manifest.json
92+
# projectname/
93+
# assets.py - This module
94+
# routes.py - Route definitions
95+
# assets.ini
96+
root_dir = os.path.dirname(__file__)
97+
98+
assets_env = Environment(
99+
assets_base_url="/assets",
100+
bundle_config_path="{root_dir}/assets.ini",
101+
manifest_path=f"{root_dir}/../build/manifest.json",
102+
)
103+
104+
# Store asset environment in registry for use in registering `asset_urls`
105+
# Jinja2 helper in `app.py`.
106+
config.registry["assets_env"] = assets_env
107+
108+
config.add_view(route_name="assets", view=assets_view(assets_env))
109+
```
110+
111+
### Referencing assets in templates
112+
113+
To get a list of asset URLs for assets in a bundle, use the `urls` method of the
114+
asset `Environment`. A common pattern is to expose these methods as global helpers
115+
in the templating environment being used to generate HTML responses. For example,
116+
in a project using `pyramid_jinja2`:
117+
118+
```py
119+
jinja2_env = config.get_jinja2_environment()
120+
jinja2_env.globals["asset_url"] = config.registry["assets_env"].url
121+
jinja2_env.globals["asset_urls"] = config.registry["assets_env"].urls
122+
```
123+
124+
Then a template can generate URLs using:
125+
126+
```jinja2
127+
{% for url in asset_urls("frontend_apps_js") %}
128+
<script async defer src="{{ url }}"></script>
129+
{% endfor %}
130+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pyramid

.coveragerc

-21
This file was deleted.

.github/dependabot.yml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "pip"
4+
directory: "/"
5+
schedule:
6+
interval: "monthly"
7+
day: "sunday"
8+
time: "00:00"
9+
timezone: "Europe/London"

.github/workflows/ci.yml

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
name: CI
2+
on:
3+
push:
4+
workflow_dispatch:
5+
schedule:
6+
- cron: '0 1 * * *'
7+
jobs:
8+
Format:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v3
12+
- name: Install Python
13+
uses: actions/setup-python@v4
14+
with:
15+
python-version: '3.9'
16+
- run: python -m pip install tox
17+
- run: tox -e checkformatting
18+
Lint:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v3
22+
- name: Install Python
23+
uses: actions/setup-python@v4
24+
with:
25+
python-version: '3.9'
26+
- run: python -m pip install tox
27+
- run: tox -e lint
28+
Tests:
29+
runs-on: ubuntu-latest
30+
strategy:
31+
matrix:
32+
python-version: ['3.9', '3.8']
33+
name: Unit tests with Python ${{ matrix.python-version }}
34+
steps:
35+
- uses: actions/checkout@v3
36+
- name: Install Python
37+
uses: actions/setup-python@v4
38+
with:
39+
python-version: ${{ matrix.python-version }}
40+
- run: python -m pip install tox
41+
- run: tox -e tests
42+
- name: Upload coverage file
43+
uses: actions/upload-artifact@v3
44+
with:
45+
name: coverage
46+
path: .coverage.*
47+
Coverage:
48+
needs: tests
49+
runs-on: ubuntu-latest
50+
steps:
51+
- uses: actions/checkout@v3
52+
- name: Install Python
53+
uses: actions/setup-python@v4
54+
with:
55+
python-version: '3.9'
56+
- name: Download coverage files
57+
uses: actions/download-artifact@v3
58+
with:
59+
name: coverage
60+
- run: python -m pip install tox
61+
- run: tox -e coverage
62+
Functests:
63+
runs-on: ubuntu-latest
64+
strategy:
65+
matrix:
66+
python-version: ['3.9', '3.8']
67+
name: Functional tests with Python ${{ matrix.python-version }}
68+
steps:
69+
- uses: actions/checkout@v3
70+
- name: Install Python
71+
uses: actions/setup-python@v4
72+
with:
73+
python-version: ${{ matrix.python-version }}
74+
- run: python -m pip install tox
75+
- run: tox -e functests

.github/workflows/pypi.yml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
name: PyPI
2+
on:
3+
release:
4+
types: [published]
5+
jobs:
6+
PyPI:
7+
uses: hypothesis/workflows/.github/workflows/pypi.yml@main
8+
secrets: inherit

0 commit comments

Comments
 (0)