0
# Style System
1
2
Pluggable style system for citation formatting and referencing, supporting multiple citation styles through a flexible plugin architecture built on top of pybtex styles.
3
4
## Capabilities
5
6
### Base Reference Style
7
8
Abstract base class for all citation reference styles that defines the interface for formatting citations.
9
10
```python { .api }
11
class BaseReferenceStyle(ABC):
12
"""
13
Base class for citation reference styles.
14
15
All subclasses must be decorated as dataclass and provide default values
16
for all attributes to allow instantiation without arguments.
17
"""
18
19
def role_names(self) -> Iterable[str]:
20
"""
21
Get list of role names supported by this style.
22
23
Returns:
24
Iterable of role names (e.g., ['p', 't'] for parenthetical/textual)
25
"""
26
27
def outer(self, role_name: str, children: List[BaseText]) -> Node:
28
"""
29
Returns outer template for formatting multiple references.
30
31
Parameters:
32
role_name: The citation role name ('p', 't', etc.)
33
children: List of formatted individual references
34
35
Returns:
36
Template node for combining multiple references
37
"""
38
39
def inner(self, role_name: str) -> Node:
40
"""
41
Returns inner template for formatting individual references.
42
43
Parameters:
44
role_name: The citation role name ('p', 't', etc.)
45
46
Returns:
47
Template node for formatting single reference
48
"""
49
```
50
51
### Reference Formatting
52
53
Core function that formats lists of references according to a given style.
54
55
```python { .api }
56
def format_references(
57
style: BaseReferenceStyle,
58
role_name: str,
59
references: Iterable[Tuple[Entry, FormattedEntry, ReferenceInfo]],
60
) -> BaseText:
61
"""
62
Format list of references according to the given role and style.
63
64
First formats each reference using the style's inner method,
65
then combines all formatted references using the style's outer method.
66
67
Parameters:
68
style: Reference style instance to use for formatting
69
role_name: Citation role name ('p' for parenthetical, 't' for textual)
70
references: Iterable of (entry, formatted_entry, reference_info) tuples
71
72
Returns:
73
Formatted text containing all references
74
"""
75
```
76
77
### Style Composition
78
79
Classes for composing and customizing reference styles with brackets, separators, and person formatting.
80
81
```python { .api }
82
class BracketStyle:
83
"""
84
Provides brackets and separators for citation formatting.
85
86
Attributes:
87
left: Left bracket character or text (default: "[")
88
right: Right bracket character or text (default: "]")
89
sep: Separator between multiple citations (default: ", ")
90
sep2: Separator when exactly two citations (default: None)
91
last_sep: Separator before last citation when 3+ citations (default: None)
92
"""
93
left: Union[BaseText, str] = "["
94
right: Union[BaseText, str] = "]"
95
sep: Union[BaseText, str] = ", "
96
sep2: Optional[Union[BaseText, str]] = None
97
last_sep: Optional[Union[BaseText, str]] = None
98
99
def outer(
100
self,
101
children: List[BaseText],
102
brackets: bool = False,
103
capfirst: bool = False
104
) -> Node:
105
"""
106
Create outer template with separators, brackets, and capitalization.
107
108
Parameters:
109
children: List of formatted citation components
110
brackets: Whether to add brackets around the result
111
capfirst: Whether to capitalize the first word
112
113
Returns:
114
Template node with appropriate formatting
115
"""
116
117
class PersonStyle:
118
"""
119
Provides person name formatting for citations.
120
121
Attributes:
122
style: Plugin name for name formatting style (default: "last")
123
abbreviate: Whether to abbreviate first names (default: True)
124
sep: Separator between persons (default: ", ")
125
sep2: Separator for exactly two persons (default: " and ")
126
last_sep: Separator before last person when 3+ (default: ", and ")
127
other: Text for 3+ persons abbreviation (default: " et al.")
128
"""
129
style: str = "last"
130
abbreviate: bool = True
131
sep: Union[BaseText, str] = ", "
132
sep2: Optional[Union[BaseText, str]] = " and "
133
last_sep: Optional[Union[BaseText, str]] = ", and "
134
other: Optional[Union[BaseText, str]] = None # Defaults to " et al."
135
136
def names(self, role: str, full: bool) -> Node:
137
"""
138
Template for formatting person names with separators.
139
140
Parameters:
141
role: Person role ("author" or "editor")
142
full: Whether to show full person list or use abbreviation
143
144
Returns:
145
Template node for person name formatting
146
"""
147
148
def author_or_editor_or_title(self, full: bool) -> Node:
149
"""
150
Template for author names, falling back to editor or title.
151
152
Parameters:
153
full: Whether to show full person list
154
155
Returns:
156
Template node with fallback logic
157
"""
158
159
class GroupReferenceStyle(BaseReferenceStyle):
160
"""
161
Composes multiple reference styles into a single consistent style.
162
163
Allows different role names to use different formatting approaches
164
while maintaining a unified interface.
165
166
Attributes:
167
styles: List of component reference styles
168
"""
169
styles: List[BaseReferenceStyle] = field(default_factory=list)
170
171
def role_names(self) -> Iterable[str]:
172
"""Get all role names from all component styles."""
173
174
def outer(self, role_name: str, children: List[BaseText]) -> Node:
175
"""Get outer template from the appropriate component style."""
176
177
def inner(self, role_name: str) -> Node:
178
"""Get inner template from the appropriate component style."""
179
```
180
181
### Plugin System
182
183
Functions for loading and registering citation style plugins.
184
185
```python { .api }
186
def find_plugin(group: str, name: str) -> Type[Any]:
187
"""
188
Load a sphinxcontrib-bibtex plugin from entry points or runtime store.
189
190
Parameters:
191
group: Plugin group name (e.g., "sphinxcontrib.bibtex.style.referencing")
192
name: Plugin name within the group
193
194
Returns:
195
Plugin class type
196
197
Raises:
198
ImportError: If plugin group or plugin name not found
199
"""
200
201
def register_plugin(
202
group: str,
203
name: str,
204
klass: Type[Any],
205
force: bool = False
206
) -> bool:
207
"""
208
Register a plugin in the runtime store.
209
210
Parameters:
211
group: Plugin group name
212
name: Plugin name within group
213
klass: Plugin class to register
214
force: Whether to override existing plugins
215
216
Returns:
217
True if plugin was registered, False if already exists and force=False
218
219
Raises:
220
ImportError: If plugin group is not recognized
221
"""
222
```
223
224
## Built-in Reference Styles
225
226
The extension provides several built-in reference styles via entry points:
227
228
### Author-Year Style
229
230
```python
231
# Entry point: sphinxcontrib.bibtex.style.referencing.author_year:AuthorYearReferenceStyle
232
# Configuration: bibtex_reference_style = "author_year"
233
234
# Example output:
235
# :cite:t: -> Smith (2020)
236
# :cite:p: -> (Smith, 2020; Jones, 2019)
237
```
238
239
### Label Style
240
241
```python
242
# Entry point: sphinxcontrib.bibtex.style.referencing.label:LabelReferenceStyle
243
# Configuration: bibtex_reference_style = "label" (default)
244
245
# Example output:
246
# :cite:t: -> Smith [Smi20]
247
# :cite:p: -> [Smi20, Jon19]
248
```
249
250
### Footnote Style
251
252
```python
253
# Entry point: sphinxcontrib.bibtex.style.referencing.foot:FootReferenceStyle
254
# Configuration: bibtex_foot_reference_style = "foot" (default for footnotes)
255
256
# Used with :footcite: roles for footnote formatting
257
```
258
259
### Superscript Style
260
261
```python
262
# Entry point: sphinxcontrib.bibtex.style.referencing.super_:SuperReferenceStyle
263
# Configuration: bibtex_reference_style = "super"
264
265
# Example output:
266
# :cite:p: -> [1,2]
267
# :cite:t: -> Smith¹
268
```
269
270
## Usage Examples
271
272
### Custom Reference Style
273
274
```python
275
from dataclasses import dataclass
276
from sphinxcontrib.bibtex.style.referencing import BaseReferenceStyle
277
278
@dataclass
279
class CustomReferenceStyle(BaseReferenceStyle):
280
def role_names(self):
281
return ["p", "t"]
282
283
def outer(self, role_name, children):
284
if role_name == "p":
285
return join["(", sentence[children], ")"]
286
else: # textual
287
return sentence[children]
288
289
def inner(self, role_name):
290
return field("author") + " " + field("year")
291
292
# Register the style
293
from sphinxcontrib.bibtex.plugin import register_plugin
294
register_plugin(
295
"sphinxcontrib.bibtex.style.referencing",
296
"custom",
297
CustomReferenceStyle
298
)
299
```
300
301
### Style Configuration
302
303
```python
304
# conf.py
305
bibtex_reference_style = "author_year" # For regular citations
306
bibtex_foot_reference_style = "foot" # For footnote citations
307
```
308
309
### Complex Style Composition
310
311
```python
312
@dataclass
313
class AuthorYearStyle(BaseReferenceStyle):
314
bracket: BracketStyle = field(default_factory=BracketStyle)
315
person: PersonStyle = field(default_factory=PersonStyle)
316
317
def role_names(self):
318
return ["p", "t"]
319
320
def outer(self, role_name, children):
321
return self.bracket.outer(
322
children,
323
brackets=(role_name == "p"),
324
capfirst=(role_name == "t")
325
)
326
327
def inner(self, role_name):
328
return join[
329
self.person.author_or_editor_or_title(full=False),
330
" ",
331
field("year")
332
]
333
```
334
335
## Rich Text Integration
336
337
The style system integrates with pybtex's rich text system for advanced formatting:
338
339
```python { .api }
340
# Type definitions for rich text integration
341
ReferenceInfo = TypeVar("ReferenceInfo")
342
343
class BaseReferenceText(BaseMultipartText, Generic[ReferenceInfo], ABC):
344
"""
345
Generic rich text element for citation references.
346
347
Stores extra reference information for use during formatting.
348
Must be subclassed to override render method for specific output formats.
349
"""
350
351
def __init__(self, info: ReferenceInfo, *parts: BaseText):
352
"""Initialize with reference info and text parts."""
353
```
354
355
## Error Handling
356
357
### Plugin Loading
358
359
- **Missing plugins**: `ImportError` with descriptive message about missing plugin
360
- **Invalid plugin groups**: `ImportError` for unrecognized plugin groups
361
- **Plugin conflicts**: Configurable override behavior with `force` parameter
362
363
### Style Formatting
364
365
- **Missing fields**: Handled by pybtex with appropriate fallbacks
366
- **Invalid templates**: Template syntax errors reported during style initialization
367
- **Type mismatches**: Clear error messages for incompatible style configurations
368
369
### Integration Issues
370
371
- **Style conflicts**: Warnings when multiple styles claim the same role names
372
- **Configuration errors**: Fallback to default styles with appropriate logging