writeadoc 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.
Files changed (61) hide show
  1. writeadoc-0.1.0/PKG-INFO +47 -0
  2. writeadoc-0.1.0/README.md +28 -0
  3. writeadoc-0.1.0/pyproject.toml +179 -0
  4. writeadoc-0.1.0/setup.cfg +4 -0
  5. writeadoc-0.1.0/src/writeadoc/__init__.py +7 -0
  6. writeadoc-0.1.0/src/writeadoc/autodoc.py +303 -0
  7. writeadoc-0.1.0/src/writeadoc/blueprint/assets/css/index.css +41 -0
  8. writeadoc-0.1.0/src/writeadoc/blueprint/assets/css/style.css +1994 -0
  9. writeadoc-0.1.0/src/writeadoc/blueprint/assets/fonts/Inter-LICENSE.txt +92 -0
  10. writeadoc-0.1.0/src/writeadoc/blueprint/assets/fonts/Inter-Variable.woff2 +0 -0
  11. writeadoc-0.1.0/src/writeadoc/blueprint/assets/images/apple-touch-icon.png +0 -0
  12. writeadoc-0.1.0/src/writeadoc/blueprint/assets/images/favicon.png +0 -0
  13. writeadoc-0.1.0/src/writeadoc/blueprint/assets/images/favicon.svg +67 -0
  14. writeadoc-0.1.0/src/writeadoc/blueprint/assets/images/opengraph.png +0 -0
  15. writeadoc-0.1.0/src/writeadoc/blueprint/assets/js/code.js +24 -0
  16. writeadoc-0.1.0/src/writeadoc/blueprint/assets/js/color-scheme.js +22 -0
  17. writeadoc-0.1.0/src/writeadoc/blueprint/assets/js/lunr.da.min.js +18 -0
  18. writeadoc-0.1.0/src/writeadoc/blueprint/assets/js/lunr.de.min.js +18 -0
  19. writeadoc-0.1.0/src/writeadoc/blueprint/assets/js/lunr.es.min.js +18 -0
  20. writeadoc-0.1.0/src/writeadoc/blueprint/assets/js/lunr.fr.min.js +18 -0
  21. writeadoc-0.1.0/src/writeadoc/blueprint/assets/js/lunr.it.min.js +18 -0
  22. writeadoc-0.1.0/src/writeadoc/blueprint/assets/js/lunr.min.js +15 -0
  23. writeadoc-0.1.0/src/writeadoc/blueprint/assets/js/lunr.pt.min.js +18 -0
  24. writeadoc-0.1.0/src/writeadoc/blueprint/assets/js/search.js +96 -0
  25. writeadoc-0.1.0/src/writeadoc/blueprint/assets/js/turbo.min.js +15 -0
  26. writeadoc-0.1.0/src/writeadoc/blueprint/content/index.md +13 -0
  27. writeadoc-0.1.0/src/writeadoc/blueprint/content/sub/ipsum.md +5 -0
  28. writeadoc-0.1.0/src/writeadoc/blueprint/content/sub/lorem.md +7 -0
  29. writeadoc-0.1.0/src/writeadoc/blueprint/content/welcome.md +10 -0
  30. writeadoc-0.1.0/src/writeadoc/blueprint/docs.py +37 -0
  31. writeadoc-0.1.0/src/writeadoc/blueprint/views/autodoc.jinja +119 -0
  32. writeadoc-0.1.0/src/writeadoc/blueprint/views/color_scheme.jinja +17 -0
  33. writeadoc-0.1.0/src/writeadoc/blueprint/views/index.jinja +20 -0
  34. writeadoc-0.1.0/src/writeadoc/blueprint/views/language_popover.jinja +12 -0
  35. writeadoc-0.1.0/src/writeadoc/blueprint/views/layout.jinja +126 -0
  36. writeadoc-0.1.0/src/writeadoc/blueprint/views/metadata.jinja +33 -0
  37. writeadoc-0.1.0/src/writeadoc/blueprint/views/page.jinja +53 -0
  38. writeadoc-0.1.0/src/writeadoc/blueprint/views/pagetoc.jinja +18 -0
  39. writeadoc-0.1.0/src/writeadoc/blueprint/views/pagetoc_select.jinja +13 -0
  40. writeadoc-0.1.0/src/writeadoc/blueprint/views/robots.txt.jinja +4 -0
  41. writeadoc-0.1.0/src/writeadoc/blueprint/views/search.jinja +32 -0
  42. writeadoc-0.1.0/src/writeadoc/blueprint/views/sitemap.xml.jinja +14 -0
  43. writeadoc-0.1.0/src/writeadoc/blueprint/views/strings.json +142 -0
  44. writeadoc-0.1.0/src/writeadoc/blueprint/views/toc.jinja +35 -0
  45. writeadoc-0.1.0/src/writeadoc/blueprint/views/version_popover.jinja +14 -0
  46. writeadoc-0.1.0/src/writeadoc/cli.py +24 -0
  47. writeadoc-0.1.0/src/writeadoc/exceptions.py +5 -0
  48. writeadoc-0.1.0/src/writeadoc/main.py +619 -0
  49. writeadoc-0.1.0/src/writeadoc/pagetoc.py +375 -0
  50. writeadoc-0.1.0/src/writeadoc/search.py +243 -0
  51. writeadoc-0.1.0/src/writeadoc/types.py +169 -0
  52. writeadoc-0.1.0/src/writeadoc/utils.py +210 -0
  53. writeadoc-0.1.0/src/writeadoc.egg-info/PKG-INFO +47 -0
  54. writeadoc-0.1.0/src/writeadoc.egg-info/SOURCES.txt +59 -0
  55. writeadoc-0.1.0/src/writeadoc.egg-info/dependency_links.txt +1 -0
  56. writeadoc-0.1.0/src/writeadoc.egg-info/entry_points.txt +2 -0
  57. writeadoc-0.1.0/src/writeadoc.egg-info/requires.txt +9 -0
  58. writeadoc-0.1.0/src/writeadoc.egg-info/top_level.txt +1 -0
  59. writeadoc-0.1.0/tests/test_autodoc.py +302 -0
  60. writeadoc-0.1.0/tests/test_autodoc_extension.py +0 -0
  61. writeadoc-0.1.0/tests/test_extractor.py +66 -0
@@ -0,0 +1,47 @@
1
+ Metadata-Version: 2.4
2
+ Name: writeadoc
3
+ Version: 0.1.0
4
+ Summary: Focus on your content and let WriteADoc take care of the rest
5
+ Author-email: Juan Pablo Scaletti <juanpablo@jpscaletti.com>
6
+ Project-URL: Homepage, https://writeadoc.scaletti.dev/
7
+ Project-URL: GitHub, https://github.com/jpsca/writeadoc
8
+ Requires-Python: >=3.12
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: docstring-parser>=0.17.0
11
+ Requires-Dist: hecto>=2.0.1
12
+ Requires-Dist: jinja2>=3.1.6
13
+ Requires-Dist: jx>=0.2.0
14
+ Requires-Dist: markdown>=3.8.2
15
+ Requires-Dist: pygments>=2.19.2
16
+ Requires-Dist: pymdown-extensions>=10.16
17
+ Requires-Dist: strictyaml>=1.7.3
18
+ Requires-Dist: watchdog>=6.0.0
19
+
20
+ # <img src="./docs/logo.png" align="middle" />
21
+
22
+ Focus on your content and let WriteADoc take care of the rest
23
+
24
+
25
+ ## Main features
26
+
27
+ * **Simple yet powerful formatting**: Write in Markdown, plus enjoy powerful features like callbacks, flexible code blocks, and _much more_.
28
+ * **Built-in full-text search**: Automatically generates a full-text search index for you. No third-party service required.
29
+ * **Multi-language & multi-version capable**: Easily manage documentation for multiple versions and languages, right out of the box. No plugins or complicated setup needed.
30
+ * **Works on all devices and with light/dark modes**: WriteADoc automatically adapts to perfectly fit the available screen, no matter the type or size of the viewing device and whether you're an early bird or a night owl.
31
+ * **Always yours**: A static site means you can host it anywhere. You own your content and your site. No need to trust your product knowledge to third-party platforms.
32
+
33
+
34
+ ## Documentation
35
+
36
+ [Read the WriteADoc docs][docs] (they’re built with WriteADoc!)
37
+
38
+
39
+ ## License
40
+
41
+ MIT
42
+
43
+ Copyright (c) 2025–present Juan-Pablo Scaletti and [contributors][contributors]
44
+
45
+ [docs]: https://writeadoc.scaletti.dev/
46
+ [contributors]: https://github.com/jpsca/writeadoc/graphs/contributors
47
+ [issues]: https://github.com/jpsca/writeadoc/issues
@@ -0,0 +1,28 @@
1
+ # <img src="./docs/logo.png" align="middle" />
2
+
3
+ Focus on your content and let WriteADoc take care of the rest
4
+
5
+
6
+ ## Main features
7
+
8
+ * **Simple yet powerful formatting**: Write in Markdown, plus enjoy powerful features like callbacks, flexible code blocks, and _much more_.
9
+ * **Built-in full-text search**: Automatically generates a full-text search index for you. No third-party service required.
10
+ * **Multi-language & multi-version capable**: Easily manage documentation for multiple versions and languages, right out of the box. No plugins or complicated setup needed.
11
+ * **Works on all devices and with light/dark modes**: WriteADoc automatically adapts to perfectly fit the available screen, no matter the type or size of the viewing device and whether you're an early bird or a night owl.
12
+ * **Always yours**: A static site means you can host it anywhere. You own your content and your site. No need to trust your product knowledge to third-party platforms.
13
+
14
+
15
+ ## Documentation
16
+
17
+ [Read the WriteADoc docs][docs] (they’re built with WriteADoc!)
18
+
19
+
20
+ ## License
21
+
22
+ MIT
23
+
24
+ Copyright (c) 2025–present Juan-Pablo Scaletti and [contributors][contributors]
25
+
26
+ [docs]: https://writeadoc.scaletti.dev/
27
+ [contributors]: https://github.com/jpsca/writeadoc/graphs/contributors
28
+ [issues]: https://github.com/jpsca/writeadoc/issues
@@ -0,0 +1,179 @@
1
+ [project]
2
+ name = "writeadoc"
3
+ version = "0.1.0"
4
+ description = "Focus on your content and let WriteADoc take care of the rest"
5
+ authors = [
6
+ {name = "Juan Pablo Scaletti", email = "juanpablo@jpscaletti.com"},
7
+ ]
8
+ license = { "file" = "MIT-LICENSE" }
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ dependencies = [
12
+ "docstring-parser>=0.17.0",
13
+ "hecto>=2.0.1",
14
+ "jinja2>=3.1.6",
15
+ "jx>=0.2.0",
16
+ "markdown>=3.8.2",
17
+ "pygments>=2.19.2",
18
+ "pymdown-extensions>=10.16",
19
+ "strictyaml>=1.7.3",
20
+ "watchdog>=6.0.0",
21
+ ]
22
+
23
+ [project.urls]
24
+ Homepage = "https://writeadoc.scaletti.dev/"
25
+ GitHub = "https://github.com/jpsca/writeadoc"
26
+
27
+ [dependency-groups]
28
+ dev = [
29
+ "ipdb>=0.13.13",
30
+ "ruff>=0.12.4",
31
+ "tox-uv",
32
+ "ty>=0.0.1a15",
33
+ ]
34
+ test = [
35
+ "pytest>=8.4.1",
36
+ ]
37
+
38
+ [project.scripts]
39
+ writeadoc = "writeadoc.cli:run"
40
+
41
+
42
+
43
+ [tool.setuptools.packages.find]
44
+ where = ["src"]
45
+
46
+ [tool.setuptools.package-data]
47
+ writeadoc = [
48
+ "blueprint/**",
49
+ ]
50
+ [tool.setuptools.exclude-package-data]
51
+ "*" = [
52
+ "**/__pycache__",
53
+ "*.pyc",
54
+ "*.pyo",
55
+ ]
56
+
57
+ [tool.coverage.run]
58
+ branch = true
59
+
60
+ [tool.coverage.report]
61
+ exclude_lines = [
62
+ "pragma: no cover",
63
+ "TYPE_CHECKING",
64
+ "def __repr__",
65
+ "def __str__",
66
+ "raise AssertionError",
67
+ "raise NotImplementedError",
68
+ "if __name__ == .__main__.:"
69
+ ]
70
+ omit = [
71
+ "src/writeadoc/blueprint/**",
72
+ ]
73
+
74
+ [tool.coverage.html]
75
+ directory = "covreport"
76
+
77
+
78
+ [tool.pytest.ini_options]
79
+ addopts = "--doctest-modules --ignore=src/writeadoc/blueprint"
80
+
81
+
82
+ [tool.tox]
83
+ legacy_tox_ini = """
84
+ [tox]
85
+ env_list =
86
+ 3.12
87
+ 3.13
88
+ 3.14
89
+
90
+ [testenv]
91
+ runner = uv-venv-lock-runner
92
+ dependency_groups =
93
+ dev
94
+ test
95
+ commands =
96
+ pytest -x src/writeadoc tests
97
+ """
98
+
99
+ [tool.ruff]
100
+ line-length = 90
101
+ indent-width = 4
102
+ target-version = "py312"
103
+ exclude = [
104
+ ".*",
105
+ "_build",
106
+ "build",
107
+ "covreport",
108
+ "dist",
109
+ "src/writeadoc/blueprint/*",
110
+ ]
111
+ include = ["*.py"]
112
+
113
+ [tool.ruff.format]
114
+ # Like Black, use double quotes for strings.
115
+ quote-style = "double"
116
+
117
+ # Like Black, indent with spaces, rather than tabs.
118
+ indent-style = "space"
119
+
120
+ # Like Black, respect magic trailing commas.
121
+ skip-magic-trailing-comma = false
122
+
123
+ # Like Black, automatically detect the appropriate line ending.
124
+ line-ending = "auto"
125
+
126
+ # Enable auto-formatting of code examples in docstrings. Markdown,
127
+ # reStructuredText code/literal blocks and doctests are all supported.
128
+ #
129
+ # This is currently disabled by default, but it is planned for this
130
+ # to be opt-out in the future.
131
+ docstring-code-format = false
132
+
133
+ # Set the line length limit used when formatting code snippets in
134
+ # docstrings.
135
+ #
136
+ # This only has an effect when the `docstring-code-format` setting is
137
+ # enabled.
138
+ docstring-code-line-length = "dynamic"
139
+
140
+ [tool.ruff.lint]
141
+ fixable = ["ALL"]
142
+
143
+ ignore = [
144
+ # x is too complex
145
+ "C901",
146
+ # whitespace before ':'
147
+ "E203",
148
+ "E501",
149
+ # x defined from star imports
150
+ "F405",
151
+ # line break before binary operator
152
+ "W505",
153
+ "W605",
154
+ ]
155
+ select = [
156
+ # bugbear
157
+ "B",
158
+ # mccabe"", comprehensions, commas
159
+ "C",
160
+ # pycodestyle errors
161
+ "E",
162
+ # pyflakes
163
+ "F",
164
+ # logging format
165
+ "G",
166
+ # imports
167
+ "I",
168
+ # quotes
169
+ "Q",
170
+ # pycodestyle warnings
171
+ "W",
172
+ ]
173
+
174
+ [tool.ruff.lint.isort]
175
+ known-first-party = ["writeadoc"]
176
+ known-local-folder = ["src/writeadoc"]
177
+
178
+ # Use two line after imports.
179
+ lines-after-imports = 2
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,7 @@
1
+ from .exceptions import * # noqa
2
+ from .main import Docs # noqa
3
+ from .types import * # noqa
4
+ from .utils import (
5
+ DEFAULT_MD_EXTENSIONS, # noqa
6
+ DEFAULT_MD_CONFIG, # noqa
7
+ )
@@ -0,0 +1,303 @@
1
+ import inspect
2
+ import typing as t
3
+ from dataclasses import dataclass, field
4
+ from importlib import import_module
5
+
6
+ from docstring_parser import parse
7
+ from docstring_parser.common import (
8
+ DocstringDeprecated,
9
+ DocstringExample,
10
+ DocstringParam,
11
+ DocstringRaises,
12
+ DocstringReturns,
13
+ )
14
+
15
+
16
+ @dataclass(slots=True)
17
+ class AttrDocstring:
18
+ symbol: str = ""
19
+ name: str = ""
20
+ label: str = "attribute"
21
+ short_description: str = ""
22
+ long_description: str = ""
23
+ description: str = ""
24
+
25
+
26
+ @dataclass(slots=True)
27
+ class Docstring:
28
+ name: str = ""
29
+ symbol: str = ""
30
+ label: str = ""
31
+ signature: str = ""
32
+ params: list[AttrDocstring] = field(default_factory=list)
33
+
34
+ # First paragraph of the description
35
+ short_description: str = ""
36
+ # Rest of the description
37
+ long_description: str = ""
38
+ # The full description
39
+ description: str = ""
40
+
41
+ # Deprecation notes
42
+ deprecation: DocstringDeprecated | None = None
43
+ # A list of examples.
44
+ examples: list[DocstringExample] = field(default_factory=list)
45
+ # Return information.
46
+ returns: DocstringReturns | None = None
47
+ # A list of multiple return values.
48
+ many_returns: list[DocstringReturns] = field(default_factory=list)
49
+ # A list of exceptions that the function may raise.
50
+ raises: list[DocstringRaises] = field(default_factory=list)
51
+
52
+ # Inheritance information
53
+ bases: list[str] = field(default_factory=list)
54
+ # Attributes
55
+ attrs: list[AttrDocstring] = field(default_factory=list)
56
+ # Properties
57
+ properties: list[AttrDocstring] = field(default_factory=list)
58
+ # Methods
59
+ methods: list["Docstring"] = field(default_factory=list)
60
+
61
+
62
+ class Autodoc:
63
+ def __call__(
64
+ self,
65
+ name: str,
66
+ *,
67
+ include: tuple[str, ...] = (),
68
+ exclude: tuple[str, ...] = (),
69
+ ) -> Docstring:
70
+ module_name, obj_name = name.rsplit(".", 1)
71
+ module = import_module(module_name)
72
+ assert module
73
+ obj = getattr(module, obj_name, None)
74
+ if not obj:
75
+ raise ValueError(f"Object {obj_name} not found in module {module_name}")
76
+
77
+ return self.autodoc_obj(obj, include=include, exclude=exclude)
78
+
79
+ def autodoc_obj(
80
+ self,
81
+ obj: t.Any,
82
+ *,
83
+ include: tuple[str, ...] = (),
84
+ exclude: tuple[str, ...] = (),
85
+ ) -> Docstring:
86
+ if inspect.isclass(obj):
87
+ ds = self.autodoc_class(obj, include=include, exclude=exclude)
88
+ elif inspect.isfunction(obj) or inspect.ismethod(obj):
89
+ ds = self.autodoc_function(obj)
90
+ else:
91
+ ds = Docstring()
92
+ return ds
93
+
94
+ def autodoc_class(
95
+ self,
96
+ obj: t.Any,
97
+ *,
98
+ symbol: str = "class",
99
+ include: tuple[str, ...] = (),
100
+ exclude: tuple[str, ...] = (),
101
+ ) -> Docstring:
102
+ init = getattr(obj, "__init__", None)
103
+ obj_name = obj.__name__
104
+ ds = parse(obj.__doc__ or init.__doc__ or "")
105
+
106
+ description = (ds.description or "").strip()
107
+ short_description, long_description = self.split_description(description)
108
+
109
+ params = []
110
+ attrs = []
111
+ properties = []
112
+ methods = []
113
+
114
+ for param in ds.params:
115
+ doc = self.autodoc_attr(param)
116
+ if param.args[0] == "param":
117
+ params.append(doc)
118
+ elif param.args[0] == "attribute":
119
+ attrs.append(doc)
120
+
121
+ for name, value in inspect.getmembers(obj):
122
+ if name.startswith("_") and name not in include:
123
+ continue
124
+ if name in exclude:
125
+ continue
126
+ if inspect.isfunction(value):
127
+ methods.append(self.autodoc_function(value, symbol="method"))
128
+ continue
129
+ if isinstance(value, property):
130
+ properties.append(self.autodoc_property(name, value))
131
+ continue
132
+
133
+ if ds.deprecation:
134
+ ds.deprecation.description = (ds.deprecation.description or "").strip()
135
+ if ds.returns:
136
+ ds.returns.description = (ds.returns.description or "").strip()
137
+ for meta in ds.raises:
138
+ meta.description = (meta.description or "").strip()
139
+ for meta in ds.many_returns:
140
+ meta.description = (meta.description or "").strip()
141
+ for meta in ds.examples:
142
+ meta.snippet = (meta.snippet or "").strip()
143
+ meta.description = (meta.description or "").strip()
144
+
145
+ return Docstring(
146
+ symbol=symbol,
147
+ name=obj_name,
148
+ signature=self.get_signature(obj_name, init),
149
+ params=params,
150
+ short_description=short_description,
151
+ long_description=long_description,
152
+ description=description,
153
+ deprecation=ds.deprecation,
154
+ returns=ds.returns,
155
+ raises=ds.raises,
156
+ examples=ds.examples,
157
+ many_returns=ds.many_returns,
158
+ bases=[base.__name__ for base in obj.__bases__ if base.__name__ != "object"],
159
+ attrs=attrs,
160
+ properties=properties,
161
+ methods=methods,
162
+ )
163
+
164
+ def autodoc_function(self, obj: t.Any, *, symbol: str = "function") -> Docstring:
165
+ obj_name = obj.__name__
166
+ ds = parse(obj.__doc__ or "")
167
+
168
+ description = (ds.description or "").strip()
169
+ short_description, long_description = self.split_description(description)
170
+ params = [self.autodoc_attr(param) for param in ds.params]
171
+
172
+ if ds.deprecation:
173
+ ds.deprecation.description = (ds.deprecation.description or "").strip()
174
+ if ds.returns:
175
+ ds.returns.description = (ds.returns.description or "").strip()
176
+ for meta in ds.raises:
177
+ meta.description = (meta.description or "").strip()
178
+ for meta in ds.many_returns:
179
+ meta.description = (meta.description or "").strip()
180
+ for meta in ds.examples:
181
+ meta.snippet = (meta.snippet or "").strip()
182
+ meta.description = (meta.description or "").strip()
183
+
184
+ return Docstring(
185
+ name=obj_name,
186
+ symbol=symbol,
187
+ signature=self.get_signature(obj_name, obj),
188
+ params=params,
189
+ short_description=short_description,
190
+ long_description=long_description,
191
+ description=description,
192
+ deprecation=ds.deprecation,
193
+ returns=ds.returns,
194
+ raises=ds.raises,
195
+ examples=ds.examples,
196
+ many_returns=ds.many_returns,
197
+ )
198
+
199
+ def autodoc_property(
200
+ self, name: str, obj: t.Any, *, symbol: str = "attr"
201
+ ) -> Docstring:
202
+ ds = parse(obj.__doc__ or "")
203
+ description = (ds.description or "").strip()
204
+ short_description, long_description = self.split_description(description)
205
+
206
+ return Docstring(
207
+ name=name,
208
+ symbol=symbol,
209
+ label="property",
210
+ short_description=short_description,
211
+ long_description=long_description,
212
+ description=description,
213
+ deprecation=ds.deprecation,
214
+ returns=ds.returns,
215
+ raises=ds.raises,
216
+ examples=ds.examples,
217
+ many_returns=ds.many_returns,
218
+ )
219
+
220
+ def autodoc_attr(
221
+ self, attr: DocstringParam, *, symbol: str = "attr"
222
+ ) -> AttrDocstring:
223
+ if attr.type_name:
224
+ name = f"{attr.arg_name}: {attr.type_name}"
225
+ else:
226
+ name = attr.arg_name
227
+
228
+ description = (attr.description or "").strip()
229
+ short_description, long_description = self.split_description(description)
230
+
231
+ return AttrDocstring(
232
+ symbol=symbol,
233
+ name=name,
234
+ label="attribute",
235
+ short_description=short_description,
236
+ long_description=long_description,
237
+ description=description,
238
+ )
239
+
240
+ def get_signature(self, obj_name: str, obj: t.Any) -> str:
241
+ sig = inspect.signature(obj)
242
+ str_sig = (
243
+ format_signature(sig, max_width=5).replace(" self,\n", "").replace("(self)", "()")
244
+ )
245
+ return f"{obj_name}{str_sig}"
246
+
247
+ def split_description(self, description: str) -> tuple[str, str]:
248
+ if "\n\n" not in description:
249
+ return description, ""
250
+ head, rest = description.split("\n\n", 1)
251
+ return head, rest
252
+
253
+
254
+ def format_signature(sig, *, max_width=None):
255
+ """Create a string representation of the Signature object.
256
+
257
+ If *max_width* integer is passed, signature will try to fit into the *max_width*.
258
+ If signature is longer than *max_width*, all parameters will be on separate lines.
259
+ """
260
+ result = []
261
+ render_pos_only_separator = False
262
+ render_kw_only_separator = True
263
+ for param in sig.parameters.values():
264
+ formatted = str(param)
265
+
266
+ kind = str(param.kind).lower().replace("_", "-")
267
+ if kind == "positional-only":
268
+ render_pos_only_separator = True
269
+ elif render_pos_only_separator:
270
+ # It's not a positional-only parameter, and the flag
271
+ # is set to 'True' (there were pos-only params before.)
272
+ result.append("/")
273
+ render_pos_only_separator = False
274
+
275
+ if kind == "variadic positional":
276
+ # OK, we have an '*args'-like parameter, so we won't need
277
+ # a '*' to separate keyword-only arguments
278
+ render_kw_only_separator = False
279
+ elif kind == "keyword-only" and render_kw_only_separator:
280
+ # We have a keyword-only parameter to render and we haven't
281
+ # rendered an '*args'-like parameter before, so add a '*'
282
+ # separator to the parameters list ("foo(arg1, *, arg2)" case)
283
+ result.append("*")
284
+ # This condition should be only triggered once, so
285
+ # reset the flag
286
+ render_kw_only_separator = False
287
+
288
+ result.append(formatted)
289
+
290
+ if render_pos_only_separator:
291
+ # There were only positional-only parameters, hence the
292
+ # flag was not reset to 'False'
293
+ result.append("/")
294
+
295
+ rendered = "({})".format(", ".join(result))
296
+ if max_width is not None and len(rendered) > max_width:
297
+ rendered = "(\n {}\n)".format(",\n ".join(result))
298
+
299
+ if sig.return_annotation is not inspect._empty:
300
+ anno = inspect.formatannotation(sig.return_annotation)
301
+ rendered += " -> {}".format(anno)
302
+
303
+ return rendered
@@ -0,0 +1,41 @@
1
+ .page-index .hero {
2
+ background: rgba(var(--rgb-base), 0.4);
3
+ }
4
+
5
+
6
+ .headline {
7
+ padding: var(--space-medium);
8
+ padding-bottom: var(--space-large);
9
+ }
10
+ .headline header {
11
+ display: flex;
12
+ flex-direction: column;
13
+ gap: var(--space-medium);
14
+ align-items: center;
15
+ justify-content: center;
16
+ text-align: center;
17
+ max-width: 60rem;
18
+ margin: 0 auto;
19
+ font-weight: 500;
20
+ }
21
+ .headline header h1 {
22
+ font-size: var(--font-size-xx-large);
23
+ font-weight: 900;
24
+ text-align: center;
25
+ }
26
+ .headline header p {
27
+ transform: skew(-4deg);
28
+ }
29
+ .headline header p span {
30
+ background-color: var(--color-base-darker);
31
+ padding: 0.1em;
32
+ }
33
+
34
+ @media (min-width: 64em) {
35
+ .headline {
36
+ padding: var(--space-x-large) var(--space-large);
37
+ }
38
+ .headline header h1 {
39
+ font-size: var(--font-size-xxx-large);
40
+ }
41
+ }