Skip to content

Commit d998394

Browse files
authored
Merge pull request #393 from machow/refactor-griffe-compat
refactor: make _griffe_compat a submodule that generates import stubs
2 parents a003f3d + 1d5077e commit d998394

File tree

6 files changed

+185
-4
lines changed

6 files changed

+185
-4
lines changed

quartodoc/_griffe_compat.py renamed to quartodoc/_griffe_compat/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
from griffe import GriffeLoader
55
from griffe import ModulesCollection, LinesCollection
66

7-
import _griffe.models as dataclasses
8-
import _griffe.docstrings.models as docstrings
9-
import _griffe.expressions as expressions
7+
from . import dataclasses
8+
from . import docstrings
9+
from . import expressions
1010

1111
from griffe import Parser, parse, parse_numpy
1212
from griffe import AliasResolutionError
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""Generate the submodules which import parts of griffe (e.g. dataclasses.py)
2+
3+
This process balances having to import specific objects from griffe, against
4+
importing everything via the top-level griffe module. It does this by generating
5+
modules for objects commonly used together in quartodoc.
6+
7+
* dataclasses: represent python objects
8+
* docstrings: represent python docstrings
9+
* expressions: represent annotation expressions
10+
11+
Run using: python -m quartodoc._griffe_compat._generate_stubs
12+
"""
13+
14+
import ast
15+
import black
16+
import copy
17+
import griffe
18+
import inspect
19+
from pathlib import Path
20+
21+
22+
def fetch_submodule(ast_body, submodule: str):
23+
ast_imports = [
24+
obj
25+
for obj in ast_body
26+
if isinstance(obj, ast.ImportFrom) and obj.module == submodule
27+
]
28+
29+
if len(ast_imports) > 1:
30+
raise Exception(f"Found {len(ast_imports)} imports for {submodule}")
31+
elif not ast_imports:
32+
raise Exception(f"Could not find import for {submodule}")
33+
34+
return ast_imports[0]
35+
36+
37+
def code_for_imports(mod_code: str, submodules: list[str]) -> str:
38+
res = []
39+
mod = ast.parse(mod_code)
40+
for submod in submodules:
41+
expr = fetch_submodule(mod.body, submod)
42+
expr.module = "griffe"
43+
new_expr = copy.copy(expr)
44+
new_expr.module = "griffe"
45+
res.append(ast.unparse(new_expr))
46+
47+
return black.format_str(
48+
"# flake8: noqa\n\n" + "\n".join(res), mode=black.FileMode()
49+
)
50+
51+
52+
def generate_griffe_stub(out_path: Path, mod, submodules: list[str]):
53+
res = code_for_imports(inspect.getsource(mod), submodules)
54+
out_path.write_text(res)
55+
56+
57+
MAPPINGS = {
58+
"dataclasses": [
59+
"_griffe.models",
60+
"_griffe.mixins",
61+
"_griffe.enumerations",
62+
],
63+
"docstrings": ["_griffe.docstrings.models"],
64+
"expressions": ["_griffe.expressions"],
65+
}
66+
67+
if __name__ == "__main__":
68+
for out_name, submodules in MAPPINGS.items():
69+
generate_griffe_stub(
70+
Path(__file__).parent / f"{out_name}.py", griffe, submodules
71+
)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# flake8: noqa
2+
3+
from griffe import (
4+
Alias,
5+
Attribute,
6+
Class,
7+
Decorator,
8+
Docstring,
9+
Function,
10+
Module,
11+
Object,
12+
Parameter,
13+
Parameters,
14+
)
15+
from griffe import (
16+
DelMembersMixin,
17+
GetMembersMixin,
18+
ObjectAliasMixin,
19+
SerializationMixin,
20+
SetMembersMixin,
21+
)
22+
from griffe import (
23+
BreakageKind,
24+
DocstringSectionKind,
25+
ExplanationStyle,
26+
Kind,
27+
LogLevel,
28+
ObjectKind,
29+
ParameterKind,
30+
Parser,
31+
)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# flake8: noqa
2+
3+
from griffe import (
4+
DocstringAdmonition,
5+
DocstringAttribute,
6+
DocstringClass,
7+
DocstringDeprecated,
8+
DocstringElement,
9+
DocstringFunction,
10+
DocstringModule,
11+
DocstringNamedElement,
12+
DocstringParameter,
13+
DocstringRaise,
14+
DocstringReceive,
15+
DocstringReturn,
16+
DocstringSection,
17+
DocstringSectionAdmonition,
18+
DocstringSectionAttributes,
19+
DocstringSectionClasses,
20+
DocstringSectionDeprecated,
21+
DocstringSectionExamples,
22+
DocstringSectionFunctions,
23+
DocstringSectionModules,
24+
DocstringSectionOtherParameters,
25+
DocstringSectionParameters,
26+
DocstringSectionRaises,
27+
DocstringSectionReceives,
28+
DocstringSectionReturns,
29+
DocstringSectionText,
30+
DocstringSectionWarns,
31+
DocstringSectionYields,
32+
DocstringWarn,
33+
DocstringYield,
34+
)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# flake8: noqa
2+
3+
from griffe import (
4+
Expr,
5+
ExprAttribute,
6+
ExprBinOp,
7+
ExprBoolOp,
8+
ExprCall,
9+
ExprCompare,
10+
ExprComprehension,
11+
ExprConstant,
12+
ExprDict,
13+
ExprDictComp,
14+
ExprExtSlice,
15+
ExprFormatted,
16+
ExprGeneratorExp,
17+
ExprIfExp,
18+
ExprJoinedStr,
19+
ExprKeyword,
20+
ExprLambda,
21+
ExprList,
22+
ExprListComp,
23+
ExprName,
24+
ExprNamedExpr,
25+
ExprParameter,
26+
ExprSet,
27+
ExprSetComp,
28+
ExprSlice,
29+
ExprSubscript,
30+
ExprTuple,
31+
ExprUnaryOp,
32+
ExprVarKeyword,
33+
ExprVarPositional,
34+
ExprYield,
35+
ExprYieldFrom,
36+
get_annotation,
37+
get_base_class,
38+
get_condition,
39+
get_expression,
40+
safe_get_annotation,
41+
safe_get_base_class,
42+
safe_get_condition,
43+
safe_get_expression,
44+
)

quartodoc/ast.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from ._griffe_compat import docstrings as ds
66
from ._griffe_compat import dataclasses as dc
7+
from ._griffe_compat import AliasResolutionError
78

89
from enum import Enum
910
from dataclasses import dataclass
@@ -210,7 +211,7 @@ def fields(el: dc.Object):
210211
def fields(el: dc.ObjectAliasMixin):
211212
try:
212213
return fields(el.target)
213-
except dc.AliasResolutionError:
214+
except AliasResolutionError:
214215
warnings.warn(
215216
f"Could not resolve Alias target `{el.target_path}`."
216217
" This often occurs because the module was not loaded (e.g. it is a"

0 commit comments

Comments
 (0)