Skip to content

Commit d89e86c

Browse files
Merge pull request #44 from thetianshuhuang/main
Fine-grained Configuration of `check_crossrefs`
2 parents 1bf9d1d + c053860 commit d89e86c

File tree

4 files changed

+86
-39
lines changed

4 files changed

+86
-39
lines changed

docs/config.md

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,77 @@ that the handler name should be `python_xref` instead of `python`. Because
33
this handler extends the standard [mkdocstrings-python][] handler, the same options are
44
available.
55

6-
Additional options are added by this extension. Currently, there are two:
6+
Additional options are added by this extension. Currently, there are three:
77

8-
* **relative_crossrefs** - if set to true enables use of relative path syntax in
8+
* **relative_crossrefs**: `bool` - if set to true enables use of relative path syntax in
99
cross-references.
1010

11-
* **check_crossrefs** - enables early checking of all cross-references. Note that
11+
* **check_crossrefs**: `bool` - enables early checking of all cross-references. Note that
1212
this option only takes affect if **relative_crossrefs** is also true. This option is
1313
true by default, so this option is used to disable checking. Checking can
1414
also be disabled on a per-case basis by prefixing the reference with '?', e.g.
1515
`[something][?dontcheckme]`.
1616

17-
!!! Example "mkdocs.yml plugins specification using this handler"
18-
19-
```yaml
20-
plugins:
21-
- search
22-
- mkdocstrings:
23-
default_handler: python_xref
24-
handlers:
25-
python_xref:
26-
import:
27-
- https://docs.python.org/3/objects.inv
28-
options:
29-
docstring_style: google
30-
docstring_options:
31-
ignore_init_summary: yes
32-
merge_init_into_class: yes
33-
relative_crossrefs: yes
34-
check_crossrefs: no
35-
separate_signature: yes
36-
show_source: no
37-
show_root_full_path: no
38-
```
17+
* **check_crossrefs_exclude**: `list[str]` - exclude cross-references matching any of these
18+
regex patterns from crossref checking. This option can be used disabling checking on
19+
libraries which are very expensive to import without having to disable checking for all
20+
cross-references.
21+
22+
!!! Example "mkdocs.yml plugins specifications using this handler"
23+
24+
=== "Always check"
25+
26+
!!! warning
27+
28+
Crossrefs to libraries which are expensive to import (e.g., machine learning
29+
frameworks) can cause very slow build times when checked!
30+
31+
```yaml
32+
plugins:
33+
- mkdocstrings:
34+
default_handler: python_xref
35+
handlers:
36+
python_xref:
37+
import:
38+
- https://docs.python.org/3/objects.inv
39+
- https://pytorch.org/docs/stable/objects.inv
40+
options:
41+
relative_crossrefs: yes
42+
```
43+
44+
=== "Check all but listed exclusions"
45+
46+
```yaml
47+
plugins:
48+
- mkdocstrings:
49+
default_handler: python_xref
50+
handlers:
51+
python_xref:
52+
import:
53+
- https://docs.python.org/3/objects.inv
54+
- https://pytorch.org/docs/stable/objects.inv
55+
options:
56+
relative_crossrefs: yes
57+
check_crossrefs_exclude:
58+
- "^torch\\.(.*)"
59+
```
60+
61+
=== "Never check"
62+
63+
```yaml
64+
plugins:
65+
- mkdocstrings:
66+
default_handler: python_xref
67+
handlers:
68+
python_xref:
69+
import:
70+
- https://docs.python.org/3/objects.inv
71+
- https://pytorch.org/docs/stable/objects.inv
72+
options:
73+
relative_crossrefs: yes
74+
check_crossrefs: no
75+
```
76+
77+
3978

4079
[mkdocstrings-python]: https://mkdocstrings.github.io/python/

docs/index.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ but has not yet been accepted.
105105

106106
If `relative_crossrefs` and `check_crossrefs` are both enabled (the latter is true by default),
107107
then all cross-reference expressions will be checked to ensure that they exist and failures
108-
will be reported with the source location. Otherwise, missing cross-references will be reported
108+
will be reported with the source location (with the exception of any crossrefs which match a pattern in `check_crossrefs_exclude`). Otherwise, missing cross-references will be reported
109109
by mkdocstrings without the source location, in which case it is often difficult to locate the source
110110
of the error. Note that the errors generated by this feature are in addition to the errors
111111
from mkdocstrings.
@@ -121,5 +121,3 @@ This function returns a [Path][?pathlib.] instance.
121121
[mkdocstrings]: https://mkdocstrings.github.io/
122122
[mkdocstrings_python]: https://mkdocstrings.github.io/python/
123123
[relative-crossref-issue]: https://github.com/mkdocstrings/python/issues/27
124-
125-
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.16.2
1+
1.16.3

src/mkdocstrings_handlers/python_xref/handler.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717

1818
from __future__ import annotations
1919

20+
import re
2021
import sys
21-
from dataclasses import dataclass, fields
22+
from dataclasses import dataclass, field, fields
23+
from functools import partial
2224
from pathlib import Path
2325
from typing import Any, ClassVar, Mapping, MutableMapping, Optional
2426
from warnings import warn
@@ -43,6 +45,7 @@
4345
@dataclass(**_dataclass_options)
4446
class PythonRelXRefOptions(PythonOptions):
4547
check_crossrefs: bool = True
48+
check_crossrefs_exclude: list[str | re.Pattern] = field(default_factory=list)
4649

4750
class PythonRelXRefHandler(PythonHandler):
4851
"""Extended version of mkdocstrings Python handler
@@ -62,26 +65,30 @@ def __init__(self, config: PythonConfig, base_dir: Path, **kwargs: Any) -> None:
6265
base_dir: The base directory of the project.
6366
**kwargs: Arguments passed to the parent constructor.
6467
"""
65-
check_crossrefs = config.options.pop('check_crossrefs', None) # Remove
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]
6671
super().__init__(config, base_dir, **kwargs)
67-
if check_crossrefs is not None:
68-
self.global_options["check_crossrefs"] = check_crossrefs
6972

7073
def get_options(self, local_options: Mapping[str, Any]) -> PythonRelXRefOptions:
7174
local_options = dict(local_options)
72-
check_crossrefs = local_options.pop('check_crossrefs', None)
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)
7379
_opts = super().get_options(local_options)
7480
opts = PythonRelXRefOptions(
81+
check_crossrefs=check_crossrefs,
82+
check_crossrefs_exclude=check_crossrefs_exclude,
7583
**{field.name: getattr(_opts, field.name) for field in fields(_opts)}
7684
)
77-
if check_crossrefs is not None:
78-
opts.check_crossrefs = bool(check_crossrefs)
7985
return opts
8086

8187
def render(self, data: CollectorItem, options: PythonOptions) -> str:
8288
if options.relative_crossrefs:
83-
if isinstance(options, PythonRelXRefOptions):
84-
checkref = self._check_ref if options.check_crossrefs else None
89+
if isinstance(options, PythonRelXRefOptions) and options.check_crossrefs:
90+
checkref = partial(
91+
self._check_ref, exclude=options.check_crossrefs_exclude)
8592
else:
8693
checkref = None
8794
substitute_relative_crossrefs(data, checkref=checkref)
@@ -98,8 +105,11 @@ def get_templates_dir(self, handler: Optional[str] = None) -> Path:
98105
handler = 'python'
99106
return super().get_templates_dir(handler)
100107

101-
def _check_ref(self, ref:str) -> bool:
108+
def _check_ref(self, ref : str, exclude: list[str | re.Pattern] = []) -> bool:
102109
"""Check for existence of reference"""
110+
for ex in exclude:
111+
if re.match(ex, ref):
112+
return True
103113
try:
104114
self.collect(ref, PythonOptions())
105115
return True

0 commit comments

Comments
 (0)