Markdown-Checker 1.0.3__tar.gz → 1.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.
- markdown_checker-1.2.0/PKG-INFO +118 -0
- markdown_checker-1.2.0/README.md +88 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/docs/CONTRIBUTING.rst +8 -8
- markdown_checker-1.2.0/docs/api/checker.rst +10 -0
- markdown_checker-1.2.0/docs/api/checks.rst +45 -0
- markdown_checker-1.2.0/docs/api/cli.rst +10 -0
- markdown_checker-1.2.0/docs/api/main.rst +14 -0
- markdown_checker-1.2.0/docs/api/models.rst +39 -0
- markdown_checker-1.2.0/docs/api/patterns.rst +10 -0
- markdown_checker-1.2.0/docs/api/reports.rst +71 -0
- markdown_checker-1.2.0/docs/api/utils.rst +46 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/docs/conf.py +7 -0
- markdown_checker-1.2.0/docs/explanation/index.rst +12 -0
- markdown_checker-1.2.0/docs/explanation/link-detection.rst +53 -0
- markdown_checker-1.2.0/docs/explanation/url-checking.rst +78 -0
- markdown_checker-1.2.0/docs/howto/github-actions.rst +87 -0
- markdown_checker-1.2.0/docs/howto/index.rst +17 -0
- markdown_checker-1.2.0/docs/howto/pyproject-config.rst +63 -0
- markdown_checker-1.2.0/docs/howto/rate-limits.rst +73 -0
- markdown_checker-1.2.0/docs/howto/report-formats.rst +68 -0
- markdown_checker-1.2.0/docs/howto/select-files.rst +62 -0
- markdown_checker-1.2.0/docs/howto/shell-completions.rst +64 -0
- markdown_checker-1.2.0/docs/howto/skip-links.rst +53 -0
- markdown_checker-1.2.0/docs/index.rst +87 -0
- markdown_checker-1.2.0/docs/reference/checks.rst +105 -0
- markdown_checker-1.2.0/docs/reference/cli.rst +305 -0
- markdown_checker-1.2.0/docs/reference/configuration.rst +104 -0
- markdown_checker-1.2.0/docs/reference/exit-codes.rst +62 -0
- markdown_checker-1.2.0/docs/reference/index.rst +16 -0
- markdown_checker-1.2.0/docs/reference/report-formats.rst +95 -0
- markdown_checker-1.2.0/docs/tutorial.rst +135 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/pyproject.toml +5 -7
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/__init__.py +2 -2
- markdown_checker-1.2.0/src/markdown_checker/checker.py +154 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/checks/__init__.py +3 -1
- markdown_checker-1.2.0/src/markdown_checker/checks/base.py +89 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/checks/broken_paths.py +10 -0
- markdown_checker-1.2.0/src/markdown_checker/checks/broken_urls.py +104 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/checks/locale.py +15 -1
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/checks/tracking.py +21 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/cli.py +126 -51
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/models/__init__.py +2 -0
- markdown_checker-1.2.0/src/markdown_checker/models/base.py +59 -0
- markdown_checker-1.2.0/src/markdown_checker/models/config.py +86 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/models/path.py +33 -17
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/models/url.py +55 -38
- markdown_checker-1.2.0/src/markdown_checker/patterns.py +36 -0
- markdown_checker-1.2.0/src/markdown_checker/reports/__init__.py +38 -0
- markdown_checker-1.2.0/src/markdown_checker/reports/base.py +23 -0
- markdown_checker-1.2.0/src/markdown_checker/reports/model.py +135 -0
- markdown_checker-1.2.0/src/markdown_checker/reports/registry.py +35 -0
- markdown_checker-1.2.0/src/markdown_checker/reports/renderers/__init__.py +10 -0
- markdown_checker-1.2.0/src/markdown_checker/reports/renderers/annotations.py +38 -0
- markdown_checker-1.2.0/src/markdown_checker/reports/renderers/console.py +35 -0
- markdown_checker-1.2.0/src/markdown_checker/reports/renderers/json.py +48 -0
- markdown_checker-1.2.0/src/markdown_checker/reports/renderers/markdown.py +111 -0
- markdown_checker-1.2.0/src/markdown_checker/reports/writer.py +21 -0
- markdown_checker-1.2.0/src/markdown_checker/utils/__init__.py +26 -0
- markdown_checker-1.2.0/src/markdown_checker/utils/extract_links.py +97 -0
- markdown_checker-1.2.0/src/markdown_checker/utils/github_env.py +57 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/utils/list_files.py +3 -1
- markdown_checker-1.2.0/src/markdown_checker/utils/pyproject_config.py +147 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/utils/spinner.py +23 -1
- markdown_checker-1.2.0/src/markdown_checker/utils/url_pipeline.py +250 -0
- markdown_checker-1.2.0/tests/checks/__init__.py +0 -0
- markdown_checker-1.2.0/tests/checks/test_base.py +56 -0
- markdown_checker-1.0.3/tests/test_checks_broken_urls.py → markdown_checker-1.2.0/tests/checks/test_broken_urls.py +42 -84
- markdown_checker-1.0.3/tests/test_checks_locale.py → markdown_checker-1.2.0/tests/checks/test_locale.py +0 -2
- markdown_checker-1.0.3/tests/test_checks_tracking.py → markdown_checker-1.2.0/tests/checks/test_tracking.py +0 -5
- markdown_checker-1.2.0/tests/models/__init__.py +0 -0
- markdown_checker-1.0.3/tests/test_models_base.py → markdown_checker-1.2.0/tests/models/test_base.py +3 -0
- markdown_checker-1.2.0/tests/models/test_config.py +70 -0
- markdown_checker-1.2.0/tests/models/test_models.py +20 -0
- markdown_checker-1.0.3/tests/test_models_url.py → markdown_checker-1.2.0/tests/models/test_url.py +41 -64
- markdown_checker-1.2.0/tests/reports/__init__.py +0 -0
- markdown_checker-1.2.0/tests/reports/conftest.py +36 -0
- markdown_checker-1.2.0/tests/reports/renderers/__init__.py +0 -0
- markdown_checker-1.2.0/tests/reports/renderers/test_annotations.py +15 -0
- markdown_checker-1.2.0/tests/reports/renderers/test_console.py +15 -0
- markdown_checker-1.2.0/tests/reports/renderers/test_json.py +27 -0
- markdown_checker-1.2.0/tests/reports/renderers/test_markdown.py +209 -0
- markdown_checker-1.2.0/tests/reports/renderers/test_renderers.py +17 -0
- markdown_checker-1.2.0/tests/reports/test_base.py +37 -0
- markdown_checker-1.2.0/tests/reports/test_model.py +77 -0
- markdown_checker-1.2.0/tests/reports/test_registry.py +42 -0
- markdown_checker-1.2.0/tests/reports/test_reports.py +28 -0
- markdown_checker-1.2.0/tests/reports/test_writer.py +22 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/tests/smoke/test_cli_smoke.py +1 -1
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/tests/test_checker.py +112 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/tests/test_cli.py +88 -16
- markdown_checker-1.2.0/tests/test_markdown_checker.py +34 -0
- markdown_checker-1.2.0/tests/test_patterns.py +88 -0
- markdown_checker-1.2.0/tests/utils/__init__.py +0 -0
- markdown_checker-1.0.3/tests/test_utils_extract_links.py → markdown_checker-1.2.0/tests/utils/test_extract_links.py +54 -0
- markdown_checker-1.2.0/tests/utils/test_github_env.py +105 -0
- markdown_checker-1.2.0/tests/utils/test_pyproject_config.py +173 -0
- markdown_checker-1.2.0/tests/utils/test_url_pipeline.py +323 -0
- markdown_checker-1.2.0/tests/utils/test_utils.py +22 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/uv.lock +359 -557
- markdown_checker-1.0.3/PKG-INFO +0 -128
- markdown_checker-1.0.3/README.md +0 -97
- markdown_checker-1.0.3/docs/advanced.rst +0 -388
- markdown_checker-1.0.3/docs/api/checker.rst +0 -7
- markdown_checker-1.0.3/docs/api/checks.rst +0 -42
- markdown_checker-1.0.3/docs/api/cli.rst +0 -7
- markdown_checker-1.0.3/docs/api/main.rst +0 -6
- markdown_checker-1.0.3/docs/api/models.rst +0 -26
- markdown_checker-1.0.3/docs/api/reports.rst +0 -26
- markdown_checker-1.0.3/docs/api/utils.rst +0 -26
- markdown_checker-1.0.3/docs/automate.rst +0 -9
- markdown_checker-1.0.3/docs/index.rst +0 -71
- markdown_checker-1.0.3/docs/usage.rst +0 -73
- markdown_checker-1.0.3/src/markdown_checker/checker.py +0 -84
- markdown_checker-1.0.3/src/markdown_checker/checks/base.py +0 -36
- markdown_checker-1.0.3/src/markdown_checker/checks/broken_urls.py +0 -86
- markdown_checker-1.0.3/src/markdown_checker/models/base.py +0 -43
- markdown_checker-1.0.3/src/markdown_checker/models/config.py +0 -33
- markdown_checker-1.0.3/src/markdown_checker/reports/__init__.py +0 -6
- markdown_checker-1.0.3/src/markdown_checker/reports/base.py +0 -31
- markdown_checker-1.0.3/src/markdown_checker/reports/format_output.py +0 -58
- markdown_checker-1.0.3/src/markdown_checker/reports/markdown.py +0 -65
- markdown_checker-1.0.3/src/markdown_checker/utils/__init__.py +0 -13
- markdown_checker-1.0.3/src/markdown_checker/utils/extract_links.py +0 -76
- markdown_checker-1.0.3/tests/test_reports.py +0 -106
- markdown_checker-1.0.3/tests/test_utils_format_output.py +0 -86
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/LICENSE +0 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/docs/CODE_OF_CONDUCT.rst +0 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/docs/changes.rst +0 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/docs/license.rst +0 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/py.typed +0 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/reports/templates/paths/broken.md +0 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/reports/templates/paths/tracking.md +0 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/reports/templates/urls/broken.md +0 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/reports/templates/urls/locale.md +0 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/src/markdown_checker/reports/templates/urls/tracking.md +0 -0
- /markdown_checker-1.0.3/tests/test_checks_broken_paths.py → /markdown_checker-1.2.0/tests/checks/test_broken_paths.py +0 -0
- /markdown_checker-1.0.3/tests/test_checks_registry.py → /markdown_checker-1.2.0/tests/checks/test_checks.py +0 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/tests/conftest.py +0 -0
- /markdown_checker-1.0.3/tests/test_models_path.py → /markdown_checker-1.2.0/tests/models/test_path.py +0 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/tests/resources/sample1.md +0 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/tests/resources/sample2.md +0 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/tests/resources/sample3.md +0 -0
- {markdown_checker-1.0.3 → markdown_checker-1.2.0}/tests/resources/sample4.md +0 -0
- /markdown_checker-1.0.3/tests/test_utils_list_files.py → /markdown_checker-1.2.0/tests/utils/test_list_files.py +0 -0
- /markdown_checker-1.0.3/tests/test_utils_spinner.py → /markdown_checker-1.2.0/tests/utils/test_spinner.py +0 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: markdown-checker
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: A markdown link validation reporting tool.
|
|
5
|
+
Author-email: John Aziz <johnaziz269@gmail.com>
|
|
6
|
+
Maintainer-email: John Aziz <johnaziz269@gmail.com>
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: click>=8.3.1
|
|
23
|
+
Requires-Dist: httpx2>=2.0.0
|
|
24
|
+
Project-URL: Contributing, https://github.com/john0isaac/markdown-checker/pulls
|
|
25
|
+
Project-URL: Documentation, https://markdown-checker.readthedocs.io/en/latest/
|
|
26
|
+
Project-URL: Homepage, https://github.com/john0isaac/markdown-checker
|
|
27
|
+
Project-URL: Issues, https://github.com/john0isaac/markdown-checker/issues
|
|
28
|
+
Project-URL: Releases, https://github.com/john0isaac/markdown-checker/releases
|
|
29
|
+
|
|
30
|
+
[](https://pypi.org/project/markdown-checker/)
|
|
31
|
+
[](https://markdown-checker.readthedocs.io/en/latest/?badge=latest)
|
|
32
|
+
[](https://pypi.org/project/markdown-checker/)
|
|
33
|
+
|
|
34
|
+
[](https://github.com/john0isaac/markdown-checker/issues)
|
|
35
|
+
[](https://github.com/john0isaac/markdown-checker/pulls)
|
|
36
|
+
|
|
37
|
+
markdown-checker is a markdown link validation reporting tool for `.md` and
|
|
38
|
+
`.ipynb` files. It flags broken relative paths, broken web URLs, missing
|
|
39
|
+
locale segments, and missing tracking IDs, then writes the findings as a
|
|
40
|
+
report your CI can post back to a pull request.
|
|
41
|
+
|
|
42
|
+
## Features
|
|
43
|
+
|
|
44
|
+
- Five built-in checks: broken relative paths, broken web URLs, locale
|
|
45
|
+
segments in URLs, and tracking IDs on URLs and paths.
|
|
46
|
+
- Concurrent URL checking with cross-file deduplication, per-host rate
|
|
47
|
+
pacing, and `Retry-After`/429 handling, so large repositories don't
|
|
48
|
+
trip host rate limits.
|
|
49
|
+
- Four report formats: `markdown`, `json`, `github-annotations`, and
|
|
50
|
+
`console`.
|
|
51
|
+
- Error vs. warning severity - rate-limited or unverifiable links are
|
|
52
|
+
reported but never fail your CI.
|
|
53
|
+
- Configuration via a `[tool.markdown-checker]` table in `pyproject.toml`,
|
|
54
|
+
so you don't have to repeat flags in every command or workflow file.
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install markdown-checker
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Quickstart
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
markdown-checker . -f check_broken_paths
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
🔍 Checked 42 links in 10 files.
|
|
70
|
+
All files are compliant with the guidelines. 🎉
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
When issues are found, a `comment.md` report is written and the command
|
|
74
|
+
exits with a non-zero status:
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
🔍 Checked 42 links in 10 files.
|
|
78
|
+
😭 Found 1 issues in the following files:
|
|
79
|
+
File 'docs/index.md', line 5
|
|
80
|
+
./missing.md is broken.
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Using `markdown-checker` in GitHub Actions
|
|
84
|
+
|
|
85
|
+
Run this tool within a GitHub workflow using the
|
|
86
|
+
[action-check-markdown](https://github.com/marketplace/actions/check-markdown)
|
|
87
|
+
GitHub Action, which posts the report as a pull request comment:
|
|
88
|
+
|
|
89
|
+
```yaml
|
|
90
|
+
- uses: john0isaac/action-check-markdown@v1.1.0
|
|
91
|
+
with:
|
|
92
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
93
|
+
command: check_broken_paths
|
|
94
|
+
directory: ./
|
|
95
|
+
guide-url: "https://github.com/<owner>/<repo>/blob/main/CONTRIBUTING.md"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
See the [GitHub Actions how-to](https://markdown-checker.readthedocs.io/en/latest/howto/github-actions/)
|
|
99
|
+
for the full workflow, including running `check_broken_urls` (not yet
|
|
100
|
+
supported by the wrapper action) directly as a step.
|
|
101
|
+
|
|
102
|
+
## Documentation
|
|
103
|
+
|
|
104
|
+
- [Tutorial](https://markdown-checker.readthedocs.io/en/latest/tutorial/) - install and run your first check.
|
|
105
|
+
- [How-to guides](https://markdown-checker.readthedocs.io/en/latest/howto/) - configuration, rate limiting, report formats, CI.
|
|
106
|
+
- [CLI reference](https://markdown-checker.readthedocs.io/en/latest/reference/cli/) - every command-line option.
|
|
107
|
+
- [API reference](https://markdown-checker.readthedocs.io/en/latest/api/) - for programmatic use.
|
|
108
|
+
- [Full documentation](https://markdown-checker.readthedocs.io/en/latest/).
|
|
109
|
+
|
|
110
|
+
## Contributing
|
|
111
|
+
|
|
112
|
+
Contributions are welcome - see the
|
|
113
|
+
[Contributing guide](https://markdown-checker.readthedocs.io/en/latest/CONTRIBUTING/).
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
[MIT](https://github.com/john0isaac/markdown-checker/blob/main/LICENSE)
|
|
118
|
+
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
[](https://pypi.org/project/markdown-checker/)
|
|
2
|
+
[](https://markdown-checker.readthedocs.io/en/latest/?badge=latest)
|
|
3
|
+
[](https://pypi.org/project/markdown-checker/)
|
|
4
|
+
|
|
5
|
+
[](https://github.com/john0isaac/markdown-checker/issues)
|
|
6
|
+
[](https://github.com/john0isaac/markdown-checker/pulls)
|
|
7
|
+
|
|
8
|
+
markdown-checker is a markdown link validation reporting tool for `.md` and
|
|
9
|
+
`.ipynb` files. It flags broken relative paths, broken web URLs, missing
|
|
10
|
+
locale segments, and missing tracking IDs, then writes the findings as a
|
|
11
|
+
report your CI can post back to a pull request.
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- Five built-in checks: broken relative paths, broken web URLs, locale
|
|
16
|
+
segments in URLs, and tracking IDs on URLs and paths.
|
|
17
|
+
- Concurrent URL checking with cross-file deduplication, per-host rate
|
|
18
|
+
pacing, and `Retry-After`/429 handling, so large repositories don't
|
|
19
|
+
trip host rate limits.
|
|
20
|
+
- Four report formats: `markdown`, `json`, `github-annotations`, and
|
|
21
|
+
`console`.
|
|
22
|
+
- Error vs. warning severity - rate-limited or unverifiable links are
|
|
23
|
+
reported but never fail your CI.
|
|
24
|
+
- Configuration via a `[tool.markdown-checker]` table in `pyproject.toml`,
|
|
25
|
+
so you don't have to repeat flags in every command or workflow file.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install markdown-checker
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quickstart
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
markdown-checker . -f check_broken_paths
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
🔍 Checked 42 links in 10 files.
|
|
41
|
+
All files are compliant with the guidelines. 🎉
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
When issues are found, a `comment.md` report is written and the command
|
|
45
|
+
exits with a non-zero status:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
🔍 Checked 42 links in 10 files.
|
|
49
|
+
😭 Found 1 issues in the following files:
|
|
50
|
+
File 'docs/index.md', line 5
|
|
51
|
+
./missing.md is broken.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Using `markdown-checker` in GitHub Actions
|
|
55
|
+
|
|
56
|
+
Run this tool within a GitHub workflow using the
|
|
57
|
+
[action-check-markdown](https://github.com/marketplace/actions/check-markdown)
|
|
58
|
+
GitHub Action, which posts the report as a pull request comment:
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
- uses: john0isaac/action-check-markdown@v1.1.0
|
|
62
|
+
with:
|
|
63
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
64
|
+
command: check_broken_paths
|
|
65
|
+
directory: ./
|
|
66
|
+
guide-url: "https://github.com/<owner>/<repo>/blob/main/CONTRIBUTING.md"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
See the [GitHub Actions how-to](https://markdown-checker.readthedocs.io/en/latest/howto/github-actions/)
|
|
70
|
+
for the full workflow, including running `check_broken_urls` (not yet
|
|
71
|
+
supported by the wrapper action) directly as a step.
|
|
72
|
+
|
|
73
|
+
## Documentation
|
|
74
|
+
|
|
75
|
+
- [Tutorial](https://markdown-checker.readthedocs.io/en/latest/tutorial/) - install and run your first check.
|
|
76
|
+
- [How-to guides](https://markdown-checker.readthedocs.io/en/latest/howto/) - configuration, rate limiting, report formats, CI.
|
|
77
|
+
- [CLI reference](https://markdown-checker.readthedocs.io/en/latest/reference/cli/) - every command-line option.
|
|
78
|
+
- [API reference](https://markdown-checker.readthedocs.io/en/latest/api/) - for programmatic use.
|
|
79
|
+
- [Full documentation](https://markdown-checker.readthedocs.io/en/latest/).
|
|
80
|
+
|
|
81
|
+
## Contributing
|
|
82
|
+
|
|
83
|
+
Contributions are welcome - see the
|
|
84
|
+
[Contributing guide](https://markdown-checker.readthedocs.io/en/latest/CONTRIBUTING/).
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
[MIT](https://github.com/john0isaac/markdown-checker/blob/main/LICENSE)
|
|
@@ -16,13 +16,13 @@ Install all dependencies and the package in editable mode:
|
|
|
16
16
|
|
|
17
17
|
.. code-block:: shell
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
uv sync
|
|
20
20
|
|
|
21
21
|
Activate the virtual environment:
|
|
22
22
|
|
|
23
23
|
.. code-block:: shell
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
source .venv/bin/activate
|
|
26
26
|
|
|
27
27
|
Any changes you make to the source will take effect immediately.
|
|
28
28
|
|
|
@@ -39,13 +39,13 @@ These are the most common commands you will use:
|
|
|
39
39
|
These are some more specific commands if you need them:
|
|
40
40
|
|
|
41
41
|
- ``tox parallel``: Run all test environments that will be run in CI, in
|
|
42
|
-
|
|
42
|
+
parallel. Python versions that are not installed are skipped.
|
|
43
43
|
- ``pre-commit``: Run the linter and formatter tools. Only staged files are
|
|
44
|
-
|
|
44
|
+
checked, and this runs automatically before each commit.
|
|
45
45
|
- ``pre-commit run --all-files``: Run the pre-commit hooks against all files,
|
|
46
|
-
|
|
46
|
+
including unchanged and unstaged files.
|
|
47
47
|
- ``tox run -e py3.11``: Run unit tests with a specific Python version. The
|
|
48
|
-
|
|
48
|
+
version must be installed.
|
|
49
49
|
- ``tox run -e style``: Run all pre-commit hooks on all files via tox.
|
|
50
50
|
- ``tox run -e typing``: Run all typing checks.
|
|
51
51
|
- ``tox run -e docs``: Build the documentation in strict mode.
|
|
@@ -56,5 +56,5 @@ These are some more specific commands if you need them:
|
|
|
56
56
|
|
|
57
57
|
.. tip::
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
``tox run`` and ``tox parallel`` can be shortened to ``tox r`` and
|
|
60
|
+
``tox p``.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
Checks
|
|
2
|
+
======
|
|
3
|
+
|
|
4
|
+
The five built-in checks and their shared base class. See
|
|
5
|
+
:doc:`../reference/checks` for what each one flags.
|
|
6
|
+
|
|
7
|
+
Base
|
|
8
|
+
----
|
|
9
|
+
|
|
10
|
+
.. automodule:: markdown_checker.checks.base
|
|
11
|
+
:members:
|
|
12
|
+
:undoc-members:
|
|
13
|
+
:show-inheritance:
|
|
14
|
+
|
|
15
|
+
Broken Paths
|
|
16
|
+
------------
|
|
17
|
+
|
|
18
|
+
.. automodule:: markdown_checker.checks.broken_paths
|
|
19
|
+
:members:
|
|
20
|
+
:undoc-members:
|
|
21
|
+
:show-inheritance:
|
|
22
|
+
|
|
23
|
+
Broken URLs
|
|
24
|
+
-----------
|
|
25
|
+
|
|
26
|
+
.. automodule:: markdown_checker.checks.broken_urls
|
|
27
|
+
:members:
|
|
28
|
+
:undoc-members:
|
|
29
|
+
:show-inheritance:
|
|
30
|
+
|
|
31
|
+
Locale
|
|
32
|
+
------
|
|
33
|
+
|
|
34
|
+
.. automodule:: markdown_checker.checks.locale
|
|
35
|
+
:members:
|
|
36
|
+
:undoc-members:
|
|
37
|
+
:show-inheritance:
|
|
38
|
+
|
|
39
|
+
Tracking
|
|
40
|
+
--------
|
|
41
|
+
|
|
42
|
+
.. automodule:: markdown_checker.checks.tracking
|
|
43
|
+
:members:
|
|
44
|
+
:undoc-members:
|
|
45
|
+
:show-inheritance:
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Main
|
|
2
|
+
====
|
|
3
|
+
|
|
4
|
+
Top-level package exports: :class:`~markdown_checker.models.Config`,
|
|
5
|
+
:class:`~markdown_checker.models.MarkdownPath`,
|
|
6
|
+
:class:`~markdown_checker.models.MarkdownURL`,
|
|
7
|
+
:class:`~markdown_checker.models.MarkdownLinkBase`, ``main``, and
|
|
8
|
+
``__version__``. Documented canonically under :doc:`models`, :doc:`cli`,
|
|
9
|
+
and :doc:`checker`; shown here without indexing to avoid duplicate targets.
|
|
10
|
+
|
|
11
|
+
.. automodule:: markdown_checker
|
|
12
|
+
:members:
|
|
13
|
+
:undoc-members:
|
|
14
|
+
:noindex:
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Models
|
|
2
|
+
======
|
|
3
|
+
|
|
4
|
+
Data models shared by the checks: extracted links (:class:`MarkdownPath
|
|
5
|
+
<markdown_checker.models.path.MarkdownPath>`,
|
|
6
|
+
:class:`MarkdownURL <markdown_checker.models.url.MarkdownURL>`) and runtime
|
|
7
|
+
configuration (:class:`Config <markdown_checker.models.config.Config>`).
|
|
8
|
+
|
|
9
|
+
Base
|
|
10
|
+
----
|
|
11
|
+
|
|
12
|
+
.. automodule:: markdown_checker.models.base
|
|
13
|
+
:members:
|
|
14
|
+
:undoc-members:
|
|
15
|
+
:show-inheritance:
|
|
16
|
+
|
|
17
|
+
Config
|
|
18
|
+
------
|
|
19
|
+
|
|
20
|
+
.. automodule:: markdown_checker.models.config
|
|
21
|
+
:members:
|
|
22
|
+
:undoc-members:
|
|
23
|
+
:show-inheritance:
|
|
24
|
+
|
|
25
|
+
Path
|
|
26
|
+
----
|
|
27
|
+
|
|
28
|
+
.. automodule:: markdown_checker.models.path
|
|
29
|
+
:members:
|
|
30
|
+
:undoc-members:
|
|
31
|
+
:show-inheritance:
|
|
32
|
+
|
|
33
|
+
URL
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
.. automodule:: markdown_checker.models.url
|
|
37
|
+
:members:
|
|
38
|
+
:undoc-members:
|
|
39
|
+
:show-inheritance:
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Reports
|
|
2
|
+
=======
|
|
3
|
+
|
|
4
|
+
The format-agnostic report model, the renderer contract and
|
|
5
|
+
implementations, and the writer that emits rendered reports. See
|
|
6
|
+
:doc:`../reference/report-formats` for the user-facing shape of each format.
|
|
7
|
+
|
|
8
|
+
Base
|
|
9
|
+
----
|
|
10
|
+
|
|
11
|
+
.. automodule:: markdown_checker.reports.base
|
|
12
|
+
:members:
|
|
13
|
+
:undoc-members:
|
|
14
|
+
:show-inheritance:
|
|
15
|
+
|
|
16
|
+
Model
|
|
17
|
+
------
|
|
18
|
+
|
|
19
|
+
.. automodule:: markdown_checker.reports.model
|
|
20
|
+
:members:
|
|
21
|
+
:undoc-members:
|
|
22
|
+
:show-inheritance:
|
|
23
|
+
|
|
24
|
+
Registry
|
|
25
|
+
--------
|
|
26
|
+
|
|
27
|
+
.. automodule:: markdown_checker.reports.registry
|
|
28
|
+
:members:
|
|
29
|
+
:undoc-members:
|
|
30
|
+
:show-inheritance:
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
Writer
|
|
34
|
+
------
|
|
35
|
+
|
|
36
|
+
.. automodule:: markdown_checker.reports.writer
|
|
37
|
+
:members:
|
|
38
|
+
:undoc-members:
|
|
39
|
+
:show-inheritance:
|
|
40
|
+
|
|
41
|
+
Markdown Renderer
|
|
42
|
+
------------------
|
|
43
|
+
|
|
44
|
+
.. automodule:: markdown_checker.reports.renderers.markdown
|
|
45
|
+
:members:
|
|
46
|
+
:undoc-members:
|
|
47
|
+
:show-inheritance:
|
|
48
|
+
|
|
49
|
+
JSON Renderer
|
|
50
|
+
-------------
|
|
51
|
+
|
|
52
|
+
.. automodule:: markdown_checker.reports.renderers.json
|
|
53
|
+
:members:
|
|
54
|
+
:undoc-members:
|
|
55
|
+
:show-inheritance:
|
|
56
|
+
|
|
57
|
+
GitHub Annotations Renderer
|
|
58
|
+
----------------------------
|
|
59
|
+
|
|
60
|
+
.. automodule:: markdown_checker.reports.renderers.annotations
|
|
61
|
+
:members:
|
|
62
|
+
:undoc-members:
|
|
63
|
+
:show-inheritance:
|
|
64
|
+
|
|
65
|
+
Console Renderer
|
|
66
|
+
-----------------
|
|
67
|
+
|
|
68
|
+
.. automodule:: markdown_checker.reports.renderers.console
|
|
69
|
+
:members:
|
|
70
|
+
:undoc-members:
|
|
71
|
+
:show-inheritance:
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Utilities
|
|
2
|
+
=========
|
|
3
|
+
|
|
4
|
+
Standalone helpers: link extraction, file listing, the concurrent
|
|
5
|
+
URL-checking pipeline, GitHub Actions environment detection, pyproject.toml
|
|
6
|
+
config loading, and the CLI spinner.
|
|
7
|
+
|
|
8
|
+
Extract Links
|
|
9
|
+
-------------
|
|
10
|
+
|
|
11
|
+
.. automodule:: markdown_checker.utils.extract_links
|
|
12
|
+
:members:
|
|
13
|
+
:undoc-members:
|
|
14
|
+
:show-inheritance:
|
|
15
|
+
|
|
16
|
+
GitHub Environment
|
|
17
|
+
-------------------
|
|
18
|
+
|
|
19
|
+
.. automodule:: markdown_checker.utils.github_env
|
|
20
|
+
:members:
|
|
21
|
+
:undoc-members:
|
|
22
|
+
:show-inheritance:
|
|
23
|
+
|
|
24
|
+
List Files
|
|
25
|
+
----------
|
|
26
|
+
|
|
27
|
+
.. automodule:: markdown_checker.utils.list_files
|
|
28
|
+
:members:
|
|
29
|
+
:undoc-members:
|
|
30
|
+
:show-inheritance:
|
|
31
|
+
|
|
32
|
+
Spinner
|
|
33
|
+
-------
|
|
34
|
+
|
|
35
|
+
.. automodule:: markdown_checker.utils.spinner
|
|
36
|
+
:members:
|
|
37
|
+
:undoc-members:
|
|
38
|
+
:show-inheritance:
|
|
39
|
+
|
|
40
|
+
URL Pipeline
|
|
41
|
+
------------
|
|
42
|
+
|
|
43
|
+
.. automodule:: markdown_checker.utils.url_pipeline
|
|
44
|
+
:members:
|
|
45
|
+
:undoc-members:
|
|
46
|
+
:show-inheritance:
|
|
@@ -15,6 +15,7 @@ extensions = [
|
|
|
15
15
|
"sphinx.ext.autodoc",
|
|
16
16
|
"sphinx.ext.extlinks",
|
|
17
17
|
"sphinx.ext.intersphinx",
|
|
18
|
+
"sphinx.ext.napoleon",
|
|
18
19
|
"sphinxcontrib.log_cabinet",
|
|
19
20
|
"sphinx_tabs.tabs",
|
|
20
21
|
"sphinx_copybutton",
|
|
@@ -23,6 +24,12 @@ extensions = [
|
|
|
23
24
|
autodoc_member_order = "bysource"
|
|
24
25
|
autodoc_typehints = "description"
|
|
25
26
|
autodoc_preserve_defaults = True
|
|
27
|
+
autodoc_default_options = {
|
|
28
|
+
"no-value": True,
|
|
29
|
+
}
|
|
30
|
+
napoleon_google_docstring = True
|
|
31
|
+
napoleon_numpy_docstring = False
|
|
32
|
+
napoleon_use_rtype = False
|
|
26
33
|
extlinks = {
|
|
27
34
|
"issue": ("https://github.com/john0isaac/markdown-checker/issues/%s", "#%s"),
|
|
28
35
|
"pr": ("https://github.com/john0isaac/markdown-checker/pull/%s", "#%s"),
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Explanation
|
|
2
|
+
============
|
|
3
|
+
|
|
4
|
+
Background and design discussion for understanding *why* markdown-checker
|
|
5
|
+
behaves the way it does, rather than step-by-step instructions. For tasks,
|
|
6
|
+
see :doc:`../howto/index`; for exact facts, see :doc:`../reference/index`.
|
|
7
|
+
|
|
8
|
+
.. toctree::
|
|
9
|
+
:maxdepth: 1
|
|
10
|
+
|
|
11
|
+
url-checking
|
|
12
|
+
link-detection
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
How Link Detection Works
|
|
2
|
+
===========================
|
|
3
|
+
|
|
4
|
+
Every check starts from the same extraction step: reading a markdown file
|
|
5
|
+
line by line and pulling out link destinations. This page explains what
|
|
6
|
+
counts as a checkable link and what's deliberately excluded.
|
|
7
|
+
|
|
8
|
+
What's matched
|
|
9
|
+
-----------------
|
|
10
|
+
|
|
11
|
+
Only the destination of an inline Markdown link is considered - the part
|
|
12
|
+
inside parentheses in ``[text](destination)``, or inside angle brackets in
|
|
13
|
+
``[text](<destination>)``. Reference-style links (``[text][ref]`` with a
|
|
14
|
+
separate ``[ref]: destination`` definition) are not currently matched.
|
|
15
|
+
|
|
16
|
+
Code fences are skipped entirely: lines between an opening and matching
|
|
17
|
+
closing fence (three or more backtick or tilde characters) are ignored, so
|
|
18
|
+
example links inside a code sample are never checked.
|
|
19
|
+
|
|
20
|
+
How a destination is classified
|
|
21
|
+
------------------------------------
|
|
22
|
+
|
|
23
|
+
Each matched destination falls into one of three buckets:
|
|
24
|
+
|
|
25
|
+
- **URL**: starts with ``http://`` or ``https://`` (protocol-relative
|
|
26
|
+
``//host/...`` links are treated as ``https://``). Handled by
|
|
27
|
+
``check_broken_urls``, ``check_urls_locale``, and ``check_urls_tracking``.
|
|
28
|
+
- **Ignored**: starts with another URI scheme (e.g. ``mailto:``, ``tel:``),
|
|
29
|
+
or is a bare same-page anchor (``#section``). These can't be meaningfully
|
|
30
|
+
checked as either a URL or a local file, so no check ever sees them.
|
|
31
|
+
- **Path**: anything else - this includes root-relative paths
|
|
32
|
+
(``/docs/usage.md``), explicitly relative paths (``./img.png``,
|
|
33
|
+
``../docs/usage.md``), and bare relative paths with no prefix
|
|
34
|
+
(``docs/usage.md``). All of these are treated identically and handled by
|
|
35
|
+
``check_broken_paths`` and ``check_paths_tracking``.
|
|
36
|
+
|
|
37
|
+
Fragments on paths
|
|
38
|
+
----------------------
|
|
39
|
+
|
|
40
|
+
A path may carry a trailing ``?query`` and/or ``#anchor`` - for example
|
|
41
|
+
``docs/usage.md#configuration``. Both checks that operate on paths strip
|
|
42
|
+
this fragment before resolving the file, so only the ``docs/usage.md``
|
|
43
|
+
part needs to exist on disk; the anchor itself is never validated against
|
|
44
|
+
the target file's headings.
|
|
45
|
+
|
|
46
|
+
Resolving a path to a file
|
|
47
|
+
--------------------------------
|
|
48
|
+
|
|
49
|
+
``check_broken_paths`` tries to resolve a path relative to the markdown
|
|
50
|
+
file it was found in first (e.g. ``../img.png`` in ``docs/usage.md``
|
|
51
|
+
resolves against ``docs/``), then falls back to resolving it as an
|
|
52
|
+
absolute or current-working-directory-relative path. A path is reported as
|
|
53
|
+
broken only if neither resolution finds an existing file.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
How URL Checking Works
|
|
2
|
+
========================
|
|
3
|
+
|
|
4
|
+
``check_broken_urls`` (and the other URL-based checks) can end up sending
|
|
5
|
+
thousands of requests across a large repository. This page explains the
|
|
6
|
+
pipeline that makes that practical without hammering any single host, and
|
|
7
|
+
why some failures are reported as warnings rather than errors.
|
|
8
|
+
|
|
9
|
+
The life of a URL
|
|
10
|
+
--------------------
|
|
11
|
+
|
|
12
|
+
1. **Extraction.** Every markdown link destination is extracted per file
|
|
13
|
+
(see :doc:`link-detection`) and classified as a URL if it starts with
|
|
14
|
+
``http://``/``https://`` (protocol-relative ``//host/...`` links are
|
|
15
|
+
normalized to ``https://``).
|
|
16
|
+
|
|
17
|
+
2. **Normalization and dedupe.** Before checking, each URL is normalized
|
|
18
|
+
(scheme and host lowercased, trailing slash and fragment dropped; the
|
|
19
|
+
query string is kept). If the same normalized URL appears in fifty
|
|
20
|
+
files, it is only ever requested once - every other occurrence shares
|
|
21
|
+
the same in-flight result.
|
|
22
|
+
|
|
23
|
+
3. **Per-host queueing and pacing.** Requests are grouped by host and paced
|
|
24
|
+
with a minimum delay between two requests to the same host
|
|
25
|
+
(``--per-host-delay``), so a link-heavy file doesn't burst a host with
|
|
26
|
+
many simultaneous requests just because it happens to link to it
|
|
27
|
+
repeatedly.
|
|
28
|
+
|
|
29
|
+
4. **The request itself.** Each URL is checked with a ``HEAD`` request
|
|
30
|
+
first; if that isn't a success, a ``GET`` is attempted as a fallback,
|
|
31
|
+
since some servers reject ``HEAD`` but allow ``GET``. A successful
|
|
32
|
+
(``2xx``) response on either is treated as ``alive``.
|
|
33
|
+
|
|
34
|
+
5. **Hard-failure retries.** If neither request succeeds and there's no
|
|
35
|
+
rate-limit or auth signal, the attempt is retried with exponential
|
|
36
|
+
backoff up to ``--retries`` times before being reported as ``broken``.
|
|
37
|
+
|
|
38
|
+
6. **Rate limiting and auth errors return immediately.** A ``429`` (or any
|
|
39
|
+
non-success response carrying ``Retry-After``) is reported as
|
|
40
|
+
``rate_limited`` right away - it is *not* retried in place. Likewise, a
|
|
41
|
+
``401``/``403`` response is reported as ``unverifiable`` immediately:
|
|
42
|
+
the server is reachable but blocking automated access, and retrying
|
|
43
|
+
won't change that. Retrying either case would only generate more
|
|
44
|
+
traffic against a host that's already unhappy with us.
|
|
45
|
+
|
|
46
|
+
7. **Host circuit breaker.** When a host produces two rate-limited
|
|
47
|
+
responses in a row, it's treated as persistently throttled: every other
|
|
48
|
+
URL already queued for that host is resolved as ``rate_limited``
|
|
49
|
+
without spending a network request on each, and the host is blocked
|
|
50
|
+
from new requests until its ``Retry-After`` window elapses.
|
|
51
|
+
|
|
52
|
+
8. **Backpressure.** The number of URL checks in flight at once is bounded
|
|
53
|
+
(``max_pending`` in the underlying configuration), so checking a huge
|
|
54
|
+
repository doesn't grow memory unboundedly - submitting more work simply
|
|
55
|
+
waits for a slot to free up.
|
|
56
|
+
|
|
57
|
+
Why warnings don't fail the build
|
|
58
|
+
-------------------------------------
|
|
59
|
+
|
|
60
|
+
``rate_limited``, ``unverifiable``, and ``transient_error`` all mean the
|
|
61
|
+
checker *couldn't determine* whether the link is actually broken - the host
|
|
62
|
+
is either throttling, blocking bots, or momentarily unreachable. Treating
|
|
63
|
+
these the same as a confirmed ``404`` would make CI fail on
|
|
64
|
+
infrastructure noise rather than real broken links, so they're reported as
|
|
65
|
+
warnings instead: visible, but never blocking. Only ``broken`` (a
|
|
66
|
+
confirmed non-2xx response with no rate-limit/auth signal) is an
|
|
67
|
+
error. See :doc:`../reference/exit-codes` for the full status table.
|
|
68
|
+
|
|
69
|
+
Overlapping file processing
|
|
70
|
+
-------------------------------
|
|
71
|
+
|
|
72
|
+
Separately from URL-level concurrency, files themselves are processed
|
|
73
|
+
through an adaptive window: a file's links are submitted for checking as
|
|
74
|
+
soon as they're extracted, without waiting for earlier files' checks to
|
|
75
|
+
finish first. This overlaps link extraction and I/O wait time across
|
|
76
|
+
files, while still bounding how many files can be "in flight"
|
|
77
|
+
simultaneously so memory use stays predictable regardless of how many
|
|
78
|
+
links a single file happens to contain.
|