greatspectations 0.1.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.
- greatspectations-0.1.0/LICENSE +22 -0
- greatspectations-0.1.0/PKG-INFO +210 -0
- greatspectations-0.1.0/README.md +191 -0
- greatspectations-0.1.0/pyproject.toml +43 -0
- greatspectations-0.1.0/setup.cfg +4 -0
- greatspectations-0.1.0/src/greatspectations/__init__.py +1 -0
- greatspectations-0.1.0/src/greatspectations/__main__.py +6 -0
- greatspectations-0.1.0/src/greatspectations/cli.py +231 -0
- greatspectations-0.1.0/src/greatspectations/config.py +190 -0
- greatspectations-0.1.0/src/greatspectations/coverage.py +269 -0
- greatspectations-0.1.0/src/greatspectations/formats/__init__.py +55 -0
- greatspectations-0.1.0/src/greatspectations/formats/_common.py +103 -0
- greatspectations-0.1.0/src/greatspectations/formats/markdown.py +14 -0
- greatspectations-0.1.0/src/greatspectations/formats/mediawiki.py +21 -0
- greatspectations-0.1.0/src/greatspectations/formats/rfc_text.py +85 -0
- greatspectations-0.1.0/src/greatspectations/matching.py +234 -0
- greatspectations-0.1.0/src/greatspectations/quotes.py +217 -0
- greatspectations-0.1.0/src/greatspectations.egg-info/PKG-INFO +210 -0
- greatspectations-0.1.0/src/greatspectations.egg-info/SOURCES.txt +28 -0
- greatspectations-0.1.0/src/greatspectations.egg-info/dependency_links.txt +1 -0
- greatspectations-0.1.0/src/greatspectations.egg-info/entry_points.txt +2 -0
- greatspectations-0.1.0/src/greatspectations.egg-info/top_level.txt +1 -0
- greatspectations-0.1.0/tests/test_cli.py +239 -0
- greatspectations-0.1.0/tests/test_cli_smoke.py +29 -0
- greatspectations-0.1.0/tests/test_config.py +278 -0
- greatspectations-0.1.0/tests/test_coverage.py +219 -0
- greatspectations-0.1.0/tests/test_formats.py +185 -0
- greatspectations-0.1.0/tests/test_matching.py +281 -0
- greatspectations-0.1.0/tests/test_quotes.py +302 -0
- greatspectations-0.1.0/tests/test_rfc_text.py +195 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Note: the modules in the ccan/ directory have their own licenses, but
|
|
2
|
+
the rest of the code is covered by the following (BSD-MIT) license:
|
|
3
|
+
|
|
4
|
+
Copyright Rusty Russell (Blockstream) 2015-2024.
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
|
14
|
+
all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: greatspectations
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Check that spec quotes in source comments match the spec
|
|
5
|
+
Author: Rusty Russell
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://greatspectations.com
|
|
8
|
+
Project-URL: Repository, https://github.com/rustyrussell/greatspectations
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
14
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# Great Spectations
|
|
21
|
+
|
|
22
|
+
Checks that quotes of a spec embedded in source-code comments actually
|
|
23
|
+
say what the spec says -- so when the spec changes, the comments (and
|
|
24
|
+
the requirement they claim to implement) don't silently drift out of
|
|
25
|
+
sync.
|
|
26
|
+
|
|
27
|
+
Originally CLN's `check_quotes.py`/`bolt-coverage.py`, hardwired to
|
|
28
|
+
BOLTs. `greatspectations` generalizes the same idea to any spec source
|
|
29
|
+
you point it at: BOLTs, BIPs, RFCs, or a single-file spec like
|
|
30
|
+
`SPECIFICATION.md`.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
pip install -e .
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This installs the `spectate` command (also runnable as
|
|
39
|
+
`python -m greatspectations`).
|
|
40
|
+
|
|
41
|
+
## Quickstart
|
|
42
|
+
|
|
43
|
+
A comment like:
|
|
44
|
+
|
|
45
|
+
```c
|
|
46
|
+
/* BOLT #11: A writer:
|
|
47
|
+
* - MUST set `payment_hash` to the SHA256 of `payment_preimage`.
|
|
48
|
+
*/
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
is checked against your BOLT spec checkout by:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
spectate check --config specquotes.toml src/invoice.c
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`spectate` exits 0 if every quote is found verbatim (modulo whitespace)
|
|
58
|
+
in the spec, or 1 and prints `file:line:message` for anything that
|
|
59
|
+
doesn't match.
|
|
60
|
+
|
|
61
|
+
## `specquotes.toml`
|
|
62
|
+
|
|
63
|
+
Each repository that wants quote-checking declares its own
|
|
64
|
+
`specquotes.toml`, naming the spec sources it checks against:
|
|
65
|
+
|
|
66
|
+
```toml
|
|
67
|
+
[sources.bolt]
|
|
68
|
+
format = "markdown"
|
|
69
|
+
dir = "../lightning-rfc"
|
|
70
|
+
pattern = "{id:02d}-*.md"
|
|
71
|
+
|
|
72
|
+
[sources.bip]
|
|
73
|
+
format = "mediawiki"
|
|
74
|
+
dir = "../bips"
|
|
75
|
+
pattern = "bip-{id:04d}.mediawiki"
|
|
76
|
+
|
|
77
|
+
[sources.cmdata-spec]
|
|
78
|
+
format = "markdown"
|
|
79
|
+
file = "SPECIFICATION.md"
|
|
80
|
+
|
|
81
|
+
[sources.rfc]
|
|
82
|
+
format = "rfc-text"
|
|
83
|
+
dir = "/usr/share/doc/RFC/standard"
|
|
84
|
+
pattern = "rfc{id}.txt.gz"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`spectate` doesn't fetch anything -- point `dir`/`file` at a checkout or
|
|
88
|
+
package you already have (a `git clone` of `bitcoin/bips`, `apt install
|
|
89
|
+
doc-rfc-std`, or a spec file that lives in your own repo).
|
|
90
|
+
|
|
91
|
+
Each `[sources.NAME]` table is:
|
|
92
|
+
|
|
93
|
+
- `format` -- which parser splits the document into sections:
|
|
94
|
+
- `markdown` -- splits on `#`-prefixed headers. BOLT files and
|
|
95
|
+
single-file specs like `SPECIFICATION.md` both use this.
|
|
96
|
+
- `mediawiki` -- splits on `==Header==` lines, as used by
|
|
97
|
+
`bitcoin/bips`.
|
|
98
|
+
- `rfc-text` -- the classic RFC-editor plaintext layout, as shipped by
|
|
99
|
+
Debian's `doc-rfc-std` package (`/usr/share/doc/RFC/<category>/
|
|
100
|
+
rfcNNNN.txt.gz`). Transparently gunzips `.gz` files, strips page
|
|
101
|
+
headers/footers and form-feed page breaks so a requirement split
|
|
102
|
+
across a page boundary still reads as one section, and splits on
|
|
103
|
+
column-0 `N.`/`N.N.` numbered headers -- while ignoring the table of
|
|
104
|
+
contents, whose entries have the same shape but end in a
|
|
105
|
+
right-aligned page number (space- or dot-leader-padded), which a
|
|
106
|
+
real header never does. `doc-rfc-std` splits RFCs across category
|
|
107
|
+
subdirectories (`standard/`, `draft-standard/`, ...); point `dir`
|
|
108
|
+
at the single category you need, as in the example above. A
|
|
109
|
+
recursive `pattern` like `"**/rfc{id}.txt.gz"` also works if your
|
|
110
|
+
RFCs span categories, but `doc-rfc-std` additionally ships a
|
|
111
|
+
`links/` directory that symlinks every RFC into one flat directory
|
|
112
|
+
regardless of category, so a recursive pattern matches both the
|
|
113
|
+
symlink and the real file for the same id and `spectate` refuses
|
|
114
|
+
the ambiguity (`glob.glob` has no way to exclude a subdirectory by
|
|
115
|
+
name). If you need multiple categories, glob each one explicitly
|
|
116
|
+
with a separate `[sources.NAME]` table instead.
|
|
117
|
+
- `dir` + `pattern` -- for a source with one file per id (BOLT, BIP,
|
|
118
|
+
RFC): `pattern` is a glob template with an `{id}` placeholder, e.g.
|
|
119
|
+
`"{id:02d}-*.md"`, `"bip-{id:04d}.mediawiki"`, or
|
|
120
|
+
`"rfc{id}.txt.gz"`.
|
|
121
|
+
- `file` -- for a source that's a single fixed document (no id needed),
|
|
122
|
+
e.g. a spec that lives directly in your repo.
|
|
123
|
+
- `comment_marker` (optional) -- the literal word that opens a quote
|
|
124
|
+
comment for this source. Defaults to the source name, uppercased
|
|
125
|
+
(`bolt` -> `BOLT`, `cmdata-spec` -> `CMDATA-SPEC`), which is exactly
|
|
126
|
+
CLN's existing `# BOLT #11:` convention -- no source comments need to
|
|
127
|
+
change to adopt this tool for BOLT.
|
|
128
|
+
|
|
129
|
+
Relative `dir`/`file` paths are resolved against the directory
|
|
130
|
+
containing `specquotes.toml`, not your current working directory.
|
|
131
|
+
|
|
132
|
+
## Marker syntax
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
<MARKER>[-<commit>][ #<id>][/<section-hint>]: <quoted text>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
- `<MARKER>` is a source's `comment_marker`.
|
|
139
|
+
- `-<commit>` is CLN's "draft BOLT" convention: the line is only parsed
|
|
140
|
+
when `<commit>` is a prefix of one of `--include-commit`'s values
|
|
141
|
+
(repeatable), letting a branch reference an unmerged spec PR by
|
|
142
|
+
commit. Ignored otherwise.
|
|
143
|
+
- `#<id>` selects the document for sources with `dir`+`pattern`
|
|
144
|
+
(required there, and disallowed for `file` sources).
|
|
145
|
+
- `/<section-hint>` restricts the match to sections whose header
|
|
146
|
+
contains that text (case-insensitive). Useful when near-identical
|
|
147
|
+
wording repeats across sections -- e.g. `SPECIFICATION.md`'s "Reader
|
|
148
|
+
Requirements" and "Writer Requirements" both have a "MUST fail
|
|
149
|
+
parsing if the length is wrong" bullet, and without a hint a quote
|
|
150
|
+
could silently match the wrong one:
|
|
151
|
+
|
|
152
|
+
```c
|
|
153
|
+
/* CMDATA-SPEC/Reader Requirements: A reader:
|
|
154
|
+
* - MUST fail parsing if the length is wrong.
|
|
155
|
+
*/
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- The quoted text may use `...` as a wildcard, including once at the
|
|
159
|
+
very start of a quote to mean "must immediately follow the previous
|
|
160
|
+
quote from this source in this file" (handy for splitting one long
|
|
161
|
+
requirement across several separately-commented lines of code).
|
|
162
|
+
- Continuation lines repeat the marker's `--comment-continue` prefix
|
|
163
|
+
(default `#`); an inline/single-line comment style also needs
|
|
164
|
+
`--comment-end` (e.g. for C: `--comment-start='/* ' --comment-continue='*'
|
|
165
|
+
--comment-end='*/'`).
|
|
166
|
+
- `--comment-aside` marks a prefix for commentary that lives inside a
|
|
167
|
+
quote block but isn't part of the quote -- a continuation line
|
|
168
|
+
starting with it is dropped instead of appended, so it's never
|
|
169
|
+
checked against the spec:
|
|
170
|
+
|
|
171
|
+
```c
|
|
172
|
+
/* BOLT #2: A sending node:
|
|
173
|
+
* - MUST set `funding_satoshis`.
|
|
174
|
+
* Note: We did not implement this yet.
|
|
175
|
+
*/
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
with `--comment-aside='* Note:'` (adjust the prefix to match
|
|
179
|
+
whatever `--comment-continue` you're using, e.g. `'# Note:'` for the
|
|
180
|
+
default `#`-style comments).
|
|
181
|
+
|
|
182
|
+
## Matching modes
|
|
183
|
+
|
|
184
|
+
`--mode normalized` (default) collapses runs of whitespace in both the
|
|
185
|
+
quote and the spec before comparing, so line-wrapping differences don't
|
|
186
|
+
matter. `--mode exact` compares the literal, uncollapsed text instead,
|
|
187
|
+
for specs where exact byte matching matters.
|
|
188
|
+
|
|
189
|
+
## Coverage
|
|
190
|
+
|
|
191
|
+
`spectate check --coverage=FILE ...` appends a record for every quote
|
|
192
|
+
that matched. `spectate coverage --coverage=FILE` then reports spec text
|
|
193
|
+
in Requirements sections (or, with `--all-sections`, every section) that
|
|
194
|
+
no quote covers:
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
spectate check --config specquotes.toml --coverage=.coverage src/*.c
|
|
198
|
+
spectate coverage --config specquotes.toml --coverage=.coverage
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Restrict to specific documents with `--source NAME[:ID]` (repeatable);
|
|
202
|
+
by default every `(source, id)` pair found in the coverage file is
|
|
203
|
+
checked. `--mode` must match whatever mode `check` used to write the
|
|
204
|
+
coverage file, since match offsets are mode-specific.
|
|
205
|
+
|
|
206
|
+
## CI output
|
|
207
|
+
|
|
208
|
+
Both subcommands accept `--format json` for machine-readable output
|
|
209
|
+
instead of the default `file:line:message` text, if you want to post
|
|
210
|
+
results elsewhere rather than just scrape build logs.
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Great Spectations
|
|
2
|
+
|
|
3
|
+
Checks that quotes of a spec embedded in source-code comments actually
|
|
4
|
+
say what the spec says -- so when the spec changes, the comments (and
|
|
5
|
+
the requirement they claim to implement) don't silently drift out of
|
|
6
|
+
sync.
|
|
7
|
+
|
|
8
|
+
Originally CLN's `check_quotes.py`/`bolt-coverage.py`, hardwired to
|
|
9
|
+
BOLTs. `greatspectations` generalizes the same idea to any spec source
|
|
10
|
+
you point it at: BOLTs, BIPs, RFCs, or a single-file spec like
|
|
11
|
+
`SPECIFICATION.md`.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
pip install -e .
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This installs the `spectate` command (also runnable as
|
|
20
|
+
`python -m greatspectations`).
|
|
21
|
+
|
|
22
|
+
## Quickstart
|
|
23
|
+
|
|
24
|
+
A comment like:
|
|
25
|
+
|
|
26
|
+
```c
|
|
27
|
+
/* BOLT #11: A writer:
|
|
28
|
+
* - MUST set `payment_hash` to the SHA256 of `payment_preimage`.
|
|
29
|
+
*/
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
is checked against your BOLT spec checkout by:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
spectate check --config specquotes.toml src/invoice.c
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`spectate` exits 0 if every quote is found verbatim (modulo whitespace)
|
|
39
|
+
in the spec, or 1 and prints `file:line:message` for anything that
|
|
40
|
+
doesn't match.
|
|
41
|
+
|
|
42
|
+
## `specquotes.toml`
|
|
43
|
+
|
|
44
|
+
Each repository that wants quote-checking declares its own
|
|
45
|
+
`specquotes.toml`, naming the spec sources it checks against:
|
|
46
|
+
|
|
47
|
+
```toml
|
|
48
|
+
[sources.bolt]
|
|
49
|
+
format = "markdown"
|
|
50
|
+
dir = "../lightning-rfc"
|
|
51
|
+
pattern = "{id:02d}-*.md"
|
|
52
|
+
|
|
53
|
+
[sources.bip]
|
|
54
|
+
format = "mediawiki"
|
|
55
|
+
dir = "../bips"
|
|
56
|
+
pattern = "bip-{id:04d}.mediawiki"
|
|
57
|
+
|
|
58
|
+
[sources.cmdata-spec]
|
|
59
|
+
format = "markdown"
|
|
60
|
+
file = "SPECIFICATION.md"
|
|
61
|
+
|
|
62
|
+
[sources.rfc]
|
|
63
|
+
format = "rfc-text"
|
|
64
|
+
dir = "/usr/share/doc/RFC/standard"
|
|
65
|
+
pattern = "rfc{id}.txt.gz"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`spectate` doesn't fetch anything -- point `dir`/`file` at a checkout or
|
|
69
|
+
package you already have (a `git clone` of `bitcoin/bips`, `apt install
|
|
70
|
+
doc-rfc-std`, or a spec file that lives in your own repo).
|
|
71
|
+
|
|
72
|
+
Each `[sources.NAME]` table is:
|
|
73
|
+
|
|
74
|
+
- `format` -- which parser splits the document into sections:
|
|
75
|
+
- `markdown` -- splits on `#`-prefixed headers. BOLT files and
|
|
76
|
+
single-file specs like `SPECIFICATION.md` both use this.
|
|
77
|
+
- `mediawiki` -- splits on `==Header==` lines, as used by
|
|
78
|
+
`bitcoin/bips`.
|
|
79
|
+
- `rfc-text` -- the classic RFC-editor plaintext layout, as shipped by
|
|
80
|
+
Debian's `doc-rfc-std` package (`/usr/share/doc/RFC/<category>/
|
|
81
|
+
rfcNNNN.txt.gz`). Transparently gunzips `.gz` files, strips page
|
|
82
|
+
headers/footers and form-feed page breaks so a requirement split
|
|
83
|
+
across a page boundary still reads as one section, and splits on
|
|
84
|
+
column-0 `N.`/`N.N.` numbered headers -- while ignoring the table of
|
|
85
|
+
contents, whose entries have the same shape but end in a
|
|
86
|
+
right-aligned page number (space- or dot-leader-padded), which a
|
|
87
|
+
real header never does. `doc-rfc-std` splits RFCs across category
|
|
88
|
+
subdirectories (`standard/`, `draft-standard/`, ...); point `dir`
|
|
89
|
+
at the single category you need, as in the example above. A
|
|
90
|
+
recursive `pattern` like `"**/rfc{id}.txt.gz"` also works if your
|
|
91
|
+
RFCs span categories, but `doc-rfc-std` additionally ships a
|
|
92
|
+
`links/` directory that symlinks every RFC into one flat directory
|
|
93
|
+
regardless of category, so a recursive pattern matches both the
|
|
94
|
+
symlink and the real file for the same id and `spectate` refuses
|
|
95
|
+
the ambiguity (`glob.glob` has no way to exclude a subdirectory by
|
|
96
|
+
name). If you need multiple categories, glob each one explicitly
|
|
97
|
+
with a separate `[sources.NAME]` table instead.
|
|
98
|
+
- `dir` + `pattern` -- for a source with one file per id (BOLT, BIP,
|
|
99
|
+
RFC): `pattern` is a glob template with an `{id}` placeholder, e.g.
|
|
100
|
+
`"{id:02d}-*.md"`, `"bip-{id:04d}.mediawiki"`, or
|
|
101
|
+
`"rfc{id}.txt.gz"`.
|
|
102
|
+
- `file` -- for a source that's a single fixed document (no id needed),
|
|
103
|
+
e.g. a spec that lives directly in your repo.
|
|
104
|
+
- `comment_marker` (optional) -- the literal word that opens a quote
|
|
105
|
+
comment for this source. Defaults to the source name, uppercased
|
|
106
|
+
(`bolt` -> `BOLT`, `cmdata-spec` -> `CMDATA-SPEC`), which is exactly
|
|
107
|
+
CLN's existing `# BOLT #11:` convention -- no source comments need to
|
|
108
|
+
change to adopt this tool for BOLT.
|
|
109
|
+
|
|
110
|
+
Relative `dir`/`file` paths are resolved against the directory
|
|
111
|
+
containing `specquotes.toml`, not your current working directory.
|
|
112
|
+
|
|
113
|
+
## Marker syntax
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
<MARKER>[-<commit>][ #<id>][/<section-hint>]: <quoted text>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
- `<MARKER>` is a source's `comment_marker`.
|
|
120
|
+
- `-<commit>` is CLN's "draft BOLT" convention: the line is only parsed
|
|
121
|
+
when `<commit>` is a prefix of one of `--include-commit`'s values
|
|
122
|
+
(repeatable), letting a branch reference an unmerged spec PR by
|
|
123
|
+
commit. Ignored otherwise.
|
|
124
|
+
- `#<id>` selects the document for sources with `dir`+`pattern`
|
|
125
|
+
(required there, and disallowed for `file` sources).
|
|
126
|
+
- `/<section-hint>` restricts the match to sections whose header
|
|
127
|
+
contains that text (case-insensitive). Useful when near-identical
|
|
128
|
+
wording repeats across sections -- e.g. `SPECIFICATION.md`'s "Reader
|
|
129
|
+
Requirements" and "Writer Requirements" both have a "MUST fail
|
|
130
|
+
parsing if the length is wrong" bullet, and without a hint a quote
|
|
131
|
+
could silently match the wrong one:
|
|
132
|
+
|
|
133
|
+
```c
|
|
134
|
+
/* CMDATA-SPEC/Reader Requirements: A reader:
|
|
135
|
+
* - MUST fail parsing if the length is wrong.
|
|
136
|
+
*/
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
- The quoted text may use `...` as a wildcard, including once at the
|
|
140
|
+
very start of a quote to mean "must immediately follow the previous
|
|
141
|
+
quote from this source in this file" (handy for splitting one long
|
|
142
|
+
requirement across several separately-commented lines of code).
|
|
143
|
+
- Continuation lines repeat the marker's `--comment-continue` prefix
|
|
144
|
+
(default `#`); an inline/single-line comment style also needs
|
|
145
|
+
`--comment-end` (e.g. for C: `--comment-start='/* ' --comment-continue='*'
|
|
146
|
+
--comment-end='*/'`).
|
|
147
|
+
- `--comment-aside` marks a prefix for commentary that lives inside a
|
|
148
|
+
quote block but isn't part of the quote -- a continuation line
|
|
149
|
+
starting with it is dropped instead of appended, so it's never
|
|
150
|
+
checked against the spec:
|
|
151
|
+
|
|
152
|
+
```c
|
|
153
|
+
/* BOLT #2: A sending node:
|
|
154
|
+
* - MUST set `funding_satoshis`.
|
|
155
|
+
* Note: We did not implement this yet.
|
|
156
|
+
*/
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
with `--comment-aside='* Note:'` (adjust the prefix to match
|
|
160
|
+
whatever `--comment-continue` you're using, e.g. `'# Note:'` for the
|
|
161
|
+
default `#`-style comments).
|
|
162
|
+
|
|
163
|
+
## Matching modes
|
|
164
|
+
|
|
165
|
+
`--mode normalized` (default) collapses runs of whitespace in both the
|
|
166
|
+
quote and the spec before comparing, so line-wrapping differences don't
|
|
167
|
+
matter. `--mode exact` compares the literal, uncollapsed text instead,
|
|
168
|
+
for specs where exact byte matching matters.
|
|
169
|
+
|
|
170
|
+
## Coverage
|
|
171
|
+
|
|
172
|
+
`spectate check --coverage=FILE ...` appends a record for every quote
|
|
173
|
+
that matched. `spectate coverage --coverage=FILE` then reports spec text
|
|
174
|
+
in Requirements sections (or, with `--all-sections`, every section) that
|
|
175
|
+
no quote covers:
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
spectate check --config specquotes.toml --coverage=.coverage src/*.c
|
|
179
|
+
spectate coverage --config specquotes.toml --coverage=.coverage
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Restrict to specific documents with `--source NAME[:ID]` (repeatable);
|
|
183
|
+
by default every `(source, id)` pair found in the coverage file is
|
|
184
|
+
checked. `--mode` must match whatever mode `check` used to write the
|
|
185
|
+
coverage file, since match offsets are mode-specific.
|
|
186
|
+
|
|
187
|
+
## CI output
|
|
188
|
+
|
|
189
|
+
Both subcommands accept `--format json` for machine-readable output
|
|
190
|
+
instead of the default `file:line:message` text, if you want to post
|
|
191
|
+
results elsewhere rather than just scrape build logs.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "greatspectations"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Check that spec quotes in source comments match the spec"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.11"
|
|
13
|
+
authors = [{ name = "Rusty Russell" }]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Topic :: Software Development :: Documentation",
|
|
20
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Homepage = "https://greatspectations.com"
|
|
25
|
+
Repository = "https://github.com/rustyrussell/greatspectations"
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
spectate = "greatspectations.cli:main"
|
|
29
|
+
|
|
30
|
+
[tool.setuptools.packages.find]
|
|
31
|
+
where = ["src"]
|
|
32
|
+
|
|
33
|
+
[tool.pytest.ini_options]
|
|
34
|
+
testpaths = ["tests"]
|
|
35
|
+
|
|
36
|
+
[tool.mypy]
|
|
37
|
+
files = ["src/greatspectations"]
|
|
38
|
+
python_version = "3.11"
|
|
39
|
+
|
|
40
|
+
[dependency-groups]
|
|
41
|
+
dev = [
|
|
42
|
+
"pytest>=9.1.1",
|
|
43
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|