Nymbo commited on
Commit
858a56f
·
verified ·
1 Parent(s): a17bcac

Update Modules/_docstrings.py

Browse files
Files changed (1) hide show
  1. Modules/_docstrings.py +57 -2
Modules/_docstrings.py CHANGED
@@ -1,5 +1,6 @@
1
  from __future__ import annotations
2
 
 
3
  import inspect
4
  import sys
5
  import types
@@ -41,6 +42,43 @@ def _extract_base_and_meta(annotation: Any) -> tuple[Any, str | None]:
41
  return annotation, None
42
 
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  def autodoc(summary: str | None = None, returns: str | None = None, *, force: bool = False):
45
  """
46
  Decorator that auto-generates a concise Google-style docstring from a function's
@@ -73,7 +111,15 @@ def autodoc(summary: str | None = None, returns: str | None = None, *, force: bo
73
  for name, param in sig.parameters.items():
74
  if isinstance(param.annotation, str):
75
  try:
76
- val = eval(param.annotation, getattr(func, "__globals__", {}))
 
 
 
 
 
 
 
 
77
  hints[name] = val
78
  except Exception:
79
  pass
@@ -98,7 +144,16 @@ def autodoc(summary: str | None = None, returns: str | None = None, *, force: bo
98
  if name == "self":
99
  continue
100
  annot = hints.get(name, param.annotation)
 
101
  base, meta = _extract_base_and_meta(annot)
 
 
 
 
 
 
 
 
102
  tname = _typename(base) if base is not inspect._empty else None
103
  desc = meta or ""
104
  if tname and tname != str(inspect._empty):
@@ -127,4 +182,4 @@ def autodoc(summary: str | None = None, returns: str | None = None, *, force: bo
127
  return decorator
128
 
129
 
130
- __all__ = ["autodoc"]
 
1
  from __future__ import annotations
2
 
3
+ import ast
4
  import inspect
5
  import sys
6
  import types
 
42
  return annotation, None
43
 
44
 
45
+ def _parse_annotated_string(annot_str: str) -> tuple[str, str | None]:
46
+ """Fallback: parse 'Annotated[Type, "desc"]' string using AST."""
47
+ try:
48
+ expr = ast.parse(annot_str, mode='eval').body
49
+ if isinstance(expr, ast.Subscript):
50
+ val = expr.value
51
+ is_annotated = False
52
+ if isinstance(val, ast.Name) and val.id == 'Annotated':
53
+ is_annotated = True
54
+ elif isinstance(val, ast.Attribute) and val.attr == 'Annotated':
55
+ is_annotated = True
56
+
57
+ if is_annotated:
58
+ sl = expr.slice
59
+ # In 3.9+, slice is the node. In <3.9, it might be Index/ExtSlice.
60
+ if isinstance(sl, ast.Tuple):
61
+ elts = sl.elts
62
+ if len(elts) >= 2:
63
+ # elts[0] is type, elts[1] is metadata
64
+ meta_node = elts[1]
65
+ desc = None
66
+ if isinstance(meta_node, ast.Constant) and isinstance(meta_node.value, str):
67
+ desc = meta_node.value
68
+ elif isinstance(meta_node, ast.Str):
69
+ desc = meta_node.s
70
+
71
+ if desc:
72
+ if hasattr(ast, 'unparse'):
73
+ type_str = ast.unparse(elts[0])
74
+ else:
75
+ type_str = "Any"
76
+ return type_str, desc
77
+ except Exception:
78
+ pass
79
+ return annot_str, None
80
+
81
+
82
  def autodoc(summary: str | None = None, returns: str | None = None, *, force: bool = False):
83
  """
84
  Decorator that auto-generates a concise Google-style docstring from a function's
 
111
  for name, param in sig.parameters.items():
112
  if isinstance(param.annotation, str):
113
  try:
114
+ # Ensure typing is available in eval context
115
+ globs = getattr(func, "__globals__", {}).copy()
116
+ import typing
117
+ globs['typing'] = typing
118
+ for t in ['Annotated', 'Literal', 'Optional', 'Union', 'List', 'Dict', 'Any']:
119
+ if t not in globs:
120
+ globs[t] = getattr(typing, t)
121
+
122
+ val = eval(param.annotation, globs)
123
  hints[name] = val
124
  except Exception:
125
  pass
 
144
  if name == "self":
145
  continue
146
  annot = hints.get(name, param.annotation)
147
+
148
  base, meta = _extract_base_and_meta(annot)
149
+
150
+ # If meta is missing and annot is a string, try AST fallback
151
+ if meta is None and isinstance(annot, str):
152
+ base_str, meta_str = _parse_annotated_string(annot)
153
+ if meta_str:
154
+ base = base_str
155
+ meta = meta_str
156
+
157
  tname = _typename(base) if base is not inspect._empty else None
158
  desc = meta or ""
159
  if tname and tname != str(inspect._empty):
 
182
  return decorator
183
 
184
 
185
+ __all__ = ["autodoc"]