2
2
# License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
4
5
- """Contains the autoconfig Sphinx extension for auto-documenting components
5
+ """Contains the autocomponent Sphinx extension for auto-documenting components
6
6
with configuration.
7
7
8
- The ``autoconfig `` declaration will pull out the class docstring as well as
8
+ The ``autocomponent `` declaration will pull out the class docstring as well as
9
9
configuration requirements, throw it all in a blender and spit it out.
10
10
11
- To configure Sphinx, add ``'everett.sphinx_autoconfig '`` to the
12
- ``extensions`` in `` conf.py``::
11
+ To configure Sphinx, add ``'everett.sphinxext '`` to the ``extensions`` in
12
+ ``conf.py``::
13
13
14
14
extensions = [
15
15
...
16
- 'everett.sphinx_autoconfig '
16
+ 'everett.sphinxext '
17
17
]
18
18
19
19
22
22
You need to make sure that Everett is installed in the environment
23
23
that Sphinx is being run in.
24
24
25
-
26
25
Use it like this in an ``.rst`` file to document a component::
27
26
28
- .. autoconfig:: collector.external.boto.crashstorage.BotoS3CrashStorage
27
+ .. autocomponent:: collector.external.boto.crashstorage.BotoS3CrashStorage
28
+
29
+
30
+ .. versionchanged:: 0.9
31
+
32
+ In Everett 0.8 and prior, the extension was in the
33
+ ``everett.sphinx_autoconfig`` module and the directive was ``..
34
+ autoconfig::``.
29
35
30
36
31
37
**Showing docstring and content**
32
38
33
39
If you want the docstring for the class, you can specify ``:show-docstring:``::
34
40
35
- .. autoconfig :: collector.external.boto.crashstorage.BotoS3CrashStorage
41
+ .. autocomponent :: collector.external.boto.crashstorage.BotoS3CrashStorage
36
42
:show-docstring:
37
43
38
44
39
45
If you want to show help, but from a different attribute than the docstring,
40
46
you can specify any class attribute::
41
47
42
- .. autoconfig :: collector.external.boto.crashstorage.BotoS3CrashStorage
48
+ .. autocomponent :: collector.external.boto.crashstorage.BotoS3CrashStorage
43
49
:show-docstring: __everett_help__
44
50
45
51
46
52
You can provide content as well::
47
53
48
- .. autoconfig :: collector.external.boto.crashstorage.BotoS3CrashStorage
54
+ .. autocomponent :: collector.external.boto.crashstorage.BotoS3CrashStorage
49
55
50
56
This is some content!
51
57
56
62
57
63
You can hide the class name if you want::
58
64
59
- .. autoconfig :: collector.external.boto.crashstorage.BotoS3CrashStorage
65
+ .. autocomponent :: collector.external.boto.crashstorage.BotoS3CrashStorage
60
66
:hide-classname:
61
67
62
68
74
80
75
81
You can do that like this::
76
82
77
- .. autoconfig :: collector.external.boto.crashstorage.BotoS3CrashStorage
83
+ .. autocomponent :: collector.external.boto.crashstorage.BotoS3CrashStorage
78
84
:namespace: crashstorage
79
85
80
86
92
98
93
99
You can do that like this::
94
100
95
- .. autoconfig :: collector.external.boto.crashstorage.BotoS3CrashStorage
101
+ .. autocomponent :: collector.external.boto.crashstorage.BotoS3CrashStorage
96
102
:case: upper
97
103
98
104
101
107
102
108
You can do that like this::
103
109
104
- .. autoconfig :: collector.external.boto.crashstorage.BotoS3CrashStorage
110
+ .. autocomponent :: collector.external.boto.crashstorage.BotoS3CrashStorage
105
111
:case: lower
106
112
107
113
.. versionadded:: 0.8
113
119
from docutils import nodes
114
120
from docutils .parsers .rst import Directive , directives
115
121
from docutils .statemachine import ViewList
122
+ from sphinx import addnodes
123
+ from sphinx .directives import ObjectDescription
124
+ from sphinx .domains import Domain , ObjType
125
+ from sphinx .roles import XRefRole
126
+ from sphinx .util .docfields import TypedField
127
+ from sphinx .locale import l_ , _
116
128
from sphinx .util .docstrings import prepare_docstring
117
129
118
- from everett import NO_VALUE
130
+ from everett import NO_VALUE , __version__
119
131
from everett .manager import qualname
120
132
121
133
@@ -151,7 +163,98 @@ def upper_lower_none(arg):
151
163
raise ValueError ('argument must be "upper", "lower" or None' )
152
164
153
165
154
- class AutoConfigDirective (Directive ):
166
+ class EverettComponent (ObjectDescription ):
167
+ """
168
+ Description of an Everett component""
169
+ """
170
+
171
+ doc_field_types = [
172
+ TypedField ('options' , label = l_ ('Options' ),
173
+ names = ('option' , 'opt' ),
174
+ typerolename = 'obj' , typenames = ('parser' ,),
175
+ can_collapse = True ),
176
+ ]
177
+
178
+ allow_nesting = False
179
+
180
+ def handle_signature (self , sig , signode ):
181
+ if sig != 'Configuration' :
182
+ # Add "component" to the beginning if it's a specific component
183
+ signode .clear ()
184
+
185
+ # Add "component" which is the type of this thing
186
+ signode += addnodes .desc_annotation ('component ' , 'component ' )
187
+
188
+ if '.' in sig :
189
+ modname , clsname = sig .rsplit ('.' , 1 )
190
+ else :
191
+ modname , clsname = '' , sig
192
+
193
+ # If there's a module name, then we add the module
194
+ if modname :
195
+ signode += addnodes .desc_addname (modname + '.' , modname + '.' )
196
+
197
+ # Add the class name
198
+ signode += addnodes .desc_name (clsname , clsname )
199
+ else :
200
+ # Add just "Configuration"
201
+ signode += addnodes .desc_name (sig , sig )
202
+
203
+ return sig
204
+
205
+ def add_target_and_index (self , name , sig , signode ):
206
+ targetname = '%s-%s' % (self .objtype , name )
207
+
208
+ if targetname not in self .state .document .ids :
209
+ signode ['names' ].append (targetname )
210
+ signode ['ids' ].append (targetname )
211
+ signode ['first' ] = (not self .names )
212
+ self .state .document .note_explicit_target (signode )
213
+
214
+ objects = self .env .domaindata ['everett' ]['objects' ]
215
+ key = (self .objtype , name )
216
+ if key in objects :
217
+ self .state_machine .reporter .warning (
218
+ 'duplicate description of %s %s, ' % (self .objtype , name ) +
219
+ 'other instance in ' + self .env .doc2path (objects [key ]),
220
+ line = self .lineno
221
+ )
222
+ objects [key ] = self .env .docname
223
+
224
+ indextext = _ ('%s (component)' ) % name
225
+ self .indexnode ['entries' ].append (('single' , indextext , targetname , '' , None ))
226
+
227
+
228
+ class EverettDomain (Domain ):
229
+ """Everett domain for component configuration"""
230
+ name = 'everett'
231
+ label = 'Everett'
232
+
233
+ object_types = {
234
+ 'component' : ObjType (l_ ('component' ), 'comp' ),
235
+ }
236
+ directives = {
237
+ 'component' : EverettComponent ,
238
+ }
239
+ roles = {
240
+ 'comp' : XRefRole (),
241
+ }
242
+ initial_data = {
243
+ 'objects' : {},
244
+ }
245
+
246
+ def clear_doc (self , docname ):
247
+ for (typ , name ), doc in list (self .data ['objects' ].items ()):
248
+ if doc == docname :
249
+ del self .data ['objects' ][typ , name ]
250
+
251
+ def merge_domaindata (self , docnames , otherdata ):
252
+ for (typ , name ), doc in otherdata ['objects' ].items ():
253
+ if doc in docnames :
254
+ self .data ['objects' ][typ , name ] = doc
255
+
256
+
257
+ class AutoComponentDirective (Directive ):
155
258
has_content = True
156
259
required_arguments = 1
157
260
optional_arguments = 0
@@ -185,11 +288,11 @@ def generate_docs(self, clspath, more_content):
185
288
# Add the classname or 'Configuration'
186
289
if 'hide-classname' not in self .options :
187
290
modname , clsname = split_clspath (clspath )
188
- self .add_line ('.. %s:%s:: %s.%s' % ('py' , 'class' , modname , clsname ),
189
- sourcename )
190
- indent = ' '
291
+ self .add_line ('.. everett:component:: %s.%s' % (modname , clsname ), sourcename )
191
292
else :
192
- indent = ''
293
+ self .add_line ('.. everett:component:: Configuration' , sourcename )
294
+
295
+ indent = ' '
193
296
self .add_line ('' , sourcename )
194
297
195
298
# Add the docstring if there is one and if show-docstring
@@ -212,9 +315,6 @@ def generate_docs(self, clspath, more_content):
212
315
config = obj .get_required_config ()
213
316
214
317
if config .options :
215
- self .add_line (indent + 'Configuration:' , '' )
216
- self .add_line ('' , '' )
217
-
218
318
sourcename = 'class definition'
219
319
220
320
for option in config :
@@ -229,17 +329,16 @@ def generate_docs(self, clspath, more_content):
229
329
elif self .options ['case' ] == 'lower' :
230
330
namespaced_key = namespaced_key .lower ()
231
331
232
- self .add_line ('%s ``%s``' % (indent , namespaced_key ), sourcename )
233
- if option .default is NO_VALUE :
234
- self .add_line ('%s :default: ' % indent , sourcename )
235
- else :
236
- self .add_line ('%s :default: ``%r``' % (indent , option .default ),
237
- sourcename )
238
-
239
- self .add_line ('%s :parser: %s' % (indent , qualname (option .parser )),
240
- sourcename )
241
- self .add_line ('' , '' )
242
- self .add_line ('%s %s' % (indent , option .doc ), sourcename )
332
+ self .add_line ('%s:option %s %s:' % (
333
+ indent , qualname (option .parser ), namespaced_key ), sourcename
334
+ )
335
+ self .add_line ('%s %s' % (indent , option .doc ), sourcename )
336
+ if option .default is not NO_VALUE :
337
+ self .add_line ('' , '' )
338
+ self .add_line (
339
+ '%s Defaults to ``%r``.' % (indent , option .default ),
340
+ sourcename
341
+ )
243
342
self .add_line ('' , '' )
244
343
245
344
def run (self ):
@@ -258,4 +357,11 @@ def run(self):
258
357
259
358
260
359
def setup (app ):
261
- app .add_directive ('autoconfig' , AutoConfigDirective )
360
+ app .add_domain (EverettDomain )
361
+ app .add_directive ('autocomponent' , AutoComponentDirective )
362
+
363
+ return {
364
+ 'version' : __version__ ,
365
+ 'parallel_read_safe' : True ,
366
+ 'parallel_write_safe' : True
367
+ }
0 commit comments