billwright 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- billwright-0.2.0/.github/workflows/ci.yml +135 -0
- billwright-0.2.0/.github/workflows/release.yml +92 -0
- billwright-0.2.0/.gitignore +259 -0
- billwright-0.2.0/.pre-commit-config.yaml +41 -0
- billwright-0.2.0/AGENTS.md +344 -0
- billwright-0.2.0/CHANGELOG.md +197 -0
- billwright-0.2.0/CLAUDE.md +5 -0
- billwright-0.2.0/GEMINI.md +5 -0
- billwright-0.2.0/LICENSE +201 -0
- billwright-0.2.0/Makefile +100 -0
- billwright-0.2.0/NOTICE +31 -0
- billwright-0.2.0/PKG-INFO +514 -0
- billwright-0.2.0/README.md +492 -0
- billwright-0.2.0/docs/assets/banner-dark.svg +102 -0
- billwright-0.2.0/docs/assets/banner-light.svg +99 -0
- billwright-0.2.0/docs/example-invoice.png +0 -0
- billwright-0.2.0/docs/example-statement.png +0 -0
- billwright-0.2.0/example/bills/2026/RE-26001.toml +35 -0
- billwright-0.2.0/example/bills/2026/RE-26002.toml +30 -0
- billwright-0.2.0/example/brand.toml +30 -0
- billwright-0.2.0/example/clients/example-institute.toml +22 -0
- billwright-0.2.0/example/company.toml +41 -0
- billwright-0.2.0/example/rates.toml +9 -0
- billwright-0.2.0/example/years/2025.toml +11 -0
- billwright-0.2.0/example/years/2026.toml +47 -0
- billwright-0.2.0/pyproject.toml +103 -0
- billwright-0.2.0/skills/README.md +60 -0
- billwright-0.2.0/skills/brand-profile/SKILL.md +125 -0
- billwright-0.2.0/skills/brand-profile/references/deriving-tokens.md +77 -0
- billwright-0.2.0/skills/swiss-billing-generator/SKILL.md +152 -0
- billwright-0.2.0/skills/swiss-billing-generator/references/architecture.md +141 -0
- billwright-0.2.0/skills/swiss-billing-generator/references/swiss-rules.md +81 -0
- billwright-0.2.0/skills/swiss-billing-generator/references/weasyprint.md +118 -0
- billwright-0.2.0/src/billwright/__init__.py +12 -0
- billwright-0.2.0/src/billwright/__main__.py +4 -0
- billwright-0.2.0/src/billwright/assets/fonts/Inter-Medium.otf +0 -0
- billwright-0.2.0/src/billwright/assets/fonts/Inter-Regular.otf +0 -0
- billwright-0.2.0/src/billwright/assets/fonts/Inter-SemiBold.otf +0 -0
- billwright-0.2.0/src/billwright/assets/fonts/OFL.txt +92 -0
- billwright-0.2.0/src/billwright/audit.py +101 -0
- billwright-0.2.0/src/billwright/doctor.py +248 -0
- billwright-0.2.0/src/billwright/fonts.py +51 -0
- billwright-0.2.0/src/billwright/i18n.py +187 -0
- billwright-0.2.0/src/billwright/load.py +385 -0
- billwright-0.2.0/src/billwright/main.py +341 -0
- billwright-0.2.0/src/billwright/mcp_server.py +441 -0
- billwright-0.2.0/src/billwright/model.py +262 -0
- billwright-0.2.0/src/billwright/money.py +64 -0
- billwright-0.2.0/src/billwright/native.py +90 -0
- billwright-0.2.0/src/billwright/numbering.py +62 -0
- billwright-0.2.0/src/billwright/paths.py +164 -0
- billwright-0.2.0/src/billwright/qr.py +64 -0
- billwright-0.2.0/src/billwright/render.py +270 -0
- billwright-0.2.0/src/billwright/scaffold.py +206 -0
- billwright-0.2.0/src/billwright/scan.py +334 -0
- billwright-0.2.0/src/billwright/statement.py +122 -0
- billwright-0.2.0/src/billwright/styles/bill.css +260 -0
- billwright-0.2.0/src/billwright/styles/print.css +67 -0
- billwright-0.2.0/src/billwright/styles/statement.css +167 -0
- billwright-0.2.0/src/billwright/styles/tokens.css +103 -0
- billwright-0.2.0/src/billwright/templates/_wordmark.html.j2 +16 -0
- billwright-0.2.0/src/billwright/templates/base.html.j2 +17 -0
- billwright-0.2.0/src/billwright/templates/bill.html.j2 +156 -0
- billwright-0.2.0/src/billwright/templates/figures.html.j2 +81 -0
- billwright-0.2.0/src/billwright/templates/statement.html.j2 +110 -0
- billwright-0.2.0/tests/conftest.py +36 -0
- billwright-0.2.0/tests/test_audit.py +84 -0
- billwright-0.2.0/tests/test_doctor.py +135 -0
- billwright-0.2.0/tests/test_fonts.py +53 -0
- billwright-0.2.0/tests/test_load.py +150 -0
- billwright-0.2.0/tests/test_mcp.py +146 -0
- billwright-0.2.0/tests/test_money.py +54 -0
- billwright-0.2.0/tests/test_numbering.py +38 -0
- billwright-0.2.0/tests/test_overrides.py +120 -0
- billwright-0.2.0/tests/test_paths.py +105 -0
- billwright-0.2.0/tests/test_profile.py +180 -0
- billwright-0.2.0/tests/test_qr.py +51 -0
- billwright-0.2.0/tests/test_render.py +165 -0
- billwright-0.2.0/tests/test_reproducible.py +31 -0
- billwright-0.2.0/tests/test_scaffold.py +137 -0
- billwright-0.2.0/tests/test_scan.py +336 -0
- billwright-0.2.0/tests/test_statement.py +138 -0
- billwright-0.2.0/uv.lock +2671 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
# Runs against `example/` only. The private profile does not exist on a runner,
|
|
4
|
+
# and a workflow that needed it would be a workflow that one day leaked it.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [main]
|
|
9
|
+
pull_request:
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
17
|
+
cancel-in-progress: true
|
|
18
|
+
|
|
19
|
+
env:
|
|
20
|
+
FORCE_COLOR: "1"
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
linux:
|
|
24
|
+
name: ubuntu / python ${{ matrix.python-version }}
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
strategy:
|
|
27
|
+
fail-fast: false
|
|
28
|
+
matrix:
|
|
29
|
+
# Every version `requires-python` claims to support. A claim nothing
|
|
30
|
+
# exercises is a claim that is wrong sooner or later.
|
|
31
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
32
|
+
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v5
|
|
35
|
+
|
|
36
|
+
# WeasyPrint binds Pango and Cairo through cffi. Without these every
|
|
37
|
+
# rendering test fails on `cannot load library 'libgobject-2.0-0'`.
|
|
38
|
+
- name: Install native libraries
|
|
39
|
+
run: |
|
|
40
|
+
sudo apt-get update
|
|
41
|
+
sudo apt-get install -y --no-install-recommends \
|
|
42
|
+
libpango-1.0-0 libpangoft2-1.0-0 libharfbuzz0b libcairo2 poppler-utils
|
|
43
|
+
|
|
44
|
+
- uses: astral-sh/setup-uv@v7
|
|
45
|
+
with:
|
|
46
|
+
enable-cache: true
|
|
47
|
+
python-version: ${{ matrix.python-version }}
|
|
48
|
+
|
|
49
|
+
# --locked, so a stale uv.lock fails the build rather than being
|
|
50
|
+
# silently resolved around.
|
|
51
|
+
- name: Install
|
|
52
|
+
run: uv sync --locked --all-extras --dev
|
|
53
|
+
|
|
54
|
+
- name: Lint
|
|
55
|
+
run: |
|
|
56
|
+
uv run ruff check --output-format=github .
|
|
57
|
+
uv run ruff format --check .
|
|
58
|
+
|
|
59
|
+
- name: Types
|
|
60
|
+
run: uv run mypy
|
|
61
|
+
|
|
62
|
+
# The leak guard. On a clone there is no private profile, so this is the
|
|
63
|
+
# structural layer: anything shaped like an IBAN, a Swiss UID, an email
|
|
64
|
+
# address or a phone number in a tracked file fails the build.
|
|
65
|
+
- name: Scan for private values
|
|
66
|
+
run: uv run billwright scan
|
|
67
|
+
|
|
68
|
+
- name: Test
|
|
69
|
+
run: uv run pytest -q
|
|
70
|
+
|
|
71
|
+
- name: Numbering and sanity checks
|
|
72
|
+
run: uv run billwright check
|
|
73
|
+
|
|
74
|
+
- name: Render the example documents
|
|
75
|
+
run: |
|
|
76
|
+
uv run billwright bill RE-26001
|
|
77
|
+
uv run billwright statement 2026
|
|
78
|
+
|
|
79
|
+
# So a human can look at a render without cloning anything. Rule 6:
|
|
80
|
+
# structural checks pass happily while the layout is broken.
|
|
81
|
+
- name: Upload rendered PDFs
|
|
82
|
+
if: matrix.python-version == '3.13'
|
|
83
|
+
uses: actions/upload-artifact@v4
|
|
84
|
+
with:
|
|
85
|
+
name: example-documents
|
|
86
|
+
path: out/*.pdf
|
|
87
|
+
if-no-files-found: error
|
|
88
|
+
|
|
89
|
+
macos:
|
|
90
|
+
name: macos / python 3.13
|
|
91
|
+
runs-on: macos-latest
|
|
92
|
+
steps:
|
|
93
|
+
- uses: actions/checkout@v5
|
|
94
|
+
|
|
95
|
+
# Worth a separate job: macOS is the platform this is developed on, and
|
|
96
|
+
# the only one that exercises native.py's dyld repair.
|
|
97
|
+
- name: Install native libraries
|
|
98
|
+
run: brew install pango
|
|
99
|
+
|
|
100
|
+
- uses: astral-sh/setup-uv@v7
|
|
101
|
+
with:
|
|
102
|
+
enable-cache: true
|
|
103
|
+
python-version: "3.13"
|
|
104
|
+
|
|
105
|
+
- name: Install
|
|
106
|
+
run: uv sync --locked --all-extras --dev
|
|
107
|
+
|
|
108
|
+
- name: Test
|
|
109
|
+
run: make test
|
|
110
|
+
|
|
111
|
+
- name: Render the example bill through the CLI
|
|
112
|
+
run: uv run billwright bill RE-26001
|
|
113
|
+
|
|
114
|
+
hooks:
|
|
115
|
+
name: pre-commit
|
|
116
|
+
runs-on: ubuntu-latest
|
|
117
|
+
steps:
|
|
118
|
+
- uses: actions/checkout@v5
|
|
119
|
+
|
|
120
|
+
- name: Install native libraries
|
|
121
|
+
run: |
|
|
122
|
+
sudo apt-get update
|
|
123
|
+
sudo apt-get install -y --no-install-recommends \
|
|
124
|
+
libpango-1.0-0 libpangoft2-1.0-0 libharfbuzz0b libcairo2
|
|
125
|
+
|
|
126
|
+
- uses: astral-sh/setup-uv@v7
|
|
127
|
+
with:
|
|
128
|
+
enable-cache: true
|
|
129
|
+
python-version: "3.13"
|
|
130
|
+
|
|
131
|
+
- name: Install
|
|
132
|
+
run: uv sync --locked --all-extras --dev
|
|
133
|
+
|
|
134
|
+
- name: Run every hook over every file
|
|
135
|
+
run: uv run pre-commit run --all-files --show-diff-on-failure
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Publishes to PyPI when a `v*` tag is pushed.
|
|
4
|
+
#
|
|
5
|
+
# There is no token anywhere — not in the repository, not in a secret, not on
|
|
6
|
+
# anyone's laptop. PyPI's trusted publishing exchanges this workflow's OIDC
|
|
7
|
+
# identity for a credential that lasts minutes. That makes three things in here
|
|
8
|
+
# load-bearing rather than decorative, and PyPI matches on all of them: the
|
|
9
|
+
# filename `release.yml`, the `pypi` environment, and `id-token: write`. Rename
|
|
10
|
+
# any of them and the upload fails with a 403 that does not explain itself.
|
|
11
|
+
|
|
12
|
+
on:
|
|
13
|
+
push:
|
|
14
|
+
tags: ["v*"]
|
|
15
|
+
workflow_dispatch:
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
# Build and publish are separate jobs on purpose. Only `publish` can mint a
|
|
22
|
+
# PyPI credential, and all it does is upload files it did not produce; the
|
|
23
|
+
# build — which runs hatchling and the dependency tree — never holds one.
|
|
24
|
+
build:
|
|
25
|
+
name: build and check the artifacts
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v5
|
|
29
|
+
|
|
30
|
+
- uses: astral-sh/setup-uv@v7
|
|
31
|
+
with:
|
|
32
|
+
enable-cache: true
|
|
33
|
+
python-version: "3.13"
|
|
34
|
+
|
|
35
|
+
- name: The tag must be the version being published
|
|
36
|
+
run: |
|
|
37
|
+
tag="${GITHUB_REF_NAME#v}"
|
|
38
|
+
version=$(uv run --no-project python -c \
|
|
39
|
+
'import tomllib,pathlib; print(tomllib.loads(pathlib.Path("pyproject.toml").read_text())["project"]["version"])')
|
|
40
|
+
if [ "$tag" != "$version" ]; then
|
|
41
|
+
echo "tag $GITHUB_REF_NAME does not match pyproject version $version" >&2
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
echo "publishing $version"
|
|
45
|
+
|
|
46
|
+
- name: Build
|
|
47
|
+
run: uv build
|
|
48
|
+
|
|
49
|
+
# The regression that 0.2.0 exists to fix: the typeface was not in the
|
|
50
|
+
# wheel, so an installed copy typeset client invoices in a substituted
|
|
51
|
+
# font and said nothing. A release that ships that again is worse than no
|
|
52
|
+
# release, and this is the last point at which it is cheap to notice.
|
|
53
|
+
- name: The wheel must carry the fonts and the manual
|
|
54
|
+
run: |
|
|
55
|
+
wheel=$(ls dist/*.whl)
|
|
56
|
+
for entry in \
|
|
57
|
+
billwright/assets/fonts/Inter-Regular.otf \
|
|
58
|
+
billwright/assets/fonts/Inter-Medium.otf \
|
|
59
|
+
billwright/assets/fonts/Inter-SemiBold.otf \
|
|
60
|
+
billwright/assets/fonts/OFL.txt \
|
|
61
|
+
billwright/AGENTS.md
|
|
62
|
+
do
|
|
63
|
+
unzip -l "$wheel" | grep -q "$entry" || { echo "missing from wheel: $entry" >&2; exit 1; }
|
|
64
|
+
done
|
|
65
|
+
echo "wheel contents verified"
|
|
66
|
+
|
|
67
|
+
- uses: actions/upload-artifact@v4
|
|
68
|
+
with:
|
|
69
|
+
name: dist
|
|
70
|
+
path: dist/
|
|
71
|
+
if-no-files-found: error
|
|
72
|
+
|
|
73
|
+
publish:
|
|
74
|
+
name: publish to PyPI
|
|
75
|
+
needs: build
|
|
76
|
+
runs-on: ubuntu-latest
|
|
77
|
+
environment: pypi
|
|
78
|
+
permissions:
|
|
79
|
+
id-token: write # the whole mechanism; without it there is no credential
|
|
80
|
+
steps:
|
|
81
|
+
- uses: astral-sh/setup-uv@v7
|
|
82
|
+
|
|
83
|
+
- uses: actions/download-artifact@v4
|
|
84
|
+
with:
|
|
85
|
+
name: dist
|
|
86
|
+
path: dist/
|
|
87
|
+
|
|
88
|
+
# `always`, not `automatic`: if trusted publishing is unavailable for any
|
|
89
|
+
# reason, fail rather than quietly looking for a token that should not
|
|
90
|
+
# exist.
|
|
91
|
+
- name: Publish
|
|
92
|
+
run: uv publish --trusted-publishing always
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
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
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
# poetry.lock
|
|
109
|
+
# poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
# pdm.lock
|
|
116
|
+
# pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
# pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# Redis
|
|
135
|
+
*.rdb
|
|
136
|
+
*.aof
|
|
137
|
+
*.pid
|
|
138
|
+
|
|
139
|
+
# RabbitMQ
|
|
140
|
+
mnesia/
|
|
141
|
+
rabbitmq/
|
|
142
|
+
rabbitmq-data/
|
|
143
|
+
|
|
144
|
+
# ActiveMQ
|
|
145
|
+
activemq-data/
|
|
146
|
+
|
|
147
|
+
# SageMath parsed files
|
|
148
|
+
*.sage.py
|
|
149
|
+
|
|
150
|
+
# Environments
|
|
151
|
+
.env
|
|
152
|
+
.envrc
|
|
153
|
+
.venv
|
|
154
|
+
env/
|
|
155
|
+
venv/
|
|
156
|
+
ENV/
|
|
157
|
+
env.bak/
|
|
158
|
+
venv.bak/
|
|
159
|
+
|
|
160
|
+
# Spyder project settings
|
|
161
|
+
.spyderproject
|
|
162
|
+
.spyproject
|
|
163
|
+
|
|
164
|
+
# Rope project settings
|
|
165
|
+
.ropeproject
|
|
166
|
+
|
|
167
|
+
# mkdocs documentation
|
|
168
|
+
/site
|
|
169
|
+
|
|
170
|
+
# mypy
|
|
171
|
+
.mypy_cache/
|
|
172
|
+
.dmypy.json
|
|
173
|
+
dmypy.json
|
|
174
|
+
|
|
175
|
+
# Pyre type checker
|
|
176
|
+
.pyre/
|
|
177
|
+
|
|
178
|
+
# pytype static type analyzer
|
|
179
|
+
.pytype/
|
|
180
|
+
|
|
181
|
+
# Cython debug symbols
|
|
182
|
+
cython_debug/
|
|
183
|
+
|
|
184
|
+
# PyCharm
|
|
185
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
186
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
187
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
188
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
189
|
+
# .idea/
|
|
190
|
+
|
|
191
|
+
# Abstra
|
|
192
|
+
# Abstra is an AI-powered process automation framework.
|
|
193
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
194
|
+
# Learn more at https://abstra.io/docs
|
|
195
|
+
.abstra/
|
|
196
|
+
|
|
197
|
+
# Visual Studio Code
|
|
198
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
199
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
200
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
201
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
202
|
+
# .vscode/
|
|
203
|
+
# Temporary file for partial code execution
|
|
204
|
+
tempCodeRunnerFile.py
|
|
205
|
+
|
|
206
|
+
# Ruff stuff:
|
|
207
|
+
.ruff_cache/
|
|
208
|
+
|
|
209
|
+
# PyPI configuration file
|
|
210
|
+
.pypirc
|
|
211
|
+
|
|
212
|
+
# Marimo
|
|
213
|
+
marimo/_static/
|
|
214
|
+
marimo/_lsp/
|
|
215
|
+
__marimo__/
|
|
216
|
+
|
|
217
|
+
# Streamlit
|
|
218
|
+
.streamlit/secrets.toml
|
|
219
|
+
|
|
220
|
+
# Agent working notes — local only, never version controlled.
|
|
221
|
+
# Build plans, handovers and scratch thinking. Company facts may appear here.
|
|
222
|
+
notes/
|
|
223
|
+
|
|
224
|
+
# Rendered drafts. The archive/ copies are the record; out/ is scratch.
|
|
225
|
+
out/
|
|
226
|
+
|
|
227
|
+
# ---------------------------------------------------------------------------
|
|
228
|
+
# The private surface. Everything company-specific lives here and nowhere else:
|
|
229
|
+
# the engine in src/ holds no company values, so these are the only paths that
|
|
230
|
+
# must never reach a public remote.
|
|
231
|
+
#
|
|
232
|
+
# data/ the active company profile — issuer, IBAN, clients,
|
|
233
|
+
# rates, issued bills, brand tokens
|
|
234
|
+
# archive/ the PDFs actually sent, retained 10 years (OR 958f)
|
|
235
|
+
# assets/reference/ source documents from clients
|
|
236
|
+
#
|
|
237
|
+
# No .gitkeep placeholders here — an empty but present data/ would be selected
|
|
238
|
+
# by resolve_profile() and then fail, instead of falling through to example/.
|
|
239
|
+
# Directories are created on demand by the code that writes into them.
|
|
240
|
+
# ---------------------------------------------------------------------------
|
|
241
|
+
/data/
|
|
242
|
+
/archive/
|
|
243
|
+
assets/reference/
|
|
244
|
+
|
|
245
|
+
# Company-specific skill: client names, VAT status, rate, business structure.
|
|
246
|
+
# Ignored so it cannot be swept into a commit while its fate is undecided —
|
|
247
|
+
# renaming or splitting it into a generic skill plus a private profile is a
|
|
248
|
+
# decision, not a chore. Un-ignore once that call is made.
|
|
249
|
+
/skills/private-company-profile/
|
|
250
|
+
|
|
251
|
+
# uv
|
|
252
|
+
.venv/
|
|
253
|
+
|
|
254
|
+
# Finder and editor clutter. Finder drops .DS_Store into any directory it has
|
|
255
|
+
# been opened in, and the file records that directory's contents — so it is
|
|
256
|
+
# both noise and, in a repository organised around keeping company values out
|
|
257
|
+
# of git, a small thing that lists filenames nobody chose to publish.
|
|
258
|
+
.DS_Store
|
|
259
|
+
._*
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Runs before a commit is created, rather than telling you about it afterwards.
|
|
2
|
+
# Install once with `make hooks`; `make check` runs the same set over every file.
|
|
3
|
+
#
|
|
4
|
+
# mypy and the leak scan are `local` hooks on purpose: both need the project's
|
|
5
|
+
# own environment (its dependencies, its profile), and a hook running in an
|
|
6
|
+
# isolated venv would either fail to import weasyprint or scan with no profile
|
|
7
|
+
# at all — passing for the wrong reason, which is worse than failing.
|
|
8
|
+
repos:
|
|
9
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
10
|
+
rev: v0.14.5
|
|
11
|
+
hooks:
|
|
12
|
+
- id: ruff-check
|
|
13
|
+
args: [--fix]
|
|
14
|
+
- id: ruff-format
|
|
15
|
+
|
|
16
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
17
|
+
rev: v6.0.0
|
|
18
|
+
hooks:
|
|
19
|
+
- id: end-of-file-fixer
|
|
20
|
+
- id: trailing-whitespace
|
|
21
|
+
- id: check-yaml
|
|
22
|
+
- id: check-toml
|
|
23
|
+
- id: check-added-large-files
|
|
24
|
+
- id: check-merge-conflict
|
|
25
|
+
- id: detect-private-key
|
|
26
|
+
|
|
27
|
+
- repo: local
|
|
28
|
+
hooks:
|
|
29
|
+
- id: mypy
|
|
30
|
+
name: mypy
|
|
31
|
+
entry: uv run mypy
|
|
32
|
+
language: system
|
|
33
|
+
types: [python]
|
|
34
|
+
pass_filenames: false
|
|
35
|
+
|
|
36
|
+
- id: scan
|
|
37
|
+
name: scan for private values in tracked files
|
|
38
|
+
entry: uv run billwright scan
|
|
39
|
+
language: system
|
|
40
|
+
pass_filenames: false
|
|
41
|
+
always_run: true
|