0
# Utility Functions
1
2
Helper functions and classes for common operations including docspec manipulation, template processing, file watching, and page management.
3
4
## Capabilities
5
6
### Docspec Utilities
7
8
Functions for working with docspec objects and API analysis.
9
10
```python { .api }
11
def get_members_of_type(objs: Union[docspec.ApiObject, List[docspec.ApiObject]], type_: Type[T]) -> List[T]:
12
"""
13
Get all members of specified type from API objects.
14
15
Args:
16
objs: Single API object or list of API objects to search
17
type_: Type to filter for (e.g., docspec.Function, docspec.Class)
18
19
Returns:
20
List of objects matching the specified type
21
"""
22
23
def format_function_signature(func: docspec.Function, exclude_self: bool = False) -> str:
24
"""
25
Format function signature with arguments and return type.
26
27
Args:
28
func: Function object to format
29
exclude_self: Whether to exclude 'self' parameter from signature
30
31
Returns:
32
Formatted signature string like "(arg1, arg2) -> ReturnType"
33
"""
34
35
def is_function(obj: docspec.ApiObject) -> TypeGuard[docspec.Function]:
36
"""
37
Type guard to check if object is a function.
38
39
Args:
40
obj: API object to check
41
42
Returns:
43
True if object is a docspec.Function
44
"""
45
46
def is_method(obj: docspec.ApiObject) -> TypeGuard[docspec.Function]:
47
"""
48
Type guard to check if object is a method (function inside a class).
49
50
Args:
51
obj: API object to check
52
53
Returns:
54
True if object is a method
55
"""
56
57
def is_property(obj: docspec.ApiObject) -> TypeGuard[docspec.Function]:
58
"""
59
Type guard to check if object is a property (function with @property decorator).
60
61
Args:
62
obj: API object to check
63
64
Returns:
65
True if object is a property
66
"""
67
68
def is_attr(obj: docspec.ApiObject) -> TypeGuard[docspec.Variable]:
69
"""
70
Type guard to check if object is a class attribute.
71
72
Args:
73
obj: API object to check
74
75
Returns:
76
True if object is a class attribute
77
"""
78
79
def get_object_description(obj: docspec.ApiObject) -> str:
80
"""
81
Get descriptive text for an API object.
82
83
Args:
84
obj: API object to describe
85
86
Returns:
87
Description like "module", "class", "function", "method", etc.
88
"""
89
```
90
91
### ApiSuite Wrapper
92
93
Wrapper class for working with collections of API objects.
94
95
```python { .api }
96
class ApiSuite:
97
"""
98
Wrapper for API object collections with utility methods.
99
100
Provides convenient access to docspec objects with type filtering,
101
relationship analysis, and other collection operations.
102
"""
103
104
def get_members_of_type(self, type_: Type[T]) -> List[T]:
105
"""
106
Get all members of specified type from the suite.
107
108
Args:
109
type_: Type to filter for
110
111
Returns:
112
List of objects matching the specified type
113
"""
114
```
115
116
### Template Processing
117
118
YAML template loading with variable substitution.
119
120
```python { .api }
121
def load(filename: str, context: Dict[str, Any]) -> Any:
122
"""
123
Load YAML template file with variable substitution.
124
125
Args:
126
filename: Path to YAML template file
127
context: Dictionary of variables for substitution
128
129
Returns:
130
Parsed YAML data with variables substituted
131
"""
132
133
class Attributor:
134
"""
135
Attribute accessor for template variables.
136
137
Provides dot-notation access to dictionary data for use in templates.
138
"""
139
140
def __init__(self, data: Dict[str, Any]):
141
"""
142
Initialize with data dictionary.
143
144
Args:
145
data: Dictionary to provide attribute access for
146
"""
147
148
def __getattr__(self, name: str) -> Any:
149
"""
150
Get attribute value from underlying data.
151
152
Args:
153
name: Attribute name to access
154
155
Returns:
156
Value from data dictionary
157
158
Raises:
159
AttributeError: If attribute not found
160
"""
161
```
162
163
### File Watching
164
165
File system monitoring for development workflows.
166
167
```python { .api }
168
def watch_paths(paths: List[str]) -> Tuple[Observer, Event]:
169
"""
170
Set up file system watching for specified paths.
171
172
Args:
173
paths: List of file/directory paths to watch for changes
174
175
Returns:
176
Tuple of (Observer, Event) where Event is set when changes occur
177
"""
178
```
179
180
### Page Management
181
182
Utilities for managing documentation pages and collections.
183
184
```python { .api }
185
def collect_pages(directory: str, pattern: str = "*.md") -> List[str]:
186
"""
187
Collect documentation pages from directory.
188
189
Args:
190
directory: Directory to search for pages
191
pattern: File pattern to match (default: "*.md")
192
193
Returns:
194
List of page file paths
195
"""
196
```
197
198
### Markdown Utilities
199
200
Text processing utilities for Markdown generation.
201
202
```python { .api }
203
def escape_except_blockquotes(text: str) -> str:
204
"""
205
Escape Markdown special characters except in blockquotes.
206
207
Args:
208
text: Text to escape
209
210
Returns:
211
Text with Markdown characters escaped appropriately
212
"""
213
```
214
215
### Helper Functions
216
217
Additional utility functions for common operations.
218
219
```python { .api }
220
def dotted_name(obj: docspec.ApiObject) -> str:
221
"""
222
Get fully qualified dotted name for an API object.
223
224
Args:
225
obj: API object to get name for
226
227
Returns:
228
Dotted name like "module.Class.method"
229
"""
230
```
231
232
## Usage Examples
233
234
### Docspec Object Analysis
235
236
```python
237
from pydoc_markdown.util.docspec import get_members_of_type, is_method, format_function_signature
238
import docspec
239
240
# Get all functions from modules
241
modules = config.load_modules()
242
all_functions = get_members_of_type(modules, docspec.Function)
243
244
# Filter for methods only
245
methods = [f for f in all_functions if is_method(f)]
246
247
# Format signatures
248
for method in methods:
249
signature = format_function_signature(method, exclude_self=True)
250
print(f"{method.name}{signature}")
251
```
252
253
### API Object Type Checking
254
255
```python
256
from pydoc_markdown.util.docspec import is_function, is_method, is_property, is_attr
257
258
for obj in module.members:
259
if is_function(obj):
260
if is_method(obj):
261
print(f"Method: {obj.name}")
262
elif is_property(obj):
263
print(f"Property: {obj.name}")
264
else:
265
print(f"Function: {obj.name}")
266
elif is_attr(obj):
267
print(f"Attribute: {obj.name}")
268
```
269
270
### Template Processing
271
272
```python
273
from pydoc_markdown.util.ytemplate import load, Attributor
274
import os
275
276
# Load template with environment variables
277
context = {"env": Attributor(os.environ)}
278
config_data = load("pydoc-markdown.yml.template", context)
279
280
# Template file might contain:
281
# loaders:
282
# - type: python
283
# modules: ["{{ env.PACKAGE_NAME }}"]
284
```
285
286
### File Watching for Development
287
288
```python
289
from pydoc_markdown.util.watchdog import watch_paths
290
import time
291
292
# Watch source files for changes
293
source_files = ["src/mypackage/", "docs/"]
294
observer, event = watch_paths(source_files)
295
296
try:
297
while True:
298
if event.wait(timeout=1.0):
299
print("Files changed, regenerating docs...")
300
# Regenerate documentation
301
event.clear()
302
else:
303
time.sleep(0.1)
304
finally:
305
observer.stop()
306
```
307
308
### Page Collection
309
310
```python
311
from pydoc_markdown.util.pages import collect_pages
312
313
# Collect all markdown files in docs directory
314
doc_pages = collect_pages("docs/", "*.md")
315
316
# Collect specific patterns
317
api_pages = collect_pages("docs/api/", "*.md")
318
examples = collect_pages("examples/", "*.py")
319
```
320
321
### Markdown Text Processing
322
323
```python
324
from pydoc_markdown.util.misc import escape_except_blockquotes
325
326
# Safely escape markdown while preserving blockquotes
327
text = """
328
This text has *special* characters that need escaping.
329
330
> But this blockquote should remain unchanged
331
> with its *formatting* intact.
332
"""
333
334
escaped = escape_except_blockquotes(text)
335
```
336
337
### Object Path and Naming
338
339
```python
340
from pydoc_markdown.contrib.renderers.markdown import dotted_name
341
342
# Get full dotted names for API objects
343
for obj in module.members:
344
full_name = dotted_name(obj)
345
print(f"Full name: {full_name}")
346
# Output: "mypackage.MyClass.my_method"
347
```
348
349
## Integration Examples
350
351
### Custom Processor Using Utilities
352
353
```python
354
from pydoc_markdown.interfaces import Processor
355
from pydoc_markdown.util.docspec import get_members_of_type, is_method
356
import docspec
357
358
class MethodDocumentationProcessor(Processor):
359
def process(self, modules: List[docspec.Module], resolver: Optional[Resolver]) -> None:
360
# Get all methods across all modules
361
methods = get_members_of_type(modules, docspec.Function)
362
methods = [m for m in methods if is_method(m)]
363
364
# Add standard documentation for undocumented methods
365
for method in methods:
366
if not method.docstring:
367
signature = format_function_signature(method, exclude_self=True)
368
method.docstring = f"Method {method.name}{signature}"
369
```
370
371
### Custom Renderer Using Utilities
372
373
```python
374
from pydoc_markdown.interfaces import Renderer
375
from pydoc_markdown.util.docspec import get_object_description, dotted_name
376
from pydoc_markdown.util.misc import escape_except_blockquotes
377
378
class CustomTableRenderer(Renderer):
379
def render(self, modules: List[docspec.Module]) -> None:
380
with open("api-table.md", "w") as f:
381
f.write("# API Reference Table\n\n")
382
f.write("| Name | Type | Description |\n")
383
f.write("|------|------|-------------|\n")
384
385
for module in modules:
386
for obj in module.members:
387
name = dotted_name(obj)
388
obj_type = get_object_description(obj)
389
desc = obj.docstring or "No description"
390
desc = escape_except_blockquotes(desc.split('\n')[0]) # First line only
391
392
f.write(f"| {name} | {obj_type} | {desc} |\n")
393
```
394
395
### Development Workflow Integration
396
397
```python
398
from pydoc_markdown.util.watchdog import watch_paths
399
from pydoc_markdown.util.pages import collect_pages
400
from pydoc_markdown import PydocMarkdown
401
402
class DocumentationWatcher:
403
def __init__(self, config_file: str):
404
self.config_file = config_file
405
self.config = PydocMarkdown()
406
self.config.load_config(config_file)
407
408
def start_watching(self):
409
# Collect all relevant files to watch
410
source_files = []
411
412
# Add Python source files
413
for loader in self.config.loaders:
414
if hasattr(loader, 'search_path'):
415
source_files.extend(loader.search_path)
416
417
# Add documentation files
418
doc_files = collect_pages("docs/", "*.md")
419
source_files.extend(doc_files)
420
421
# Add config file
422
source_files.append(self.config_file)
423
424
# Start watching
425
observer, event = watch_paths(source_files)
426
427
try:
428
while True:
429
if event.wait(timeout=2.0):
430
print("Changes detected, regenerating documentation...")
431
self.regenerate_docs()
432
event.clear()
433
finally:
434
observer.stop()
435
436
def regenerate_docs(self):
437
modules = self.config.load_modules()
438
self.config.process(modules)
439
self.config.render(modules)
440
```