Repository navigation
Expand file tree
/
Copy pathpyproject.toml
More file actions
366 lines (351 loc) · 18.4 KB
/
Copy pathpyproject.toml
File metadata and controls
366 lines (351 loc) · 18.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# The one thing this repository could not check about itself in prose:
# whether the other repositories still agree with README.md. Section 15
# gives the commands a human runs to audit one repository; this is the
# subset a machine can run against all of them, weekly, unattended.
#
# It is not a distribution. Section 3's metadata that only an index reads
# is therefore not here -- no classifiers, no urls, no license
# expression, no build backend and no wheel -- there being no upload for
# any of them to describe. `package = false` below is what says so to uv,
# and what keeps `uv run` from trying to build this directory before
# running anything in it.
#
# What section 3 binds to the `[project]` table rather than to an index
# is here all the same, `authors` and `keywords` both, each with the
# reason at the key.
[project]
name = "btclib-alignment"
version = "0"
# Section 3 binds this key to every tree that declares a [project]
# table, so a tree that builds nothing declares it too: the collective
# the MIT notice names, never a literal of this tree's own. No index
# ever serves it from here -- what it buys is that the answer for a
# tree of this shape is read off the standard rather than derived again
authors = [{ name = "The btclib developers", email = "devs@btclib.org" }]
# This is not a library covering every interpreter still in support: it
# is one suite, run by one workflow, on one runner. So the rule for an
# application applies -- the newest its dependencies allow -- and which
# interpreter that is, `.python-version` says rather than this comment.
requires-python = ">=3.14"
# the GitHub topics, the same names in the same lowercase spelling.
# Section 3 turns this key on the [project] table and not on the index,
# so a tree that uploads nothing writes the list all the same: the
# topics are how a reader of github.com/btclib-org finds the standard
# the other repositories are kept to, and this is what they are read
# against. The order is this file's alone -- `gh api
# repos/btclib-org/.github --jq '.topics'` sorts what it is given -- and
# it runs from what the tree is to what it is about. Each name is read
# against the tree rather than taken from a sibling's list
keywords = [
"repository-standard",
"github-organization",
"btclib",
"bitcoin",
]
[dependency-groups]
# `gh` and `git` are the other two dependencies and neither is a wheel:
# both are on every GitHub-hosted runner already, and CONTRIBUTING.md
# says so for a developer running this by hand.
test = [
"pytest",
# section 7's default, taken rather than declined: tests/README.md
# says what the shuffle guards in this suite and what argued against
# it, and `-p no:randomly` is how a failure is reproduced in order
"pytest-randomly",
# section 7's per-test bound, which is what names a wedged test
# where `alignment.yml`'s `timeout-minutes` names only a wedged
# runner. The limit is in [tool.pytest.ini_options] below
"pytest-timeout",
# a workflow file is read with a parser and not with a regex: what
# this suite asks of one is where its `cron:` entries are, which is
# a question about the document's shape rather than about a line
"pyyaml",
# the offline copy of PyPI's classifier list, which is what makes
# "is this a real classifier" answerable before an upload rather
# than during one. Section 3 has the argument
"trove-classifiers",
]
lint = ["mypy", "pre-commit", "types-PyYAML"]
# section 1's `dev` row: every group this file declares, so that one
# sync installs what any command here runs. uv makes it the default of
# `uv sync` and `uv run`, `[tool.uv]` below naming no `default-groups`;
# CONTRIBUTING.md says what a bare `uv run pytest` then measures
dev = [{ include-group = "test" }, { include-group = "lint" }]
[tool.uv]
# nothing is built here, so nothing installs this directory either
package = false
# the oldest uv that may read uv.lock -- section 1 has the argument and
# section 15 the commands that measure it
required-version = ">=0.13.4"
[tool.ruff]
# target-version is inferred from project.requires-python. Not for
# check_changelog.py and mutation_counts.py, which are served to every
# repository of the organization and run there on whatever interpreter
# that caller's own pre-commit supplies, nor for
# install_published_release.py, which runs on the interpreter of the cell
# that calls it, nor for check_run_jobs.py, which runs on the runner's own
# `python3`: none of them runs on this repository's own 3.14, and
# [tool.ruff.per-file-target-version] below overrides it for those
# (issue btclib-org/.github#1374) -- not for the whole of
# .github/scripts: the rest run pinned at this repository's own 3.15
# regardless of the caller, the `mypy-scripts-floor` hook's own comment
# in .pre-commit-config.yaml giving the reason those are named and the
# rest are not.
# Section 3 gives this file, and not a nested `.github/scripts/ruff.toml`,
# the setting: "One file holds the project metadata and every tool that
# can be configured in it."
[tool.ruff.per-file-target-version]
# The lowest `requires-python` floor among the organization's repositories,
# which section 15's interpreter-window command prints. It bounds the
# interpreter of a caller that runs the hook through `uv run --locked`'s
# project venv. A caller with no venv reaches the hook through its pre-commit
# environment's python3, which no floor bounds; issue btclib-org/.github#1374
# recorded `uvx` callers at 3.11.15. At any target above this, `ruff-check`
# reports PEP 695 syntax as the fix (UP040, UP046, UP047), a `SyntaxError` on
# 3.11, and at 3.14 `ruff format` writes `except A, B:` (PEP 758) itself.
# This key exists to refuse both. Named by file and not by directory: the files
# below are what a caller's own floor actually reaches, and the glob is
# proved to reach only them -- `ruff format --diff` on a copy of each
# with the same hazard appended left `mutation_counts.py` untouched and
# rewrote `wait_for_pypi_release.py`. install_published_release.py runs
# on a cell's own interpreter, `setup-python`'s at the matrix floor, which
# is at or above this one, and check_run_jobs.py on the `python3` of the
# runner image, which no file here pins.
".github/scripts/{check_changelog,check_run_jobs,install_published_release,mutation_counts}.py" = "py311"
[tool.ruff.lint]
# preview and explicit-preview-rules only make sense as a pair, and this
# file needs the first because naming a rule in `ignore` below, instead
# of coding it, is itself a preview feature. Alone it would also turn on
# every rule ruff is still designing; the second takes that back off, so
# a preview rule runs only where this file names it exactly.
preview = true
explicit-preview-rules = true
# Every family ruff ships, present ones and a release's future ones
# alike: a hand-picked list is what this key held until this file's
# repository-specific measurement, and a list is a thing that rots --
# nothing forces a second edit here the day ruff adds a family nobody
# has looked at yet. "ALL" takes a new family in on the pull request
# that bumps ruff's pinned rev instead, which is the day someone is
# already looking at what changed. Section 5 has the rule this states;
# this file is the tree it decided for.
select = ["ALL"]
ignore = [
# ruff's own docs/formatter.md, under "Conflicting lint rules":
# each of these is undone by the formatter's own rewriting, so
# selecting it is a lint failure the next `ruff format` produces
# again. The list is the vendor's, and does not change with this
# tree. D203 needs no entry here: the pep257 convention below
# already disables it in favour of D211 -- the other half of the
# pair ruff calls incompatible -- without printing the warning
# ruff reserves for a pair nothing has settled.
"tab-indentation",
"indentation-with-invalid-multiple",
"indentation-with-invalid-multiple-comment",
"over-indented",
"docstring-tab-indentation",
"triple-single-quotes",
"bad-quotes-inline-string",
"bad-quotes-multiline-string",
"bad-quotes-docstring",
"avoidable-escaped-quote",
"unnecessary-escaped-quote",
"missing-trailing-comma",
"prohibited-trailing-comma",
# a magic method is documented by the data model it implements, so a
# docstring on it only restates that model: section 5 gives the
# reason
"undocumented-magic-method",
# the rule checks that __init__ carries a docstring, never that the
# docstring says anything a type-checked signature does not already
# show: section 5 gives the reason
"undocumented-public-init",
# flake8-todos disciplines the format of a marker FIX above already
# refuses outright -- TD001 through TD007 are the whole family, and
# each is a question about a TODO/FIXME/XXX/HACK comment that a tree
# FIX holds clean cannot contain. TD001 also steers a refused marker
# toward TODO, which FIX002 refuses just as hard, and TD is not even
# a superset: HACK draws no TD diagnostic at all. Section 5 gives the
# reason this tree keeps the refusal over the formatting.
"invalid-todo-tag",
"missing-todo-author",
"missing-todo-link",
"missing-todo-colon",
"missing-todo-description",
"invalid-todo-capitalization",
"missing-space-after-todo-colon",
]
[tool.ruff.lint.per-file-ignores]
"tests/**" = [
"S101", # assert, which is how a test states what it checks
# this suite exists to run `git` and `gh`, so a subprocess call with a
# partial path is what every helper here is. The argument lists are
# built from the organization name and a repository name the API
# answered with -- never from a test's input -- and `shell=False` is
# the default the helpers keep
"S603",
"S607",
]
# flake8-no-pep420: each script here is an entry point a hook or a
# workflow step invokes by path, never an import, and the directory
# carries no `__init__.py` because it is not a package -- adding one to
# satisfy this rule would make it look like one. T20 for the same
# reason read the other way: what each one prints is its whole report,
# to a failing developer's terminal or to a job's log
".github/scripts/*.py" = ["INP001", "T20"]
[tool.ruff.lint.mccabe]
# ruff's default, as everywhere in the organization
max-complexity = 10
[tool.ruff.lint.pycodestyle]
# section 5's second width. What this key reaches, what it leaves to
# `line-too-long`, and when that rule passes a line over are section
# 9's, which also gives a tree the choice this one makes here:
# `ignore` above does not name `line-too-long`, so a comment
# following code on its line meets that rule rather than nothing. The
# key is written out rather than left to `select`, for the reason
# section 5 gives at W505
max-doc-length = 80
[tool.ruff.lint.pydocstyle]
# section 5's convention, which decides which of the "D" family above
# runs. At pep257 the family is what that document asks for; unset, it
# is every rule ruff writes under D, `missing-terminal-punctuation`
# among them -- a second rule over the end of a summary line, reporting
# the docstring `missing-trailing-period` has already reported. It is
# also what settles the pairs ruff calls incompatible, so no entry above
# names the half it disables
convention = "pep257"
[tool.ruff.lint.flake8-copyright]
# COPYRIGHT transcribed, the way section 5 spells the transcription:
# each line with its regex metacharacters escaped, the lines joined by a
# literal \n, anchored with ^ and preceded by an optional #! line so
# that the notice opens the file or follows the shebang a
# `language: script` hook needs, rather than sitting anywhere in its
# first 4096 bytes. ruff reads this string and never the file, so
# tests/copyright_test.py is what compares the two, here as in every
# tree that declares one; its `transcribed` is what wrote this value --
# the one every sibling repository is owed to declare
notice-rgx = "^(#![^\\n]*\\n)?# Copyright \\(c\\) The btclib developers\\n# Distributed under the MIT software license, see the accompanying\\n# LICENSE file or https://opensource\\.org/license/mit for the full text\\."
# codespell's configuration, the other half of section 4's spelling gate.
# `intoto` is the in-toto attestation format's own name, the one
# Scorecard's `*.intoto.jsonl` suffix carries, and both spell checkers'
# dictionaries offer "into" for it; with --write-changes that rewrites the
# suffix the release workflow attaches the bundle under. [tool.typos]
# below names it too.
[tool.codespell]
ignore-words-list = "intoto"
# typos' configuration, where section 4 says both spell checkers are
# configured and where every sibling keeps this one. What is *not* here
# matters as much: no `files.extend-exclude`. A file the checker never
# reads is a file nobody is checking, and the point of naming a word is
# that the next one still gets reported.
[tool.typos.default.extend-words]
# ruff's flake8-copyright prefix, which the standard names where it says
# the copyright notice is a ruff rule rather than a hook. typos reads it
# as "COPY" or "CPU" misspelled, both of which it would be anywhere else
CPY = "CPY"
# see [tool.codespell] above
intoto = "intoto"
[tool.mypy]
strict = true
show_column_numbers = true
# section 6's list, the same in every tree of the organization
enable_error_code = [
"deprecated",
"exhaustive-match",
"explicit-override",
"ignore-without-code",
"mutable-override",
"possibly-undefined",
"redundant-expr",
"redundant-self",
"truthy-bool",
"truthy-iterable",
"unimported-reveal",
"unused-awaitable",
]
warn_unreachable = true
# what requires-python says, for the reason a sibling's own comment
# gives at this key: without it mypy targets whatever runs it.
#
# .github/scripts is served to every repository of the organization at
# whatever interpreter each caller's own pre-commit run supplies, older
# than 3.14 among them (issue btclib-org/.github#1374). Not lowered here:
# `python_version` is one value for the whole table and mypy has no
# per-module override for it -- `python_version` names none of the keys a
# `[[tool.mypy.overrides]]` module section may set -- so lowering it here
# would check tests/ at that same floor too, and measured rather than
# assumed: it errors there, on the 3.14-only syntax `ruff format` has
# already written into a test at this repository's own floor.
#
# ruff's target refuses syntax, not a stdlib name newer than the floor,
# so it does not close this by itself. The `mypy-scripts-floor` hook in
# .pre-commit-config.yaml is the second run this gap needs, a
# `--python-version` CLI flag overriding this table for the scripts
# actually served to a caller's own floor, its own comment giving the
# reason the others under .github/scripts are not in it.
python_version = "3.14"
[tool.pytest.ini_options]
testpaths = ["tests"]
# the organization's strictness flags, minus the ones that answer a
# question this suite does not have. No --cov: coverage at 100% is a
# claim about a package's own code, and this tree ships none -- what
# would be measured is the suite measuring itself. No -n auto either:
# what a test asking about another repository waits on is the fetching,
# so the wall clock is that and not the CPU, and the longest waits are
# the session fixtures', taken once for the run
# -p pytester: tests/backlog_test.py runs a suite of its own in a
# temporary directory to ask what conftest.py does with a backlog row on
# a cell the run skips, and pytester is the fixture that runs one
addopts = "-ra --durations=8 --strict-config --strict-markers -p pytester"
xfail_strict = true
# Section 7's per-test bound, for a suite that waits on something
# outside its own process. Without it a hang is the one failure this
# suite cannot report: the run stops rather than fails, and what a
# reader gets is `alignment.yml` cancelled at its `timeout-minutes`,
# naming the job and no test. pytest-timeout's `signal` method, which
# it picks wherever SIGALRM exists and so on the runner, raises inside
# the item and fails it, leaving the rest of the matrix to be asked.
# `timeout_method` is unset for that reason: the other method ends the
# process with `os._exit`, which loses the report this line is for.
#
# One item's whole protocol is bounded rather than its body alone.
# `timeout_func_only` would time the bodies, and the waiting here is
# mostly the session fixtures' -- a clone of every repository, a
# repository document for each -- which pytest-timeout charges to
# whichever item triggered them; timing bodies alone leaves a stalled
# clone unbounded, and that is the hang there is to catch.
# `session_timeout` is read between items and cannot interrupt one.
#
# So the number is the worst item a shuffle can build -- every session
# fixture set up for one test, plus the slowest body -- rather than the
# worst seen, `pytest-randomly` putting a different test in that place
# each run. Measured on a ten-core machine sharing its cores with other
# work, its load average reaching 14, over whole runs of
#
# BTCLIB_INTEGRATION=1 uv run --locked --no-default-groups \
# --group test pytest --durations=0 --durations-min=0
#
# the setup phases summed to 75.28s beside a slowest body of 5.65s,
# and on the run where the API began refusing, to 114.60s beside
# 6.20s. This doubles the second of those, and sits far enough under
# `alignment.yml`'s fifteen minutes that a run losing an item to it
# still finishes and reports the rest, the slowest whole run here
# taking 155.97s. Nothing measured on the runner stands behind it,
# btclib-org/.github#628 being what has to close for there to be one
timeout = 240
# --strict-markers is on, so a marker is declared here or it is a typo.
# Every test that reaches the network -- anything this tree does not
# ship, section 7's own definition -- carries `integration`: section 7's
# rule that a test never reaches the network is what makes this suite an
# exception that has to announce itself, and BTCLIB_INTEGRATION is the
# same switch the siblings' own integration suites read
markers = [
"integration: reaches the network, opt-in via BTCLIB_INTEGRATION",
# section 2's tier a per-repository test applies down to, read off
# each tree by tests/__init__.py as that section measures it
"tier(asked): skip a repository this tier does not bind, with the reason",
# the issues a row of the backlog in tests/__init__.py carries, put
# on the cell beside the expected failure so conftest.py can tell a
# skip on an excused cell from any other skip
"backlog(*issues): the cell is a row of the backlog, excused by these issues",
]
filterwarnings = ["error"]