mkdocstrings-python-xref 1.16.1__tar.gz → 1.16.3__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.
- {mkdocstrings_python_xref-1.16.1 → mkdocstrings_python_xref-1.16.3}/.gitignore +4 -0
- {mkdocstrings_python_xref-1.16.1 → mkdocstrings_python_xref-1.16.3}/LICENSE.md +1 -1
- {mkdocstrings_python_xref-1.16.1 → mkdocstrings_python_xref-1.16.3}/PKG-INFO +16 -2
- {mkdocstrings_python_xref-1.16.1 → mkdocstrings_python_xref-1.16.3}/pyproject.toml +96 -1
- mkdocstrings_python_xref-1.16.3/src/mkdocstrings_handlers/python_xref/VERSION +1 -0
- {mkdocstrings_python_xref-1.16.1 → mkdocstrings_python_xref-1.16.3}/src/mkdocstrings_handlers/python_xref/crossref.py +73 -8
- {mkdocstrings_python_xref-1.16.1 → mkdocstrings_python_xref-1.16.3}/src/mkdocstrings_handlers/python_xref/handler.py +20 -10
- mkdocstrings_python_xref-1.16.1/src/mkdocstrings_handlers/python_xref/VERSION +0 -1
- {mkdocstrings_python_xref-1.16.1 → mkdocstrings_python_xref-1.16.3}/README.md +0 -0
- {mkdocstrings_python_xref-1.16.1 → mkdocstrings_python_xref-1.16.3}/src/mkdocstrings_handlers/python_xref/__init__.py +0 -0
- {mkdocstrings_python_xref-1.16.1 → mkdocstrings_python_xref-1.16.3}/src/mkdocstrings_handlers/python_xref/py.typed +0 -0
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright 2022-
|
|
189
|
+
Copyright 2022-2025 Analog Devices, Inc.
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mkdocstrings-python-xref
|
|
3
|
-
Version: 1.16.
|
|
3
|
+
Version: 1.16.3
|
|
4
4
|
Summary: Enhanced mkdocstrings python handler
|
|
5
5
|
Project-URL: Repository, https://github.com/analog-garage/mkdocstrings-python-xref
|
|
6
6
|
Project-URL: Documentation, https://analog-garage.github.io/mkdocstrings-python-xref/
|
|
7
7
|
Author-email: Christopher Barber <Christopher.Barber@analog.com>
|
|
8
8
|
License-File: LICENSE.md
|
|
9
9
|
Keywords: documentation-tool,mkdocstrings,mkdocstrings-handler,python
|
|
10
|
-
Classifier: Development Status ::
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.9
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -18,6 +18,20 @@ Classifier: Topic :: Software Development :: Documentation
|
|
|
18
18
|
Requires-Python: >=3.9
|
|
19
19
|
Requires-Dist: griffe>=1.0
|
|
20
20
|
Requires-Dist: mkdocstrings-python<2.0,>=1.16.6
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: beautifulsoup4>=4.12; extra == 'dev'
|
|
23
|
+
Requires-Dist: black>=23.12; extra == 'dev'
|
|
24
|
+
Requires-Dist: build>=1.0.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: coverage>=7.4.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: hatchling>=1.21; extra == 'dev'
|
|
27
|
+
Requires-Dist: linkchecker>=10.4; extra == 'dev'
|
|
28
|
+
Requires-Dist: mike>=1.1; extra == 'dev'
|
|
29
|
+
Requires-Dist: mkdocs-material>=9.5.4; extra == 'dev'
|
|
30
|
+
Requires-Dist: mkdocs<2.0,>=1.5.3; extra == 'dev'
|
|
31
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest>=8.2; extra == 'dev'
|
|
34
|
+
Requires-Dist: ruff>=0.4.10; extra == 'dev'
|
|
21
35
|
Description-Content-Type: text/markdown
|
|
22
36
|
|
|
23
37
|
# mkdocstrings-python-xref
|
|
@@ -10,7 +10,7 @@ authors = [
|
|
|
10
10
|
{name = "Christopher Barber", email="Christopher.Barber@analog.com" },
|
|
11
11
|
]
|
|
12
12
|
classifiers = [
|
|
13
|
-
"Development Status ::
|
|
13
|
+
"Development Status :: 5 - Production/Stable",
|
|
14
14
|
"Intended Audience :: Developers",
|
|
15
15
|
"Topic :: Software Development :: Documentation",
|
|
16
16
|
"Programming Language :: Python :: 3.9",
|
|
@@ -33,6 +33,51 @@ dependencies = [
|
|
|
33
33
|
Repository = "https://github.com/analog-garage/mkdocstrings-python-xref"
|
|
34
34
|
Documentation = "https://analog-garage.github.io/mkdocstrings-python-xref/"
|
|
35
35
|
|
|
36
|
+
[project.optional-dependencies]
|
|
37
|
+
dev = [
|
|
38
|
+
"build >=1.0.0", # python-build on conda
|
|
39
|
+
"hatchling >=1.21",
|
|
40
|
+
"coverage >=7.4.0",
|
|
41
|
+
"pytest >=8.2",
|
|
42
|
+
"pytest-cov >=5.0",
|
|
43
|
+
"mypy >=1.10",
|
|
44
|
+
"ruff >=0.4.10",
|
|
45
|
+
"beautifulsoup4 >=4.12",
|
|
46
|
+
"black >=23.12",
|
|
47
|
+
"mike >=1.1",
|
|
48
|
+
"mkdocs >=1.5.3,<2.0",
|
|
49
|
+
"mkdocs-material >=9.5.4",
|
|
50
|
+
"linkchecker >=10.4"
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[tool.pixi.workspace]
|
|
54
|
+
name = "mkxref-dev"
|
|
55
|
+
channels = ["conda-forge"]
|
|
56
|
+
platforms = ["osx-arm64", "linux-64", "win-64"]
|
|
57
|
+
|
|
58
|
+
[tool.pixi.dependencies]
|
|
59
|
+
# Use conda for these in pixi
|
|
60
|
+
mkdocstrings-python ="*"
|
|
61
|
+
griffe ="*"
|
|
62
|
+
hatchling = "*"
|
|
63
|
+
python-build = "*"
|
|
64
|
+
coverage ="*"
|
|
65
|
+
pytest ="*"
|
|
66
|
+
pytest-cov ="*"
|
|
67
|
+
mypy ="*"
|
|
68
|
+
ruff = "*"
|
|
69
|
+
black = "*"
|
|
70
|
+
mike = "*"
|
|
71
|
+
mkdocs = "*"
|
|
72
|
+
mkdocs-material = "*"
|
|
73
|
+
linkchecker = "*"
|
|
74
|
+
|
|
75
|
+
[tool.pixi.pypi-dependencies]
|
|
76
|
+
mkdocstrings-python-xref = { path = ".", editable = true }
|
|
77
|
+
|
|
78
|
+
[tool.pixi.environments]
|
|
79
|
+
default = {features = ["dev"]}
|
|
80
|
+
|
|
36
81
|
[tool.hatch.version]
|
|
37
82
|
path = "src/mkdocstrings_handlers/python_xref/VERSION"
|
|
38
83
|
pattern = "\\s*(?P<version>[\\w.]*)"
|
|
@@ -174,3 +219,53 @@ disable = [
|
|
|
174
219
|
"wrong-spelling-in-comment",
|
|
175
220
|
"wrong-spelling-in-docstring",
|
|
176
221
|
]
|
|
222
|
+
|
|
223
|
+
[tool.pixi.tasks]
|
|
224
|
+
# linting tasks
|
|
225
|
+
mypy = "mypy"
|
|
226
|
+
ruff = "ruff check src/mkdocstrings_handlers tests"
|
|
227
|
+
lint = {depends-on = ["ruff", "mypy"]}
|
|
228
|
+
|
|
229
|
+
# testing tasks
|
|
230
|
+
pytest = "pytest -sv -ra tests"
|
|
231
|
+
test = {depends-on = ["pytest", "lint"]}
|
|
232
|
+
coverage = "pytest -ra --cov --cov-report=html --cov-report=term -- tests"
|
|
233
|
+
coverage-show = "python -m webbrowser file://$PIXI_PROJECT_ROOT/htmlcov/index.html"
|
|
234
|
+
|
|
235
|
+
# doc tasks
|
|
236
|
+
docs = {depends-on = ["doc"]}
|
|
237
|
+
show-doc = "mkdocs serve -f mkdocs.yml"
|
|
238
|
+
show-docs = {depends-on = ["show-doc"]}
|
|
239
|
+
|
|
240
|
+
# cleanup tasks
|
|
241
|
+
clean-build = "rm -rf build dist"
|
|
242
|
+
clean-coverage = "rm -rf .coverage .coverage.* htmlcov"
|
|
243
|
+
clean-docs = "rm -rf site"
|
|
244
|
+
clean-test = "rm -rf .pytest_cache .mypy_cache .ruff_cache"
|
|
245
|
+
clean = {depends-on = ["clean-build", "clean-coverage", "clean-test"]}
|
|
246
|
+
|
|
247
|
+
# build tasks
|
|
248
|
+
build = {depends-on = ["build-wheel", "build-sdist", "build-conda"]}
|
|
249
|
+
|
|
250
|
+
[tool.pixi.tasks.build-wheel]
|
|
251
|
+
env = {VERSION = "$(cat src/mkdocstrings_handlers/python_xref/VERSION)"}
|
|
252
|
+
cmd = "pip wheel . --no-deps --no-build-isolation -w dist"
|
|
253
|
+
inputs = ["pyproject.toml", "LICENSE.md", "src/**/*"]
|
|
254
|
+
outputs = ["dist/mkdocstrings_python_xref-$VERSION-py3-none-any.whl"]
|
|
255
|
+
|
|
256
|
+
[tool.pixi.tasks.build-sdist]
|
|
257
|
+
env = {VERSION = "$(cat src/mkdocstrings_handlers/python_xref/VERSION)"}
|
|
258
|
+
cmd = "python -m build --sdist --no-isolation --outdir dist"
|
|
259
|
+
inputs = ["pyproject.toml", "LICENSE.md", "src/**/*"]
|
|
260
|
+
outputs = ["dist/mkdocstrings_pixipython_xref-$VERSION.tar.gz"]
|
|
261
|
+
|
|
262
|
+
[tool.pixi.tasks.build-conda]
|
|
263
|
+
#env = {VERSION = "$(cat src/mkdocstrings_handlers/python_xref/VERSION)"}
|
|
264
|
+
cmd = "whl2conda convert dist/*.whl -w dist --overwrite"
|
|
265
|
+
depends-on = ["build-wheel"]
|
|
266
|
+
inputs = ["dist/mkdocstrings_python_xref-$VERSION-py3-none-any.whl"]
|
|
267
|
+
|
|
268
|
+
[tool.pixi.tasks.doc]
|
|
269
|
+
cmd = "mkdocs build -f mkdocs.yml"
|
|
270
|
+
inputs = ["docs/*.md", "docs/*.svg", "mkdocs.yml"]
|
|
271
|
+
outputs = ["site/*.html"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.16.3
|
|
@@ -15,8 +15,10 @@
|
|
|
15
15
|
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
|
+
import ast
|
|
18
19
|
import re
|
|
19
|
-
|
|
20
|
+
import sys
|
|
21
|
+
from typing import Any, Callable, List, Optional, cast
|
|
20
22
|
|
|
21
23
|
from griffe import Docstring, Object
|
|
22
24
|
from mkdocstrings import get_logger
|
|
@@ -303,14 +305,12 @@ class _RelativeCrossrefProcessor:
|
|
|
303
305
|
# We include the file:// prefix because it helps IDEs such as PyCharm
|
|
304
306
|
# recognize that this is a navigable location it can highlight.
|
|
305
307
|
prefix = f"file://{parent.filepath}:"
|
|
306
|
-
line = doc.
|
|
307
|
-
if line
|
|
308
|
-
# Add line offset to match in docstring. This can still be
|
|
309
|
-
# short if the doc string has leading newlines.
|
|
310
|
-
line += doc.value.count("\n", 0, self._cur_offset)
|
|
308
|
+
line, col = doc_value_offset_to_location(doc, self._cur_offset)
|
|
309
|
+
if line >= 0:
|
|
311
310
|
prefix += f"{line}:"
|
|
312
|
-
|
|
313
|
-
|
|
311
|
+
if col >= 0:
|
|
312
|
+
prefix += f"{col}:"
|
|
313
|
+
|
|
314
314
|
prefix += " \n"
|
|
315
315
|
|
|
316
316
|
logger.warning(prefix + msg)
|
|
@@ -334,3 +334,68 @@ def substitute_relative_crossrefs(obj: Object, checkref: Optional[Callable[[str]
|
|
|
334
334
|
for member in obj.members.values():
|
|
335
335
|
if isinstance(member, Object): # pragma: no branch
|
|
336
336
|
substitute_relative_crossrefs(member, checkref=checkref)
|
|
337
|
+
|
|
338
|
+
def doc_value_offset_to_location(doc: Docstring, offset: int) -> tuple[int,int]:
|
|
339
|
+
"""
|
|
340
|
+
Converts offset into doc.value to line and column in source file.
|
|
341
|
+
|
|
342
|
+
Returns:
|
|
343
|
+
line and column or else (-1,-1) if it cannot be computed
|
|
344
|
+
"""
|
|
345
|
+
linenum = -1
|
|
346
|
+
colnum = -2
|
|
347
|
+
|
|
348
|
+
if doc.lineno is not None:
|
|
349
|
+
linenum = doc.lineno # start of the docstring source
|
|
350
|
+
# line offset with respect to start of cleaned up docstring
|
|
351
|
+
lineoffset = clean_lineoffset = doc.value.count("\n", 0, offset)
|
|
352
|
+
|
|
353
|
+
# look at original doc source, if available
|
|
354
|
+
try:
|
|
355
|
+
source = doc.source
|
|
356
|
+
# compute docstring without cleaning up spaces and indentation
|
|
357
|
+
rawvalue = str(safe_eval(source))
|
|
358
|
+
|
|
359
|
+
# adjust line offset by number of lines removed from front of docstring
|
|
360
|
+
lineoffset += leading_space(rawvalue).count("\n")
|
|
361
|
+
|
|
362
|
+
if lineoffset == 0 and (m := re.match(r"(\s*['\"]{1,3}\s*)\S", source)):
|
|
363
|
+
# is on the same line as opening quote
|
|
364
|
+
colnum = offset + len(m.group(1))
|
|
365
|
+
else:
|
|
366
|
+
# indentation of first non-empty line in raw and cleaned up strings
|
|
367
|
+
raw_line = rawvalue.splitlines()[lineoffset]
|
|
368
|
+
clean_line = doc.value.splitlines()[clean_lineoffset]
|
|
369
|
+
raw_indent = len(leading_space(raw_line))
|
|
370
|
+
clean_indent = len(leading_space(clean_line))
|
|
371
|
+
try:
|
|
372
|
+
linestart = doc.value.rindex("\n", 0, offset) + 1
|
|
373
|
+
except ValueError: # pragma: no cover
|
|
374
|
+
linestart = 0 # paranoid check, should not really happen
|
|
375
|
+
colnum = offset - linestart + raw_indent - clean_indent
|
|
376
|
+
|
|
377
|
+
except Exception:
|
|
378
|
+
# Don't expect to get here, but just in case, it is better to
|
|
379
|
+
# not fix up the line/column than to die.
|
|
380
|
+
pass
|
|
381
|
+
|
|
382
|
+
linenum += lineoffset
|
|
383
|
+
|
|
384
|
+
return linenum, colnum + 1
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def leading_space(s: str) -> str:
|
|
388
|
+
"""Returns whitespace at the front of string."""
|
|
389
|
+
if m := re.match(r"\s*", s):
|
|
390
|
+
return m[0]
|
|
391
|
+
return "" # pragma: no cover
|
|
392
|
+
|
|
393
|
+
if sys.version_info < (3, 10) or True:
|
|
394
|
+
# TODO: remove when 3.9 support is dropped
|
|
395
|
+
# In 3.9, literal_eval cannot handle comments in input
|
|
396
|
+
def safe_eval(s: str) -> Any:
|
|
397
|
+
"""Safely evaluate a string expression."""
|
|
398
|
+
return eval(s) #eval(s, dict(__builtins__={}), {})
|
|
399
|
+
else:
|
|
400
|
+
save_eval = ast.literal_eval
|
|
401
|
+
|
|
@@ -17,8 +17,10 @@ Implementation of python_xref handler
|
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
+
import re
|
|
20
21
|
import sys
|
|
21
|
-
from dataclasses import dataclass, fields
|
|
22
|
+
from dataclasses import dataclass, field, fields
|
|
23
|
+
from functools import partial
|
|
22
24
|
from pathlib import Path
|
|
23
25
|
from typing import Any, ClassVar, Mapping, MutableMapping, Optional
|
|
24
26
|
from warnings import warn
|
|
@@ -43,6 +45,7 @@ if sys.version_info >= (3, 10):
|
|
|
43
45
|
@dataclass(**_dataclass_options)
|
|
44
46
|
class PythonRelXRefOptions(PythonOptions):
|
|
45
47
|
check_crossrefs: bool = True
|
|
48
|
+
check_crossrefs_exclude: list[str | re.Pattern] = field(default_factory=list)
|
|
46
49
|
|
|
47
50
|
class PythonRelXRefHandler(PythonHandler):
|
|
48
51
|
"""Extended version of mkdocstrings Python handler
|
|
@@ -62,26 +65,30 @@ class PythonRelXRefHandler(PythonHandler):
|
|
|
62
65
|
base_dir: The base directory of the project.
|
|
63
66
|
**kwargs: Arguments passed to the parent constructor.
|
|
64
67
|
"""
|
|
65
|
-
check_crossrefs = config.options.pop('check_crossrefs',
|
|
68
|
+
self.check_crossrefs = config.options.pop('check_crossrefs', True)
|
|
69
|
+
exclude = config.options.pop('check_crossrefs_exclude', [])
|
|
70
|
+
self.check_crossrefs_exclude = [re.compile(p) for p in exclude]
|
|
66
71
|
super().__init__(config, base_dir, **kwargs)
|
|
67
|
-
if check_crossrefs is not None:
|
|
68
|
-
self.global_options["check_crossrefs"] = check_crossrefs
|
|
69
72
|
|
|
70
73
|
def get_options(self, local_options: Mapping[str, Any]) -> PythonRelXRefOptions:
|
|
71
74
|
local_options = dict(local_options)
|
|
72
|
-
check_crossrefs = local_options.pop(
|
|
75
|
+
check_crossrefs = local_options.pop(
|
|
76
|
+
'check_crossrefs', self.check_crossrefs)
|
|
77
|
+
check_crossrefs_exclude = local_options.pop(
|
|
78
|
+
'check_crossrefs_exclude', self.check_crossrefs_exclude)
|
|
73
79
|
_opts = super().get_options(local_options)
|
|
74
80
|
opts = PythonRelXRefOptions(
|
|
81
|
+
check_crossrefs=check_crossrefs,
|
|
82
|
+
check_crossrefs_exclude=check_crossrefs_exclude,
|
|
75
83
|
**{field.name: getattr(_opts, field.name) for field in fields(_opts)}
|
|
76
84
|
)
|
|
77
|
-
if check_crossrefs is not None:
|
|
78
|
-
opts.check_crossrefs = bool(check_crossrefs)
|
|
79
85
|
return opts
|
|
80
86
|
|
|
81
87
|
def render(self, data: CollectorItem, options: PythonOptions) -> str:
|
|
82
88
|
if options.relative_crossrefs:
|
|
83
|
-
if isinstance(options, PythonRelXRefOptions):
|
|
84
|
-
checkref =
|
|
89
|
+
if isinstance(options, PythonRelXRefOptions) and options.check_crossrefs:
|
|
90
|
+
checkref = partial(
|
|
91
|
+
self._check_ref, exclude=options.check_crossrefs_exclude)
|
|
85
92
|
else:
|
|
86
93
|
checkref = None
|
|
87
94
|
substitute_relative_crossrefs(data, checkref=checkref)
|
|
@@ -98,8 +105,11 @@ class PythonRelXRefHandler(PythonHandler):
|
|
|
98
105
|
handler = 'python'
|
|
99
106
|
return super().get_templates_dir(handler)
|
|
100
107
|
|
|
101
|
-
def _check_ref(self, ref:str) -> bool:
|
|
108
|
+
def _check_ref(self, ref : str, exclude: list[str | re.Pattern] = []) -> bool:
|
|
102
109
|
"""Check for existence of reference"""
|
|
110
|
+
for ex in exclude:
|
|
111
|
+
if re.match(ex, ref):
|
|
112
|
+
return True
|
|
103
113
|
try:
|
|
104
114
|
self.collect(ref, PythonOptions())
|
|
105
115
|
return True
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.16.1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|