Skip to content

Commit 5f81cc1

Browse files
eriknwseberg
andauthored
Add precommit hooks & some linting (#18)
* Add initial version of .pre-commit-config.yaml * validate-pyproject * autoflake * pyupgrade * black (line-length = 100) * ruff * ruff extend-select (no changes) * isort via ruff * flake8-return via ruff * Enable ruff linting, and some fixes * pyroma * SIM102 (manually) * codespell * taplo to auto-format pyproject.toml * yamllint * prettier * sphinx-lint * check-jsonschema and dependabot.yml * zizmor (TODO) * blacken-docs * pygrep-hooks and updates from sp-repo-review * Add some local pre-commit hooks * Add pre-commit github action * Clean up based on actual scientific-python cookie cutter template * Fix docs (oops!) * Use `importlib_metadata.version` instead of `importlib.metadata.version`. * Add `pre-commit` to `dev` dependency group * auto-walrus (hehehe) * Use `Path(filepath).read_text()` Co-authored-by: Sebastian Berg <sebastian@sipsolutions.net> * Use `Path(filepath).write_text(text)` Co-authored-by: Sebastian Berg <sebastian@sipsolutions.net> * oops fix whitespace * Iterate over `graph` since not mutating Co-authored-by: Sebastian Berg <sebastian@sipsolutions.net> * bump ruff --------- Co-authored-by: Sebastian Berg <sebastian@sipsolutions.net>
1 parent 2583740 commit 5f81cc1

26 files changed

Lines changed: 708 additions & 284 deletions

.github/dependabot.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: 2
2+
updates:
3+
# Maintain dependencies for GitHub Actions
4+
- package-ecosystem: "github-actions"
5+
directory: "/"
6+
schedule:
7+
interval: "daily"
8+
groups:
9+
actions:
10+
patterns:
11+
- "*"

.github/workflows/build-docs.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ on:
1010
workflow_dispatch:
1111
inputs:
1212
deploy:
13-
description: 'Publish docs?'
13+
description: "Publish docs?"
1414
required: true
1515
type: boolean
1616

@@ -32,6 +32,7 @@ jobs:
3232
- uses: actions/checkout@v4
3333
with:
3434
fetch-depth: 0
35+
persist-credentials: false
3536

3637
- uses: actions/setup-python@v5
3738
with:
@@ -58,8 +59,8 @@ jobs:
5859
if: inputs.deploy
5960

6061
permissions:
61-
pages: write # to deploy to Pages
62-
id-token: write # to verify the deployment originates from an appropriate source
62+
pages: write # to deploy to Pages
63+
id-token: write # to verify the deployment originates from an appropriate source
6364

6465
# Deploy to the github-pages environment
6566
environment:

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ jobs:
3939
- uses: actions/checkout@v4
4040
with:
4141
fetch-depth: 0
42+
persist-credentials: false
4243

4344
- uses: actions/setup-python@v5
4445
with:

.github/workflows/pre-commit.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: pre-commit checks
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches: [main]
7+
8+
jobs:
9+
pre-commit:
10+
name: pre-commit-hooks
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
with:
15+
fetch-depth: 0
16+
persist-credentials: false
17+
- uses: actions/setup-python@v5
18+
with:
19+
python-version: "3.13"
20+
- uses: pre-commit/action@v3.0.1

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,4 @@ Thumbs.db
165165
# Common editor files
166166
*~
167167
*.swp
168+
*.swo

.pre-commit-config.yaml

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# https://pre-commit.com/
2+
#
3+
# Before first use:
4+
#
5+
# $ pre-commit install
6+
#
7+
ci:
8+
autofix_prs: false
9+
autoupdate_schedule: quarterly
10+
autoupdate_commit_msg: "chore: update pre-commit hooks"
11+
autofix_commit_msg: "style: pre-commit fixes"
12+
skip: [no-commit-to-branch]
13+
fail_fast: false
14+
default_language_version:
15+
python: python3
16+
repos:
17+
- repo: https://github.com/pre-commit/pre-commit-hooks
18+
rev: v5.0.0
19+
hooks:
20+
# Sanity checks
21+
- id: check-added-large-files
22+
- id: check-case-conflict
23+
# - id: check-executables-have-shebangs # No executable files yet
24+
- id: check-illegal-windows-names
25+
- id: check-merge-conflict
26+
# Checks based on file type
27+
- id: check-ast
28+
# - id: check-json # No json files yet
29+
- id: check-symlinks
30+
- id: check-toml
31+
# - id: check-xml # No xml files yet
32+
- id: check-yaml
33+
# Detect mistakes
34+
- id: check-vcs-permalinks
35+
- id: debug-statements
36+
- id: destroyed-symlinks
37+
- id: detect-private-key
38+
- id: forbid-submodules
39+
# Automatic fixes
40+
- id: end-of-file-fixer
41+
- id: mixed-line-ending
42+
args: [--fix=lf]
43+
# - id: requirements-txt-fixer # No requirements.txt file yet
44+
- id: trailing-whitespace
45+
- repo: https://github.com/abravalheri/validate-pyproject
46+
rev: v0.24.1
47+
hooks:
48+
- id: validate-pyproject
49+
name: Validate pyproject.toml
50+
# Remove unnecessary imports (currently behaves better than ruff)
51+
- repo: https://github.com/PyCQA/autoflake
52+
rev: v2.3.1
53+
hooks:
54+
- id: autoflake
55+
args: [--in-place]
56+
# Let's keep `pyupgrade` even though `ruff --fix` probably does most of it
57+
- repo: https://github.com/asottile/pyupgrade
58+
rev: v3.20.0
59+
hooks:
60+
- id: pyupgrade
61+
args: [--py310-plus]
62+
# black often looks better than ruff-format
63+
- repo: https://github.com/psf/black-pre-commit-mirror
64+
rev: 25.1.0
65+
hooks:
66+
- id: black
67+
- repo: https://github.com/adamchainz/blacken-docs
68+
rev: 1.19.1
69+
hooks:
70+
- id: blacken-docs
71+
additional_dependencies: [black==25.1.0]
72+
- repo: https://github.com/astral-sh/ruff-pre-commit
73+
rev: v0.12.5
74+
hooks:
75+
- id: ruff-check
76+
args: [--fix-only, --show-fixes]
77+
- repo: https://github.com/codespell-project/codespell
78+
rev: v2.4.1
79+
hooks:
80+
- id: codespell
81+
types_or: [python, markdown, rst, toml, yaml]
82+
additional_dependencies:
83+
- tomli; python_version<'3.11'
84+
- repo: https://github.com/MarcoGorelli/auto-walrus
85+
rev: 0.3.4
86+
hooks:
87+
- id: auto-walrus
88+
args: [--line-length, "100"]
89+
- repo: https://github.com/astral-sh/ruff-pre-commit
90+
rev: v0.12.5
91+
hooks:
92+
- id: ruff-check
93+
# - id: ruff-format # Prefer black, but may temporarily uncomment this to see
94+
# `pyroma` may help keep our package standards up to date if best practices change.
95+
# This is probably a "low value" check though and safe to remove if we want faster pre-commit.
96+
# - repo: https://github.com/regebro/pyroma
97+
# rev: "5.0"
98+
# hooks:
99+
# - id: pyroma
100+
# args: [-n, "9", .] # Need author email to score a 10
101+
- repo: https://github.com/rbubley/mirrors-prettier
102+
rev: v3.6.2
103+
hooks:
104+
- id: prettier
105+
args: [--prose-wrap=preserve]
106+
- repo: https://github.com/sphinx-contrib/sphinx-lint
107+
rev: v1.0.0
108+
hooks:
109+
- id: sphinx-lint
110+
args: [--enable, all, "--disable=line-too-long,leaked-markup"]
111+
- repo: https://github.com/pre-commit/pygrep-hooks
112+
rev: v1.10.0
113+
hooks:
114+
- id: rst-backticks
115+
- id: rst-directive-colons
116+
- id: rst-inline-touching-normal
117+
- id: python-check-blanket-noqa
118+
- id: python-check-blanket-type-ignore
119+
- id: python-no-eval
120+
- id: python-no-log-warn
121+
- id: text-unicode-replacement-char
122+
- repo: https://github.com/ComPWA/taplo-pre-commit
123+
rev: v0.9.3
124+
hooks:
125+
- id: taplo-format
126+
- repo: https://github.com/adrienverge/yamllint
127+
rev: v1.37.1
128+
hooks:
129+
- id: yamllint
130+
- repo: https://github.com/python-jsonschema/check-jsonschema
131+
rev: 0.33.2
132+
hooks:
133+
- id: check-dependabot
134+
- id: check-github-workflows
135+
# TODO: get zizmor to pass, and maybe set it up as a github action
136+
# - repo: https://github.com/woodruffw/zizmor-pre-commit
137+
# rev: v1.11.0
138+
# hooks:
139+
# - id: zizmor
140+
- repo: local
141+
hooks:
142+
- id: disallow-caps
143+
name: Disallow improper capitalization
144+
language: pygrep
145+
entry: PyBind|Numpy|Cmake|CCache|Github|PyTest|RST|PyLint
146+
exclude: (.pre-commit-config.yaml|docs/pages/guides/style\.md)$
147+
- id: disallow-words
148+
name: Disallow certain words
149+
language: pygrep
150+
entry: "[Ff]alsey"
151+
exclude: .pre-commit-config.yaml$
152+
- id: disallow-bad-permalinks
153+
name: Disallow _ in permalinks
154+
language: pygrep
155+
entry: "^permalink:.*_.*"
156+
- repo: https://github.com/pre-commit/pre-commit-hooks
157+
rev: v5.0.0
158+
hooks:
159+
- id: no-commit-to-branch # No commit directly to main
160+
- repo: meta
161+
hooks:
162+
- id: check-hooks-apply
163+
- id: check-useless-excludes

.yamllint.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
extends: default
3+
rules:
4+
document-start: disable
5+
line-length: disable

README.md

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ based on feedback.**
77

88
Spatch is a dispatching tool with a focus on scientific python libraries.
99
It integrates two forms of dispatching into a single backend system:
10-
* Type dispatching for the main type used by a library.
10+
11+
- Type dispatching for the main type used by a library.
1112
In the scientific python world, this is often the array object.
12-
* Backend selection to offer alternative implementations to users.
13+
- Backend selection to offer alternative implementations to users.
1314
These may be faster or less precise, but using them should typically
1415
not change code behavior drastically.
1516

@@ -26,7 +27,7 @@ to a large scale deployment.
2627

2728
Unfortunately, providing code for a host of such types isn't easy
2829
and the original library authors usually have neither the bandwidth nor
29-
expertise to do it. Additionally, such layers would have to be optional
30+
expertise to do it. Additionally, such layers would have to be optional
3031
components of the library.
3132

3233
`spatch` allows for a solution to this dilemma by allowing a third party
@@ -35,7 +36,7 @@ to enable library functions to work with alternative types.
3536
It should be noted that spatch is not a generic multiple dispatching
3637
library. It is opinionated about being strictly typed (we can and probably
3738
will support subclasses in the future, though).
38-
It also considers all arguments identically. I.e. if a function takes
39+
It also considers all arguments identically. I.e. if a function takes
3940
two inputs (of the kind we dispatch for), there is no distinction for
4041
their order.
4142
Besides these two things, `spatch` is however a typical type dispatching
@@ -56,11 +57,12 @@ For example, we may have a faster algorithm that is parallelized while the
5657
old one was not. Or an implementation that dispatches to the GPU but still
5758
returns NumPy arrays (as the library always did).
5859

59-
Backend selection _modifies_ behavior rather than extending it. In some
60+
Backend selection _modifies_ behavior rather than extending it. In some
6061
cases those modifications may be small (maybe it is really only faster).
6162
For the user, backend _selection_ often means that they should explicitly
6263
select a preferred backend (e.g. over the default implementation).
6364
This could be for example via a context manager:
65+
6466
```python
6567
with backend_opts(prioritize="gpu_backend"):
6668
library.function() # now running on the GPU
@@ -76,36 +78,38 @@ with backend_opts(prioritize="gpu_backend"):
7678
it should be considered a prototype when it comes to API stability.
7779

7880
Some examples for missing things we are still working on:
79-
* No way to conveniently see which backends may be used when calling a
81+
82+
- No way to conveniently see which backends may be used when calling a
8083
function (rather than actually calling it). And probably more inspection
8184
utilities.
82-
* We have implemented the ability for a backend to defer and not run,
85+
- We have implemented the ability for a backend to defer and not run,
8386
but not the ability to run anyway if there is no alternative.
84-
* The main library implementation currently can't distinguish fallback
87+
- The main library implementation currently can't distinguish fallback
8588
and default path easily. It should be easy to do this (two functions,
8689
`should_run`, or just via `uses_context`).
87-
* `spatch` is very much designed to be fast but that doesn't mean it
88-
is particularly fast yet. We may need to optimize parts (potentially
90+
- `spatch` is very much designed to be fast but that doesn't mean it
91+
is particularly fast yet. We may need to optimize parts (potentially
8992
lowering parts to a compiled language).
90-
* We have not implemented tools to test backends, e.g. against parts
91-
of the original library. We expect that "spatch" actually includes most
92-
tools to do this. For example, we could define a `convert` function
93+
- We have not implemented tools to test backends, e.g. against parts
94+
of the original library. We expect that "spatch" actually includes most
95+
tools to do this. For example, we could define a `convert` function
9396
that backends can implement to convert arguments in tests as needed.
9497

9598
There are also many smaller or bigger open questions and those include whether
9699
the API proposed here is actually quite what we want.
97100
Other things are for example whether we want API like:
98-
* `dispatchable.invoke(type=, backend=)`.
99-
* Maybe libraries should use `like=` in functions that take no dispatchable
101+
102+
- `dispatchable.invoke(type=, backend=)`.
103+
- Maybe libraries should use `like=` in functions that take no dispatchable
100104
arguments.
101-
* How do we do classes such as scikit-learn estimators. A simple solution might
105+
- How do we do classes such as scikit-learn estimators. A simple solution might
102106
a `get_backend(...)` dispatching explicitly once. But we could use more involved
103107
schemes, rather remembering the dispatching state of the `.fit()`.
104108

105109
We can also see many small conveniences, for example:
106-
* Extract the dispatchable arguments from type annotations.
107-
* Support a magic `Defer` return, rather than the `should_run` call.
108110

111+
- Extract the dispatchable arguments from type annotations.
112+
- Support a magic `Defer` return, rather than the `should_run` call.
109113

110114
# Usage examples
111115

docs/Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,3 @@ html: Makefile
2121
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
2222
%: Makefile
2323
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
24-

docs/source/api/for_backends.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Before writing a backend, you need to think about a few things:
2626
by the user.
2727

2828
Please check the example linked above. These example entry-points include
29-
code that means running them modifies them in-place if the `@implements`
29+
code that means running them modifies them in-place if the ``@implements``
3030
decorator is used (see next section).
3131

3232
Some of the most important things are:
@@ -94,7 +94,7 @@ The following fields are supported for each function:
9494

9595
- ``function``: The implementation to dispatch to.
9696
- ``should_run`` (optional): A function that gets all inputs (and context)
97-
and can decide to defer. Unless you know things will error, try to make sure
97+
and can decide to defer. Unless you know things will error, try to make sure
9898
that this function is light-weight.
9999
- ``uses_context``: Whether the implementation needs a ``DispatchContext``.
100100
- ``additional_docs`` (optional): Brief text to add to the documentation

0 commit comments

Comments
 (0)