markwork 0.1.1rc0__tar.gz → 0.1.2.dev0__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.
Files changed (91) hide show
  1. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/PKG-INFO +82 -19
  2. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/README.md +78 -15
  3. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/pyproject.toml +12 -4
  4. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork/__init__.py +22 -7
  5. markwork-0.1.2.dev0/src/markwork/__main__.py +11 -0
  6. markwork-0.1.2.dev0/src/markwork/_cli.py +279 -0
  7. markwork-0.1.2.dev0/src/markwork/_layout.py +214 -0
  8. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork/engine/__init__.py +24 -12
  9. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork/engine/_abs_module.py +6 -2
  10. markwork-0.1.2.dev0/src/markwork/engine/_attribute_chain.py +37 -0
  11. markwork-0.1.2.dev0/src/markwork/engine/_char_offset.py +46 -0
  12. markwork-0.1.2.dev0/src/markwork/engine/_collapse_navigation.py +42 -0
  13. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork/engine/_detect_package.py +18 -7
  14. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork/engine/_generate.py +15 -4
  15. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork/engine/_highlight.py +7 -9
  16. markwork-0.1.2.dev0/src/markwork/engine/_lex_tokens.py +35 -0
  17. markwork-0.1.2.dev0/src/markwork/engine/_module_definitions.py +54 -0
  18. markwork-0.1.2.dev0/src/markwork/engine/_module_statements.py +51 -0
  19. markwork-0.1.2.dev0/src/markwork/engine/_parse_init.py +93 -0
  20. markwork-0.1.2.dev0/src/markwork/engine/_parse_source.py +37 -0
  21. markwork-0.1.2.dev0/src/markwork/engine/_read_source.py +40 -0
  22. markwork-0.1.2.dev0/src/markwork/engine/_resolve_scopes.py +165 -0
  23. markwork-0.1.2.dev0/src/markwork/engine/_rst_text.py +39 -0
  24. markwork-0.1.2.dev0/src/markwork/engine/_scope.py +119 -0
  25. markwork-0.1.2.dev0/src/markwork/engine/_source_docs.py +1168 -0
  26. markwork-0.1.2.dev0/src/markwork/engine/_title.py +34 -0
  27. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork/engine/_token_html.py +25 -10
  28. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork.egg-info/PKG-INFO +82 -19
  29. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork.egg-info/SOURCES.txt +26 -9
  30. markwork-0.1.2.dev0/src/markwork.egg-info/entry_points.txt +2 -0
  31. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork.egg-info/requires.txt +1 -0
  32. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_abs_module.py +6 -1
  33. markwork-0.1.2.dev0/tests/test_attribute_chain.py +22 -0
  34. markwork-0.1.2.dev0/tests/test_char_offset.py +33 -0
  35. markwork-0.1.2.dev0/tests/test_cli.py +205 -0
  36. markwork-0.1.2.dev0/tests/test_collapse_navigation.py +41 -0
  37. markwork-0.1.2.dev0/tests/test_definition_links.py +228 -0
  38. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_detect_package.py +17 -4
  39. markwork-0.1.2.dev0/tests/test_dogfood.py +69 -0
  40. markwork-0.1.2.dev0/tests/test_emit_package.py +111 -0
  41. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_highlight.py +16 -0
  42. markwork-0.1.2.dev0/tests/test_layout.py +136 -0
  43. markwork-0.1.2.dev0/tests/test_locate.py +177 -0
  44. markwork-0.1.2.dev0/tests/test_module_definitions.py +71 -0
  45. markwork-0.1.2.dev0/tests/test_module_statements.py +47 -0
  46. markwork-0.1.2.dev0/tests/test_parse_init.py +76 -0
  47. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_paths.py +2 -0
  48. markwork-0.1.2.dev0/tests/test_read_source.py +58 -0
  49. markwork-0.1.2.dev0/tests/test_regressions.py +73 -0
  50. markwork-0.1.2.dev0/tests/test_resolve_scopes.py +181 -0
  51. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_run.py +26 -0
  52. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_scan_usages.py +39 -0
  53. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_setup.py +9 -3
  54. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_token_html.py +18 -3
  55. markwork-0.1.1rc0/src/markwork/engine/_add_alias_site.py +0 -31
  56. markwork-0.1.1rc0/src/markwork/engine/_bound_anywhere.py +0 -42
  57. markwork-0.1.1rc0/src/markwork/engine/_module_definitions.py +0 -42
  58. markwork-0.1.1rc0/src/markwork/engine/_nested_bound.py +0 -53
  59. markwork-0.1.1rc0/src/markwork/engine/_parse_init.py +0 -52
  60. markwork-0.1.1rc0/src/markwork/engine/_source_docs.py +0 -620
  61. markwork-0.1.1rc0/src/markwork/engine/_title.py +0 -26
  62. markwork-0.1.1rc0/src/markwork/engine/_top_level_def_lines.py +0 -34
  63. markwork-0.1.1rc0/src/markwork/engine/_top_level_defs.py +0 -33
  64. markwork-0.1.1rc0/tests/test_bound_anywhere.py +0 -28
  65. markwork-0.1.1rc0/tests/test_definition_links.py +0 -111
  66. markwork-0.1.1rc0/tests/test_emit_package.py +0 -58
  67. markwork-0.1.1rc0/tests/test_module_definitions.py +0 -43
  68. markwork-0.1.1rc0/tests/test_nested_bound.py +0 -37
  69. markwork-0.1.1rc0/tests/test_parse_init.py +0 -39
  70. markwork-0.1.1rc0/tests/test_top_level.py +0 -38
  71. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/LICENSE +0 -0
  72. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/setup.cfg +0 -0
  73. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork/engine/_builtin_links.py +0 -0
  74. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork/engine/_css_class.py +0 -0
  75. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork/engine/_is_stdlib.py +0 -0
  76. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork/engine/_line_starts.py +0 -0
  77. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork/engine/_merge_tokens.py +0 -0
  78. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork/engine/_pydocs.py +0 -0
  79. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork/etc/markwork.css +0 -0
  80. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork.egg-info/dependency_links.txt +0 -0
  81. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/src/markwork.egg-info/top_level.txt +0 -0
  82. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_anchors.py +0 -0
  83. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_append_section.py +0 -0
  84. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_builtin_links.py +0 -0
  85. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_css_class.py +0 -0
  86. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_emit_tests.py +0 -0
  87. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_is_stdlib.py +0 -0
  88. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_line_starts.py +0 -0
  89. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_merge_tokens.py +0 -0
  90. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_network_anchors.py +0 -0
  91. {markwork-0.1.1rc0 → markwork-0.1.2.dev0}/tests/test_no_regex.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markwork
3
- Version: 0.1.1rc0
3
+ Version: 0.1.2.dev0
4
4
  Summary: Sphinx docs without autodoc: your source, made click-through.
5
5
  Author-email: Asger Jon Vistisen <asgerjon2@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -13,25 +13,25 @@ Classifier: Framework :: Sphinx :: Extension
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: Operating System :: OS Independent
15
15
  Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.10
17
- Classifier: Programming Language :: Python :: 3.11
18
16
  Classifier: Programming Language :: Python :: 3.12
19
17
  Classifier: Programming Language :: Python :: 3.13
20
18
  Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Programming Language :: Python :: 3.15
21
20
  Classifier: Topic :: Documentation :: Sphinx
22
21
  Classifier: Topic :: Software Development :: Documentation
23
- Requires-Python: >=3.10
22
+ Requires-Python: >=3.12
24
23
  Description-Content-Type: text/markdown
25
24
  License-File: LICENSE
26
25
  Requires-Dist: sphinx>=7
27
26
  Requires-Dist: pygments
27
+ Requires-Dist: furo
28
28
  Dynamic: license-file
29
29
 
30
30
  [![PyPI version](https://badge.fury.io/py/markwork.svg)](https://pypi.org/project/markwork/)
31
31
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
32
32
  [![Framework: Sphinx](https://img.shields.io/badge/Sphinx-extension-1A5276.svg)](https://www.sphinx-doc.org/)
33
33
 
34
- # markwork v0.1.0 (alpha)
34
+ # markwork v0.1.2-dev0 (development build)
35
35
 
36
36
  **markwork** publishes your source as your documentation. The page for a
37
37
  file *is* that file: rendered verbatim, syntax-highlighted, and with every
@@ -43,6 +43,7 @@ Stop documenting your code. Start publishing it.
43
43
  # Table of Contents
44
44
 
45
45
  - [Installation](#installation)
46
+ - [Point It at a Repo](#point-it-at-a-repo)
46
47
  - [You Already Wrote the Docs](#you-already-wrote-the-docs)
47
48
  - [Click a Name, Land on the Definition](#click-a-name-land-on-the-definition)
48
49
  - [Every Page Ends With Its Tests](#every-page-ends-with-its-tests)
@@ -59,8 +60,46 @@ Install with pip:
59
60
  pip install markwork
60
61
  ```
61
62
 
62
- This pulls in Sphinx and Pygments. markwork rides on Sphinx for the HTML
63
- shell, search, theme, and hosting. What it replaces is autodoc.
63
+ This pulls in Sphinx, Pygments and the furo theme. markwork rides on
64
+ Sphinx for the HTML shell, search, theme, and hosting. What it replaces is
65
+ autodoc.
66
+
67
+ # Point It at a Repo
68
+
69
+ Want to see it before wiring anything up? Point markwork at a repository
70
+ and it renders the whole thing, with no `conf.py`, no `index.rst` and
71
+ nothing scaffolded into the project:
72
+
73
+ ```bash
74
+ markwork path/to/repo --open
75
+ ```
76
+
77
+ That generates a throwaway Sphinx config in a temporary directory, reads
78
+ the project's source in place, builds the click-through HTML, and opens it
79
+ in your browser. The repository is left untouched; only the rendered HTML
80
+ is written, to a temporary directory by default or wherever `-o` points:
81
+
82
+ ```bash
83
+ markwork . -o public/ # build the current repo into ./public
84
+ ```
85
+
86
+ markwork auto-detects the layout from what your project already declares.
87
+ The source root and package come from your build configuration (setuptools
88
+ `packages.find.where` / `package-dir` in `pyproject.toml`, with the
89
+ distribution name picking the package when several qualify), falling back
90
+ to `src/` (or the repo root) and the lone package it finds. The tests are
91
+ expected in `tests/`. markwork does not go looking for them, so a project
92
+ that keeps them elsewhere says where with `--tests`. It prints what it
93
+ resolved, and an ambiguous package stops the build with a clear message
94
+ rather than guessing. Override any of it with `--src`,
95
+ `--tests`, `--package` or `--theme` (`markwork --help` lists them; the
96
+ theme is furo when installed, alabaster otherwise). Sphinx writes the
97
+ pages with one worker per CPU; `-j 1` builds serially. The same build
98
+ runs as `python -m markwork`.
99
+
100
+ This zero-config command is for previews and one-off renders. To **host**
101
+ the docs (for example on Read the Docs), commit a `docs/conf.py` with the
102
+ one-line extension instead; see [Quickstart](#quickstart).
64
103
 
65
104
  # You Already Wrote the Docs
66
105
 
@@ -126,7 +165,7 @@ Now you are. Add one line to `conf.py`:
126
165
  extensions = ["markwork"]
127
166
  ```
128
167
 
129
- markwork publishes the function — docstring, signature, body, all of it —
168
+ markwork publishes the function (docstring, signature, body, all of it)
130
169
  exactly as you wrote it. The page is the source. You already finished the
131
170
  documentation; you just did not know it yet.
132
171
 
@@ -134,7 +173,7 @@ documentation; you just did not know it yet.
134
173
 
135
174
  markwork reads your syntax tree, so every name on the page is wired to
136
175
  where it comes from. You do not read the docs by scrolling. You read them
137
- the way you read code — by following definitions:
176
+ the way you read code, by following definitions:
138
177
 
139
178
  ```
140
179
  widget.py click Point → geometry.py:14 (the def, highlighted)
@@ -143,15 +182,18 @@ sequences.py click fib → sequences.py:30 (back to its own def)
143
182
  ```
144
183
 
145
184
  Project symbols and same-file names jump inside your docs, at the exact
146
- line. Standard-library members and builtins jump to the official Python
147
- documentation. A name shadowed by a local binding stays unlinked, so a
148
- link never sends you somewhere wrong.
185
+ line, and so does the `Thing` in `pkg.mod.Thing`. Standard-library members
186
+ and builtins jump to the official Python documentation. Names are resolved
187
+ by Python's own scoping rules: a parameter, a method or an `except ... as`
188
+ name shadows only the scope it lives in. Anything markwork cannot pin down
189
+ for certain, such as a name a star import may have replaced or one bound
190
+ two ways, stays unlinked, so a link never sends you somewhere wrong.
149
191
 
150
192
  # Every Page Ends With Its Tests
151
193
 
152
194
  Scroll to the bottom of any symbol's page and the tests that exercise it
153
- are waiting there — listed for you, no digging, file and line, each line a
154
- link straight to the assertion:
195
+ are waiting there. They are listed for you by file and line, with no
196
+ digging, and each line is a link straight to the assertion:
155
197
 
156
198
  ```
157
199
  fib()
@@ -181,7 +223,9 @@ acme/
181
223
  markwork follows your **public API**: every name in the package's `__all__`
182
224
  becomes a page, a re-exported symbol pulls in its defining file, and the
183
225
  `tests/` tree is mirrored for you. So the package's `__init__.py` is your
184
- table of contents:
226
+ table of contents. A re-export is followed however far it goes, through
227
+ subpackages, aliases and star imports, to the file that really defines
228
+ it:
185
229
 
186
230
  ```python
187
231
  # src/acme/__init__.py
@@ -190,8 +234,14 @@ from .widget import Widget
190
234
  __all__ = ["Widget"]
191
235
  ```
192
236
 
193
- `docs/index.rst` needs a single include — markwork writes the tree into
194
- `_source/`:
237
+ No `__all__`? Then the public names are the ones without a leading
238
+ underscore: whatever `__init__.py` defines or imports, then its
239
+ submodules and subpackages. A name in `__all__` that leads nowhere is a
240
+ build warning, never a silently missing page; silence those with
241
+ `suppress_warnings = ["markwork"]` if you must.
242
+
243
+ `docs/index.rst` needs a single include, since markwork writes the tree
244
+ into `_source/`:
195
245
 
196
246
  ```rst
197
247
  acme
@@ -203,7 +253,7 @@ acme
203
253
  Build it:
204
254
 
205
255
  ```bash
206
- pip install markwork furo
256
+ pip install markwork
207
257
  sphinx-build -b html docs docs/_build/html
208
258
  ```
209
259
 
@@ -220,6 +270,19 @@ markwork_src_root = "src" # source root, relative to the project
220
270
  markwork_tests_root = "tests" # test root, relative to the project
221
271
  ```
222
272
 
273
+ Each page's sidebar holds the top level and the branch the page is on,
274
+ not the whole site: with a page per source file, a full tree on every
275
+ page grows the site with the square of its size (it was two thirds of
276
+ worktoy's 61 MB). Set `markwork_collapse_navigation = False` to keep your
277
+ theme's own choice. Since each page's rST is a generated wrapper around a
278
+ source file, these two lines are worth adding too; the `markwork` command
279
+ sets them for you:
280
+
281
+ ```python
282
+ html_copy_source = False
283
+ html_show_sourcelink = False
284
+ ```
285
+
223
286
  Flat layout, with the package at the project root instead of under `src/`?
224
287
  Point the source root at the root and name the package explicitly:
225
288
 
@@ -228,7 +291,7 @@ markwork_src_root = "."
228
291
  markwork_package = "acme"
229
292
  ```
230
293
 
231
- Requires Python 3.10 or newer.
294
+ Requires Python 3.12 or newer.
232
295
 
233
296
  # Themes
234
297
 
@@ -2,7 +2,7 @@
2
2
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
3
3
  [![Framework: Sphinx](https://img.shields.io/badge/Sphinx-extension-1A5276.svg)](https://www.sphinx-doc.org/)
4
4
 
5
- # markwork v0.1.0 (alpha)
5
+ # markwork v0.1.2-dev0 (development build)
6
6
 
7
7
  **markwork** publishes your source as your documentation. The page for a
8
8
  file *is* that file: rendered verbatim, syntax-highlighted, and with every
@@ -14,6 +14,7 @@ Stop documenting your code. Start publishing it.
14
14
  # Table of Contents
15
15
 
16
16
  - [Installation](#installation)
17
+ - [Point It at a Repo](#point-it-at-a-repo)
17
18
  - [You Already Wrote the Docs](#you-already-wrote-the-docs)
18
19
  - [Click a Name, Land on the Definition](#click-a-name-land-on-the-definition)
19
20
  - [Every Page Ends With Its Tests](#every-page-ends-with-its-tests)
@@ -30,8 +31,46 @@ Install with pip:
30
31
  pip install markwork
31
32
  ```
32
33
 
33
- This pulls in Sphinx and Pygments. markwork rides on Sphinx for the HTML
34
- shell, search, theme, and hosting. What it replaces is autodoc.
34
+ This pulls in Sphinx, Pygments and the furo theme. markwork rides on
35
+ Sphinx for the HTML shell, search, theme, and hosting. What it replaces is
36
+ autodoc.
37
+
38
+ # Point It at a Repo
39
+
40
+ Want to see it before wiring anything up? Point markwork at a repository
41
+ and it renders the whole thing, with no `conf.py`, no `index.rst` and
42
+ nothing scaffolded into the project:
43
+
44
+ ```bash
45
+ markwork path/to/repo --open
46
+ ```
47
+
48
+ That generates a throwaway Sphinx config in a temporary directory, reads
49
+ the project's source in place, builds the click-through HTML, and opens it
50
+ in your browser. The repository is left untouched; only the rendered HTML
51
+ is written, to a temporary directory by default or wherever `-o` points:
52
+
53
+ ```bash
54
+ markwork . -o public/ # build the current repo into ./public
55
+ ```
56
+
57
+ markwork auto-detects the layout from what your project already declares.
58
+ The source root and package come from your build configuration (setuptools
59
+ `packages.find.where` / `package-dir` in `pyproject.toml`, with the
60
+ distribution name picking the package when several qualify), falling back
61
+ to `src/` (or the repo root) and the lone package it finds. The tests are
62
+ expected in `tests/`. markwork does not go looking for them, so a project
63
+ that keeps them elsewhere says where with `--tests`. It prints what it
64
+ resolved, and an ambiguous package stops the build with a clear message
65
+ rather than guessing. Override any of it with `--src`,
66
+ `--tests`, `--package` or `--theme` (`markwork --help` lists them; the
67
+ theme is furo when installed, alabaster otherwise). Sphinx writes the
68
+ pages with one worker per CPU; `-j 1` builds serially. The same build
69
+ runs as `python -m markwork`.
70
+
71
+ This zero-config command is for previews and one-off renders. To **host**
72
+ the docs (for example on Read the Docs), commit a `docs/conf.py` with the
73
+ one-line extension instead; see [Quickstart](#quickstart).
35
74
 
36
75
  # You Already Wrote the Docs
37
76
 
@@ -97,7 +136,7 @@ Now you are. Add one line to `conf.py`:
97
136
  extensions = ["markwork"]
98
137
  ```
99
138
 
100
- markwork publishes the function — docstring, signature, body, all of it —
139
+ markwork publishes the function (docstring, signature, body, all of it)
101
140
  exactly as you wrote it. The page is the source. You already finished the
102
141
  documentation; you just did not know it yet.
103
142
 
@@ -105,7 +144,7 @@ documentation; you just did not know it yet.
105
144
 
106
145
  markwork reads your syntax tree, so every name on the page is wired to
107
146
  where it comes from. You do not read the docs by scrolling. You read them
108
- the way you read code — by following definitions:
147
+ the way you read code, by following definitions:
109
148
 
110
149
  ```
111
150
  widget.py click Point → geometry.py:14 (the def, highlighted)
@@ -114,15 +153,18 @@ sequences.py click fib → sequences.py:30 (back to its own def)
114
153
  ```
115
154
 
116
155
  Project symbols and same-file names jump inside your docs, at the exact
117
- line. Standard-library members and builtins jump to the official Python
118
- documentation. A name shadowed by a local binding stays unlinked, so a
119
- link never sends you somewhere wrong.
156
+ line, and so does the `Thing` in `pkg.mod.Thing`. Standard-library members
157
+ and builtins jump to the official Python documentation. Names are resolved
158
+ by Python's own scoping rules: a parameter, a method or an `except ... as`
159
+ name shadows only the scope it lives in. Anything markwork cannot pin down
160
+ for certain, such as a name a star import may have replaced or one bound
161
+ two ways, stays unlinked, so a link never sends you somewhere wrong.
120
162
 
121
163
  # Every Page Ends With Its Tests
122
164
 
123
165
  Scroll to the bottom of any symbol's page and the tests that exercise it
124
- are waiting there — listed for you, no digging, file and line, each line a
125
- link straight to the assertion:
166
+ are waiting there. They are listed for you by file and line, with no
167
+ digging, and each line is a link straight to the assertion:
126
168
 
127
169
  ```
128
170
  fib()
@@ -152,7 +194,9 @@ acme/
152
194
  markwork follows your **public API**: every name in the package's `__all__`
153
195
  becomes a page, a re-exported symbol pulls in its defining file, and the
154
196
  `tests/` tree is mirrored for you. So the package's `__init__.py` is your
155
- table of contents:
197
+ table of contents. A re-export is followed however far it goes, through
198
+ subpackages, aliases and star imports, to the file that really defines
199
+ it:
156
200
 
157
201
  ```python
158
202
  # src/acme/__init__.py
@@ -161,8 +205,14 @@ from .widget import Widget
161
205
  __all__ = ["Widget"]
162
206
  ```
163
207
 
164
- `docs/index.rst` needs a single include — markwork writes the tree into
165
- `_source/`:
208
+ No `__all__`? Then the public names are the ones without a leading
209
+ underscore: whatever `__init__.py` defines or imports, then its
210
+ submodules and subpackages. A name in `__all__` that leads nowhere is a
211
+ build warning, never a silently missing page; silence those with
212
+ `suppress_warnings = ["markwork"]` if you must.
213
+
214
+ `docs/index.rst` needs a single include, since markwork writes the tree
215
+ into `_source/`:
166
216
 
167
217
  ```rst
168
218
  acme
@@ -174,7 +224,7 @@ acme
174
224
  Build it:
175
225
 
176
226
  ```bash
177
- pip install markwork furo
227
+ pip install markwork
178
228
  sphinx-build -b html docs docs/_build/html
179
229
  ```
180
230
 
@@ -191,6 +241,19 @@ markwork_src_root = "src" # source root, relative to the project
191
241
  markwork_tests_root = "tests" # test root, relative to the project
192
242
  ```
193
243
 
244
+ Each page's sidebar holds the top level and the branch the page is on,
245
+ not the whole site: with a page per source file, a full tree on every
246
+ page grows the site with the square of its size (it was two thirds of
247
+ worktoy's 61 MB). Set `markwork_collapse_navigation = False` to keep your
248
+ theme's own choice. Since each page's rST is a generated wrapper around a
249
+ source file, these two lines are worth adding too; the `markwork` command
250
+ sets them for you:
251
+
252
+ ```python
253
+ html_copy_source = False
254
+ html_show_sourcelink = False
255
+ ```
256
+
194
257
  Flat layout, with the package at the project root instead of under `src/`?
195
258
  Point the source root at the root and name the package explicitly:
196
259
 
@@ -199,7 +262,7 @@ markwork_src_root = "."
199
262
  markwork_package = "acme"
200
263
  ```
201
264
 
202
- Requires Python 3.10 or newer.
265
+ Requires Python 3.12 or newer.
203
266
 
204
267
  # Themes
205
268
 
@@ -7,10 +7,10 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "markwork"
10
- version = "0.1.1-rc0"
10
+ version = "0.1.2-dev0"
11
11
  description = "Sphinx docs without autodoc: your source, made click-through."
12
12
  readme = "README.md"
13
- requires-python = ">=3.10"
13
+ requires-python = ">=3.12"
14
14
  license = "Apache-2.0"
15
15
  license-files = ["LICENSE"]
16
16
  authors = [{ name = "Asger Jon Vistisen", email = "asgerjon2@gmail.com" }]
@@ -18,6 +18,7 @@ keywords = ["sphinx", "documentation", "autodoc", "pygments", "source"]
18
18
  dependencies = [
19
19
  "sphinx>=7",
20
20
  "pygments",
21
+ "furo",
21
22
  ]
22
23
  classifiers = [
23
24
  "Development Status :: 3 - Alpha",
@@ -25,11 +26,10 @@ classifiers = [
25
26
  "Intended Audience :: Developers",
26
27
  "Operating System :: OS Independent",
27
28
  "Programming Language :: Python :: 3",
28
- "Programming Language :: Python :: 3.10",
29
- "Programming Language :: Python :: 3.11",
30
29
  "Programming Language :: Python :: 3.12",
31
30
  "Programming Language :: Python :: 3.13",
32
31
  "Programming Language :: Python :: 3.14",
32
+ "Programming Language :: Python :: 3.15",
33
33
  "Topic :: Documentation :: Sphinx",
34
34
  "Topic :: Software Development :: Documentation",
35
35
  ]
@@ -39,12 +39,20 @@ Homepage = "https://github.com/AsgerJon/markwork"
39
39
  Repository = "https://github.com/AsgerJon/markwork"
40
40
  Issues = "https://github.com/AsgerJon/markwork/issues"
41
41
 
42
+ [project.scripts]
43
+ markwork = "markwork._cli:main"
44
+
42
45
  [tool.setuptools.packages.find]
43
46
  where = ["src"]
44
47
 
45
48
  [tool.setuptools.package-data]
46
49
  markwork = ["etc/*.css"]
47
50
 
51
+ [tool.pytest.ini_options]
52
+ testpaths = ["tests"]
53
+ # The suite runs from a checkout without installing the package first.
54
+ pythonpath = ["src"]
55
+
48
56
  [tool.coverage.run]
49
57
  branch = true
50
58
  source = ["markwork", "tests"]
@@ -9,12 +9,12 @@ A project enables it with a single line in conf.py:
9
9
  extensions = ["markwork"]
10
10
 
11
11
  The generator then runs at 'builder-inited', writing one page per source
12
- file into the docs source tree before Sphinx reads it. Three configuration
12
+ file into the docs source tree before Sphinx reads it. Four configuration
13
13
  values steer it: markwork_package names the package to document (or it is
14
14
  auto-detected when a single package sits under the source root),
15
15
  markwork_src_root and markwork_tests_root give the source and test roots
16
- relative to the project, which is taken to be the parent of the docs
17
- directory.
16
+ relative to the project, and markwork_repo_root names the project root,
17
+ relative to the docs directory, which defaults to that directory's parent.
18
18
  """
19
19
  # Apache-2.0 license
20
20
  # Copyright (c) 2026 Asger Jon Vistisen
@@ -22,9 +22,9 @@ directory.
22
22
  from pathlib import Path
23
23
 
24
24
  from . import engine
25
- from .engine import generate
25
+ from .engine import collapseNavigation, generate
26
26
 
27
- __version__ = "0.1.1-rc0"
27
+ __version__ = "0.1.2-dev0"
28
28
 
29
29
  __all__ = ["setup", "generate", "engine"]
30
30
 
@@ -33,16 +33,31 @@ def setup(app: object) -> dict:
33
33
  """Register markwork as a Sphinx extension: declare its configuration
34
34
  values, run the generator before Sphinx reads sources, and ship the
35
35
  stylesheet that styles the go-to-definition anchors and the line-jump
36
- highlight, so a project manages no CSS paths of its own."""
36
+ highlight, so a project manages no CSS paths of its own.
37
+
38
+ markwork_repo_root pins the documented project root; left unset it
39
+ defaults to the parent of the docs directory, so an in-tree docs build
40
+ needs no extra configuration while the 'markwork' CLI can point the
41
+ engine at an arbitrary repository from a throwaway conf directory.
42
+ markwork_collapse_navigation (True by default) keeps every page's
43
+ navigation tree to its own branch; see 'collapseNavigation'."""
37
44
  app.add_config_value("markwork_package", None, "env")
38
45
  app.add_config_value("markwork_src_root", "src", "env")
39
46
  app.add_config_value("markwork_tests_root", "tests", "env")
47
+ app.add_config_value("markwork_repo_root", None, "env")
48
+ app.add_config_value("markwork_collapse_navigation", True, "html")
40
49
  app.connect("builder-inited", generate)
50
+ # Ahead of the theme's own handler (default priority 500), so the
51
+ # theme builds its sidebar from the collapsed tree.
52
+ app.connect("html-page-context", collapseNavigation, priority=400)
41
53
  static = str(Path(__file__).parent / "etc")
42
54
  app.config.html_static_path.append(static)
43
55
  app.add_css_file("markwork.css")
56
+ # The generator runs once, at builder-inited, before any source is
57
+ # read, and keeps nothing in the build environment, so reading and
58
+ # writing may both run in parallel ('sphinx-build -j auto').
44
59
  return {
45
60
  "version": __version__,
46
- "parallel_read_safe": False,
61
+ "parallel_read_safe": True,
47
62
  "parallel_write_safe": True,
48
63
  }
@@ -0,0 +1,11 @@
1
+ """
2
+ Run markwork as a module: 'python -m markwork <repo>' is the same
3
+ ephemeral build as the 'markwork' console script.
4
+ """
5
+ # Apache-2.0 license
6
+ # Copyright (c) 2026 Asger Jon Vistisen
7
+
8
+ from ._cli import main
9
+
10
+ if __name__ == "__main__":
11
+ raise SystemExit(main())