0
# Inventory System
1
2
Object inventory system for managing and cross-referencing documentation objects within and across projects. The inventory system enables linking between different documentation sets and provides compatibility with Sphinx inventories.
3
4
## Capabilities
5
6
### Inventory Container
7
8
Dictionary-based storage for collected documentation objects with Sphinx inventory compatibility.
9
10
```python { .api }
11
class Inventory(dict):
12
"""Dictionary-based inventory of collected objects."""
13
14
def __init__(
15
self,
16
items: list[InventoryItem] | None = None,
17
project: str = "project",
18
version: str = "0.0.0"
19
) -> None:
20
"""
21
Initialize inventory.
22
23
Args:
24
items: Initial list of inventory items
25
project: Project name
26
version: Project version
27
"""
28
29
def register(
30
self,
31
name: str,
32
domain: str,
33
role: str,
34
uri: str,
35
priority: int = 1,
36
dispname: str | None = None
37
) -> None:
38
"""
39
Register new inventory item.
40
41
Args:
42
name: Item name/identifier
43
domain: Item domain (e.g., "py", "js")
44
role: Item role (e.g., "function", "class")
45
uri: Item URI/link
46
priority: Item priority for sorting
47
dispname: Display name (defaults to name)
48
"""
49
50
def format_sphinx(self) -> bytes:
51
"""
52
Format inventory as Sphinx inventory file.
53
54
Returns:
55
Sphinx inventory file content as bytes
56
"""
57
58
@classmethod
59
def parse_sphinx(
60
cls,
61
in_file: BinaryIO,
62
*,
63
domain_filter: Collection[str] = ()
64
) -> Inventory:
65
"""
66
Parse Sphinx inventory file.
67
68
Args:
69
in_file: Binary file containing Sphinx inventory
70
domain_filter: Only include items from these domains
71
72
Returns:
73
Inventory instance with parsed items
74
"""
75
76
project: str
77
"""Project name."""
78
79
version: str
80
"""Project version."""
81
```
82
83
**Usage Examples:**
84
85
Creating and populating an inventory:
86
```python
87
from mkdocstrings import Inventory
88
89
# Create new inventory
90
inventory = Inventory(project="my-project", version="1.0.0")
91
92
# Register items
93
inventory.register(
94
name="MyClass",
95
domain="py",
96
role="class",
97
uri="#MyClass",
98
dispname="my_module.MyClass"
99
)
100
101
inventory.register(
102
name="my_function",
103
domain="py",
104
role="function",
105
uri="#my_function",
106
priority=2
107
)
108
109
# Save as Sphinx inventory
110
with open("objects.inv", "wb") as f:
111
f.write(inventory.format_sphinx())
112
```
113
114
Loading external inventory:
115
```python
116
# Load Sphinx inventory from file
117
with open("external_objects.inv", "rb") as f:
118
external_inventory = Inventory.parse_sphinx(f, domain_filter=["py"])
119
120
# Merge with local inventory
121
local_inventory.update(external_inventory)
122
```
123
124
### Inventory Item
125
126
Individual item within an inventory, representing a single documentation object.
127
128
```python { .api }
129
class InventoryItem:
130
"""Individual item within an inventory."""
131
132
def __init__(
133
self,
134
name: str,
135
domain: str,
136
role: str,
137
uri: str,
138
priority: int = 1,
139
dispname: str | None = None
140
) -> None:
141
"""
142
Initialize inventory item.
143
144
Args:
145
name: Item name/identifier
146
domain: Item domain
147
role: Item role
148
uri: Item URI/link
149
priority: Item priority
150
dispname: Display name
151
"""
152
153
sphinx_item_regex: re.Pattern = re.compile(r"^(.+?)\s+(\S+):(\S+)\s+(-?\d+)\s+(\S+)\s*(.*)$")
154
"""Regex to parse a Sphinx v2 inventory line."""
155
156
def format_sphinx(self) -> str:
157
"""
158
Format this item as a Sphinx inventory line.
159
160
Returns:
161
A line formatted for an objects.inv file
162
"""
163
164
@classmethod
165
def parse_sphinx(
166
cls,
167
line: str,
168
*,
169
return_none: bool = False
170
) -> InventoryItem | None:
171
"""
172
Parse a line from a Sphinx v2 inventory file and return an InventoryItem from it.
173
174
Args:
175
line: Sphinx inventory line to parse
176
return_none: Return None instead of raising ValueError on parse failure
177
178
Returns:
179
InventoryItem instance or None if parsing fails and return_none is True
180
"""
181
182
name: str
183
"""The item name."""
184
185
domain: str
186
"""The item domain."""
187
188
role: str
189
"""The item role."""
190
191
uri: str
192
"""The item URI."""
193
194
priority: int
195
"""The item priority."""
196
197
dispname: str
198
"""The item display name."""
199
```
200
201
**Usage Examples:**
202
203
Creating inventory items:
204
```python
205
from mkdocstrings import InventoryItem
206
207
# Create item for a Python class
208
class_item = InventoryItem(
209
name="MyClass",
210
domain="py",
211
role="class",
212
uri="api.html#MyClass",
213
priority=1,
214
dispname="my_module.MyClass"
215
)
216
217
# Create item for a function
218
func_item = InventoryItem(
219
name="my_function",
220
domain="py",
221
role="function",
222
uri="api.html#my_function",
223
priority=2
224
)
225
226
# Format for Sphinx
227
sphinx_line = class_item.format_sphinx()
228
print(sphinx_line) # "MyClass py:class 1 api.html#MyClass my_module.MyClass"
229
```
230
231
Parsing Sphinx inventory lines:
232
```python
233
sphinx_line = "my_function py:function 1 api.html#my_function -"
234
item = InventoryItem.parse_sphinx(sphinx_line)
235
236
print(item.name) # "my_function"
237
print(item.domain) # "py"
238
print(item.role) # "function"
239
print(item.uri) # "api.html#my_function"
240
```
241
242
## Integration with Handlers
243
244
### Handler Registration
245
246
Handlers automatically register items in the inventory during rendering:
247
248
```python
249
class MyHandler(BaseHandler):
250
enable_inventory = True # Enable inventory for this handler
251
domain = "mylang" # Set domain for items
252
253
def render(self, data: CollectorItem, options: HandlerOptions, *, locale: str | None = None) -> str:
254
# Register in inventory
255
self.handlers.inventory.register(
256
name=data.name,
257
domain=self.domain,
258
role=data.kind, # "class", "function", etc.
259
uri=f"#{data.anchor}",
260
dispname=data.full_name
261
)
262
263
# Render normally
264
return self.render_template(data, options)
265
```
266
267
### Cross-Project References
268
269
Inventories enable cross-project documentation linking:
270
271
```python
272
# In handler initialization
273
def __init__(self, *args, **kwargs):
274
super().__init__(*args, **kwargs)
275
276
# Load external inventories
277
self.load_external_inventories()
278
279
def load_external_inventories(self):
280
"""Load inventories from external projects."""
281
for url, config in self.get_inventory_urls():
282
try:
283
with urllib.request.urlopen(f"{url}/objects.inv") as f:
284
external_inv = Inventory.parse_sphinx(f)
285
self.handlers.inventory.update(external_inv)
286
except Exception as e:
287
self.logger.warning(f"Failed to load inventory from {url}: {e}")
288
```
289
290
### Automatic Cross-References
291
292
The inventory system works with autorefs to provide automatic cross-referencing:
293
294
```python
295
# In template or handler
296
def resolve_reference(self, identifier: str) -> str | None:
297
"""Resolve identifier to URL using inventory."""
298
if identifier in self.handlers.inventory:
299
item = self.handlers.inventory[identifier]
300
return item.uri
301
return None
302
303
# Usage in templates
304
"""
305
{% if resolve_reference("MyClass") %}
306
<a href="{{ resolve_reference('MyClass') }}">MyClass</a>
307
{% else %}
308
MyClass
309
{% endif %}
310
"""
311
```
312
313
## Sphinx Compatibility
314
315
### Inventory Format
316
317
mkdocstrings uses the same inventory format as Sphinx:
318
319
```
320
# Inventory file structure
321
# Project: my-project
322
# Version: 1.0.0
323
324
MyClass py:class 1 api.html#MyClass my_module.MyClass
325
my_function py:function 1 api.html#my_function -
326
MY_CONSTANT py:data 1 api.html#MY_CONSTANT -
327
```
328
329
### Domain Mapping
330
331
Common domain mappings:
332
333
- **Python**: `py` (classes: `py:class`, functions: `py:function`, modules: `py:module`)
334
- **JavaScript**: `js` (functions: `js:function`, classes: `js:class`)
335
- **TypeScript**: `ts` (interfaces: `ts:interface`, types: `ts:type`)
336
- **C++**: `cpp` (classes: `cpp:class`, functions: `cpp:function`)
337
338
### Role Types
339
340
Standard role types across domains:
341
342
- `class` - Classes and class-like objects
343
- `function` - Functions and methods
344
- `method` - Class methods specifically
345
- `attribute` - Class/instance attributes
346
- `module` - Modules and namespaces
347
- `constant` - Constants and enums
348
- `type` - Type definitions
349
- `interface` - Interfaces (TypeScript, etc.)
350
351
## Configuration
352
353
### Plugin Configuration
354
355
Enable inventory in plugin configuration:
356
357
```yaml
358
plugins:
359
- mkdocstrings:
360
enable_inventory: true
361
handlers:
362
python:
363
options:
364
# Handler options
365
```
366
367
### Handler Configuration
368
369
Configure inventory behavior per handler:
370
371
```python
372
class MyHandler(BaseHandler):
373
enable_inventory = True # Enable for this handler
374
domain = "mylang" # Set domain
375
376
def get_inventory_urls(self) -> list[tuple[str, dict[str, Any]]]:
377
"""Return external inventory URLs to load."""
378
return [
379
("https://docs.python.org/3/", {}),
380
("https://numpy.org/doc/stable/", {"domain_filter": ["py"]}),
381
]
382
```
383
384
### External Inventory Loading
385
386
Load inventories from external projects:
387
388
```python
389
# In handler configuration
390
inventory_urls = [
391
"https://docs.python.org/3/objects.inv",
392
"https://docs.mkdocs.org/objects.inv",
393
"https://python-markdown.github.io/objects.inv"
394
]
395
396
# Automatic loading during handler initialization
397
for url in inventory_urls:
398
try:
399
external_inventory = self.load_inventory_from_url(url)
400
self.handlers.inventory.update(external_inventory)
401
except Exception as e:
402
self.logger.warning(f"Failed to load {url}: {e}")
403
```
404
405
This enables seamless cross-referencing between projects and integration with the broader documentation ecosystem.