Skip to content

Commit a81714a

Browse files
committed
add checks
1 parent 46f4f5c commit a81714a

File tree

9 files changed

+2095
-40
lines changed

9 files changed

+2095
-40
lines changed

.vale.ini

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
MinAlertLevel = suggestion
2+
Packages = aoo-mozilla-en-dict-us
3+
StylesPath = scripts/vale
4+
Vocab = urljsf
5+
IgnoredClasses = w, n, o, kt, s2
6+
7+
[*.{md,py}]
8+
BasedOnStyles = aoo-mozilla-en-dict-us
9+
Vale.Spelling = NO
10+
11+
[*.html]
12+
BasedOnStyles = aoo-mozilla-en-dict-us
13+
Vale.Spelling = NO

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414

1515
**Visitors** to a `urljsf`-built page see:
1616

17-
- one or more interative HTML forms...
17+
- one or more interactive HTML forms...
1818
- defined by and validated against a JSON [Schema][json-schema], optionally with...
19-
- deep customizble [user interface][ui-schema]
19+
- deep customizable [user interface][ui-schema]
2020
- pre-filled data
2121
- custom validation checks
2222

docs/use/schema.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ JSON Schema
22
===========
33

44
A ``urljsf`` form definition should conform to the overall JSON schema, and may
5-
include additional, nested schema and documents, representd inline or referenced
5+
include additional, nested schema and documents, represented inline or referenced
66
by URL.
77

88
The `Draft 7` schema is used due to its wide implementation but, most specifically,

pixi.lock

+1,797-33
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pixi.toml

+56-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ run ALL tasks that would lead to a release""", depends-on = [
1616
"test",
1717
"docs",
1818
"atest",
19+
"check",
1920
"report",
2021
], cmd = "echo 🚢"}
2122
fix = {description = """
@@ -68,6 +69,13 @@ atest = {description = """
6869
run ALL acceptance tests""", depends-on = ["atest-robot", "atest-nyc"], cmd = "echo 🤖"}
6970
docs = {description = """
7071
build all documentation""", depends-on = ["docs-sphinx"], cmd = "echo 🖨️"}
72+
check = {description = """
73+
perform ALL pre-release checks""", depends-on = [
74+
"check-links",
75+
"check-vale",
76+
"check-wheel",
77+
"check-twine",
78+
], cmd = "echo 🤓"}
7179

7280
# fragments ####################################################################
7381
prettier-- = '''yarn prettier
@@ -408,6 +416,44 @@ depends-on = ["atest-robot"]
408416
inputs = ["js/package.json", "build/reports/atest/istanbul/*.cov.json"]
409417
outputs = ["build/reports/nyc"]
410418

419+
# check ########################################################################
420+
[feature.tasks-check.tasks.check-links]
421+
description = "... check github hyperlinks in documentation"
422+
cmd = """rm -rf build/reports/check-links
423+
&& mkdir -p build/reports/check-links
424+
&& cd build/reports/check-links
425+
&& touch pytest.ini
426+
&& pytest
427+
-vv
428+
-c pytest.ini
429+
-p no:warnings
430+
--rootdir=.
431+
--check-links
432+
--check-anchors
433+
--check-links-ignore '^https?://'
434+
-k "not (404 or coverage or lite or mypy or Untitled)"
435+
../../../build/docs/**/*.html"""
436+
depends-on = ["docs-sphinx"]
437+
inputs = ["docs/**/*.html"]
438+
439+
[feature.tasks-check.tasks.check-vale]
440+
description = "... check spelling in documentation"
441+
cmd = "python scripts/vale/check.py"
442+
depends-on = ["docs-sphinx"]
443+
inputs = ["build/docs", "scripts/vale"]
444+
445+
[feature.tasks-check.tasks.check-wheel]
446+
description = "... check the built wheel"
447+
cmd = "check-wheel-contents dist/*.whl"
448+
depends-on = ["dist-pypi"]
449+
inputs = ["dist/*.whl"]
450+
451+
[feature.tasks-check.tasks.check-twine]
452+
description = "... check the built distributions for PyPI"
453+
cmd = "twine check --strict dist/*.whl dist/*.tar.gz"
454+
depends-on = ["dist-pypi"]
455+
inputs = ["dist/"]
456+
411457
# watch ########################################################################
412458
[feature.tasks-dev.tasks.watch]
413459
description = "watch ALL the things"
@@ -480,9 +526,11 @@ lint = [
480526
"tasks-lint",
481527
]
482528
docs = ["deps-pip", "deps-docs", "deps-run", "deps-py-max", "deps-build", "tasks-docs"]
529+
check = ["deps-check", "tasks-check"]
483530
dev = [
484531
"deps-atest",
485532
"deps-build",
533+
"deps-check",
486534
"deps-docs",
487535
"deps-lint",
488536
"deps-pip",
@@ -562,6 +610,14 @@ tornado = "*"
562610
firefox = "128.*"
563611
geckodriver = "*"
564612

613+
[feature.deps-check.dependencies]
614+
check-wheel-contents = "*"
615+
pytest-check-links = "*"
616+
pytest-html = "*"
617+
twine = "*"
618+
vale = "*"
619+
vale-spelling-aoo-mozilla-en-dict-us = "*"
620+
565621
# tools ########################################################################
566622
[tool.sphinx]
567623
author = "{{ ppt.project.authors[0].name }}"
@@ -614,7 +670,6 @@ pygments_light_style = "github-light-colorblind"
614670
[tool.sphinx.jsonschema_options]
615671
lift_description = true
616672
auto_reference = true
617-
auto_target = true
618673
lift_definitions = true
619674

620675
## urljsf

pyproject.toml

+14-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ Source = "https://github.com/deathbeds/urljsf"
4747
[tool.flit.sdist]
4848
include = ["LICENSE"]
4949

50+
# check-wheel-contents #########################################################
51+
[tool.check-wheel-contents]
52+
ignore = ["W002"]
53+
5054
# coverage #####################################################################
5155
[tool.coverage.run]
5256
disable_warnings = [
@@ -125,6 +129,15 @@ isort.known-first-party = ["urljsf"]
125129
"UP006",
126130
"UP035",
127131
]
128-
"scripts/*.py" = ["S603", "T201", "INP001", "ANN401", "S404", "S607", "PLW0108"]
132+
"scripts/*.py" = [
133+
"S603",
134+
"T201",
135+
"INP001",
136+
"ANN401",
137+
"S404",
138+
"S607",
139+
"PLW0108",
140+
"RUF017",
141+
]
129142
"**/source.py" = ["PLC0415"]
130143
"atest/**/*.py" = ["INP001", "PLR6301", "T201"]

scripts/vale/check.py

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
"""Prose checks for ``urljsf``."""
2+
# Copyright (C) urljsf contributors.
3+
# Distributed under the terms of the Modified BSD License.
4+
5+
from __future__ import annotations
6+
7+
import json
8+
import subprocess
9+
import sys
10+
from pathlib import Path
11+
from typing import Any
12+
13+
import mistune
14+
15+
HERE = Path(__file__)
16+
DOCS = HERE.parent.parent
17+
ROOT = DOCS.parent
18+
BUILD = ROOT / "build"
19+
DOCS_BUILD = BUILD / "docs"
20+
REPORTS = BUILD / "reports"
21+
VALE_REPORT = REPORTS / "vale.html"
22+
SRC = ROOT / "src"
23+
24+
ALL_PY = [*SRC.rglob("*.py"), *DOCS.rglob("*.py")]
25+
ALL_HTML = [*DOCS_BUILD.rglob("*.html")]
26+
27+
CHECK_PATHS = {
28+
*sorted(p for p in [*ALL_PY, *ALL_HTML] if "checkpoint" not in str(p)),
29+
}
30+
31+
VALE_ARGS: list[str | Path] = [
32+
"vale",
33+
*sorted(CHECK_PATHS),
34+
"--output=JSON",
35+
]
36+
37+
TValeResults = dict[str, list[dict[str, Any]]]
38+
39+
40+
def report(raw: TValeResults) -> list[str]:
41+
"""Filter and report vale findings."""
42+
raw = {k: v for k, v in raw.items() if "ipynb_checkpoints" not in k}
43+
if not raw:
44+
return []
45+
lines: list[str] = []
46+
widths = [
47+
":" + ("-" * (1 + max(len(r) for r in raw))),
48+
(5 * "-") + ":",
49+
(7 * "-") + ":",
50+
":" + ("-" * (1 + max(len(line["Match"]) for line in sum(raw.values(), [])))),
51+
]
52+
53+
def line(*c: str) -> str:
54+
return "|".join([
55+
"",
56+
*[
57+
f" {c[i]} ".ljust(len(w))
58+
if w.startswith(":")
59+
else f" {c[i]} ".rjust(len(w))
60+
for i, w in enumerate(widths)
61+
],
62+
"",
63+
])
64+
65+
lines += [
66+
line("file", "line", "column", "message"),
67+
"|".join(["", *widths, ""]),
68+
]
69+
70+
for path, findings in raw.items():
71+
for found in findings:
72+
lines += [line(path, found["Line"], found["Span"][0], found["Match"])]
73+
74+
md = "\n".join(lines)
75+
76+
print(md)
77+
return lines
78+
79+
80+
def write_html(md_lines: list[str]) -> None:
81+
"""Write out an HTML report."""
82+
VALE_REPORT.parent.mkdir(parents=True, exist_ok=True)
83+
html = [
84+
"<style>",
85+
"* {font-family: sans-serif}",
86+
"td, th {padding: 0.25em 0.5em;}",
87+
"</style>",
88+
mistune.html("\n".join(md_lines)),
89+
]
90+
VALE_REPORT.write_text("\n".join(html), encoding="utf-8")
91+
92+
93+
def main() -> int:
94+
"""Run the checks."""
95+
str_args = [
96+
a if isinstance(a, str) else f"{a.relative_to(ROOT)}" for a in VALE_ARGS
97+
]
98+
print(">>>", " \\\n\t".join(str_args), flush=True)
99+
proc = subprocess.Popen(
100+
str_args,
101+
encoding="utf-8",
102+
cwd=str(ROOT),
103+
stdout=subprocess.PIPE,
104+
stderr=subprocess.PIPE,
105+
)
106+
out = proc.communicate()[0]
107+
raw: TValeResults = json.loads(out)
108+
rc = proc.returncode
109+
report_lines: list[str] = []
110+
if raw:
111+
report_lines = report(raw)
112+
rc = len(report_lines)
113+
summary = f"# {len(raw)} vale issues in {len(CHECK_PATHS)} files"
114+
write_html([summary, "", *report_lines])
115+
print("\n", summary)
116+
return rc
117+
118+
119+
if __name__ == "__main__":
120+
sys.exit(main())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
__.+__
2+
_.+_
3+
--?.+
4+
.+…
5+
(all|any|one)Of
6+
[A-Z]+[\d]+
7+
[a-zA-Z\d_.]+\(
8+
\{[A-Z]+\}
9+
`.*`
10+
acceptCharset
11+
addButton
12+
additionalProperties
13+
aspirational
14+
autoComplete
15+
autocompletion
16+
behaviour
17+
Changelog
18+
className
19+
cli
20+
CLI
21+
CORS
22+
customizable
23+
customizations
24+
deserialized
25+
docutils
26+
DOM
27+
download_filename
28+
e\.g\.
29+
enctype
30+
endmacro
31+
enum
32+
extraErrorsBlockSubmit
33+
focusOnFirstError
34+
form_data
35+
form(Context|Data)
36+
Git(Lab|Hub)
37+
globals
38+
i\.e\.
39+
idPrefix
40+
idSeparator
41+
IFrame
42+
inexhaustive
43+
JavaScript/HTML
44+
jinja
45+
js
46+
JSON
47+
jupyak
48+
light/dark
49+
linter
50+
live(Omit|Validate)
51+
min(Items|Length)
52+
natively
53+
no_bootstrap
54+
non-
55+
nunjucks
56+
omitExtraData
57+
parse/serialize
58+
patternProperties
59+
pragma
60+
prefill
61+
programmatically
62+
PyData
63+
PyPI
64+
pythonic
65+
re\)render
66+
readOnly
67+
repo/branch
68+
representer
69+
RJSF
70+
Roadmap
71+
scrollable
72+
showErrorList
73+
src
74+
stylesheet
75+
submit_button
76+
tagName
77+
theming
78+
TODO
79+
TOML
80+
ui
81+
UI
82+
ui:.+
83+
UIOptions
84+
uniqueItems
85+
url
86+
urljsf
87+
whitespace
88+
xkcd
89+
XKCD
90+
YAML

src/urljsf/errors.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ class InvalidInputError(UrljsfError, ValueError):
1212

1313

1414
class InvalidDefinitionError(UrljsfError, ValueError):
15-
"""No valid defintion."""
15+
"""No valid definition."""
1616

1717

1818
class BadImportError(UrljsfError, ValueError):
19-
"""An unxpected import."""
19+
"""An unexpected import."""

0 commit comments

Comments
 (0)