• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

domdfcoding / enum_tools / 15072251616

16 May 2025 03:43PM UTC coverage: 87.452% (+0.03%) from 87.427%
15072251616

push

github

web-flow
Updated files with 'repo_helper'. (#108)

Co-authored-by: repo-helper[bot] <74742576+repo-helper[bot]@users.noreply.github.com>

453 of 518 relevant lines covered (87.45%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.65
/enum_tools/autoenum.py
1
#!/usr/bin/env python3
2
#
3
#  autoenum.py
4
"""
5
A Sphinx directive for documenting :class:`Enums <enum.Enum>` in Python.
6
"""
7
#
8
#  Copyright (c) 2020-2022 Dominic Davis-Foster <dominic@davis-foster.co.uk>
9
#
10
#  This program is free software; you can redistribute it and/or modify
11
#  it under the terms of the GNU Lesser General Public License as published by
12
#  the Free Software Foundation; either version 3 of the License, or
13
#  (at your option) any later version.
14
#
15
#  This program is distributed in the hope that it will be useful,
16
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
#  GNU Lesser General Public License for more details.
19
#
20
#  You should have received a copy of the GNU Lesser General Public License
21
#  along with this program; if not, write to the Free Software
22
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23
#  MA 02110-1301, USA.
24
#
25
#  Parts based on https://github.com/sphinx-doc/sphinx
26
#  |  Copyright (c) 2007-2020 by the Sphinx team (see AUTHORS file).
27
#  |  BSD Licensed
28
#  |  All rights reserved.
29
#  |
30
#  |  Redistribution and use in source and binary forms, with or without
31
#  |  modification, are permitted provided that the following conditions are
32
#  |  met:
33
#  |
34
#  |  * Redistributions of source code must retain the above copyright
35
#  |   notice, this list of conditions and the following disclaimer.
36
#  |
37
#  |  * Redistributions in binary form must reproduce the above copyright
38
#  |   notice, this list of conditions and the following disclaimer in the
39
#  |   documentation and/or other materials provided with the distribution.
40
#  |
41
#  |  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
42
#  |  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
43
#  |  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
44
#  |  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
45
#  |  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46
#  |  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47
#  |  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
48
#  |  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
49
#  |  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50
#  |  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
51
#  |  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52
#
53

54
# stdlib
55
from contextlib import suppress
1✔
56
from enum import Enum
1✔
57
from typing import Any, Dict, List, Optional, Tuple, get_type_hints
1✔
58

59
# 3rd party
60
import sphinx  # nodep
1✔
61
from docutils.nodes import Element  # nodep
1✔
62
from sphinx.application import Sphinx  # nodep
1✔
63
from sphinx.domains import ObjType  # nodep
1✔
64
from sphinx.domains.python import PyClasslike, PyXRefRole  # nodep
1✔
65
from sphinx.environment import BuildEnvironment  # nodep
1✔
66
from sphinx.errors import PycodeError  # nodep
1✔
67
from sphinx.ext.autodoc import (  # nodep
1✔
68
                ALL,
69
                INSTANCEATTR,
70
                SUPPRESS,
71
                AttributeDocumenter,
72
                ClassDocumenter,
73
                ClassLevelDocumenter,
74
                Documenter,
75
                ObjectMember,
76
                logger
77
                )
78
from sphinx.locale import _  # nodep
1✔
79
from sphinx.pycode import ModuleAnalyzer  # nodep
1✔
80
from sphinx.util.inspect import memory_address_re, safe_getattr  # nodep
1✔
81
from sphinx_toolbox.more_autodoc import ObjectMembers  # nodep
1✔
82
from sphinx_toolbox.more_autodoc.typehints import format_annotation  # nodep
1✔
83
from sphinx_toolbox.utils import add_fallback_css_class  # nodep
1✔
84
from sphinx_toolbox.utils import unknown_module_warning  # nodep
1✔
85

86
try:
1✔
87
        # 3rd party
88
        from sphinx.util.typing import stringify_annotation as stringify_typehint  # type: ignore[attr-defined]
1✔
89
except ImportError:
1✔
90
        from sphinx.util.typing import stringify as stringify_typehint
1✔
91

92
# this package
93
from enum_tools import __version__, documentation
1✔
94
from enum_tools.utils import get_base_object, is_enum, is_flag
1✔
95

96
__all__ = ["EnumDocumenter", "EnumMemberDocumenter", "setup", "FlagDocumenter", "PyEnumXRefRole"]
1✔
97

98
documentation.INTERACTIVE = True
1✔
99

100
_filename_set_attribute = "filename_set" if sphinx.version_info < (4, 0) else "record_dependencies"
1✔
101

102

103
def _begin_generate(
1✔
104
                documenter: Documenter,
105
                real_modname: Optional[str] = None,
106
                check_module: bool = False,
107
                ) -> Optional[str]:
108
        """
109
        Boilerplate for the top of ``generate`` in :class:`sphinx.ext.autodoc.Documenter` subclasses.
110

111
        :param documenter:
112
        :param real_modname:
113
        :param check_module:
114

115
        :return: The ``sourcename``, or :py:obj:`None` if certain conditions are met,
116
                to indicate that the Documenter class should exit early.
117
        """
118

119
        # Do not pass real_modname and use the name from the __module__
120
        # attribute of the class.
121
        # If a class gets imported into the module real_modname
122
        # the analyzer won't find the source of the class, if
123
        # it looks in real_modname.
124

125
        if not documenter.parse_name():
1✔
126
                # need a module to import
127
                unknown_module_warning(documenter)
×
128
                return None
×
129

130
        # now, import the module and get object to document
131
        if not documenter.import_object():
1✔
132
                return None
×
133

134
        # If there is no real module defined, figure out which to use.
135
        # The real module is used in the module analyzer to look up the module
136
        # where the attribute documentation would actually be found in.
137
        # This is used for situations where you have a module that collects the
138
        # functions and classes of internal submodules.
139
        guess_modname = documenter.get_real_modname()
1✔
140
        documenter.real_modname = real_modname or guess_modname
1✔
141

142
        # try to also get a source code analyzer for attribute docs
143
        try:
1✔
144
                documenter.analyzer = ModuleAnalyzer.for_module(documenter.real_modname)
1✔
145
                # parse right now, to get PycodeErrors on parsing (results will
146
                # be cached anyway)
147
                documenter.analyzer.find_attr_docs()
1✔
148

149
        except PycodeError as err:  # pragma: no cover
150
                logger.debug("[autodoc] module analyzer failed: %s", err)
151
                # no source file -- e.g. for builtin and C modules
152
                documenter.analyzer = None  # type: ignore[assignment]
153
                # at least add the module.__file__ as a dependency
154
                if hasattr(documenter.module, "__file__") and documenter.module.__file__:
155
                        filename_set = getattr(documenter.directive, _filename_set_attribute)
156
                        filename_set.add(documenter.module.__file__)
157
        else:
158
                filename_set = getattr(documenter.directive, _filename_set_attribute)
1✔
159
                filename_set.add(documenter.analyzer.srcname)
1✔
160

161
        if documenter.real_modname != guess_modname:
1✔
162
                # Add module to dependency list if target object is defined in other module.
163
                with suppress(PycodeError):
×
164
                        analyzer = ModuleAnalyzer.for_module(guess_modname)
×
165
                        filename_set = getattr(documenter.directive, _filename_set_attribute)
×
166
                        filename_set.add(analyzer.srcname)
×
167

168
        # check __module__ of object (for members not given explicitly)
169
        if check_module:
1✔
170
                if not documenter.check_module():
×
171
                        return None
×
172

173
        sourcename = documenter.get_sourcename()
1✔
174

175
        # make sure that the result starts with an empty line.  This is
176
        # necessary for some situations where another directive preprocesses
177
        # reST and no starting newline is present
178
        documenter.add_line('', sourcename)
1✔
179

180
        return sourcename
1✔
181

182

183
class EnumDocumenter(ClassDocumenter):
1✔
184
        r"""
185
        Sphinx autodoc :class:`~sphinx.ext.autodoc.Documenter` for documenting :class:`~enum.Enum`\s.
186
        """
187

188
        objtype = "enum"
1✔
189
        directivetype = "enum"
1✔
190
        priority = 20
1✔
191
        class_xref = ":class:`~enum.Enum`"
1✔
192

193
        @classmethod
1✔
194
        def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any) -> bool:
1✔
195
                """
196
                Called to see if a member can be documented by this documenter.
197

198
                :param member:
199
                :param membername:
200
                :param isattr:
201
                :param parent:
202
                """
203

204
                return is_enum(member) and not is_flag(member)
1✔
205

206
        def document_members(self, all_members: bool = False) -> None:
1✔
207
                """
208
                Generate reST for member documentation.
209

210
                :param all_members: If :py:obj:`True`, document all members, otherwise document those given by
211
                        ``self.options.members``.
212

213
                .. latex:clearpage::
214
                """
215

216
                if self.doc_as_attr:
1✔
217
                        return
×
218

219
                # print(self.directive.result)
220
                # input("> ")
221

222
                # set current namespace for finding members
223
                self.env.temp_data["autodoc:module"] = self.modname
1✔
224
                if self.objpath:
1✔
225
                        self.env.temp_data["autodoc:class"] = self.objpath[0]
1✔
226

227
                want_all = all_members or self.options.inherited_members or self.options.members is ALL
1✔
228
                # find out which members are documentable
229
                members_check_module, members = self.get_object_members(want_all)
1✔
230

231
                non_enum_members: List[ObjectMember] = []
1✔
232
                for member in members:
1✔
233
                        if isinstance(member, ObjectMember):
1✔
234
                                if member.__name__ not in self.object.__members__.keys():
1✔
235
                                        non_enum_members.append(member)
1✔
236
                        else:
237
                                member_name = member[0]
×
238
                                if member_name not in self.object.__members__.keys():
×
239
                                        non_enum_members.append(ObjectMember(*member))
×
240

241
                user_option_undoc_members = self.options.undoc_members
1✔
242

243
                # Document enums first
244
                self.options.undoc_members = True  # type: ignore[attr-defined]
1✔
245

246
                enum_members = [ObjectMember(name=var.name, obj=var) for var in self.object]
1✔
247
                self._do_document_members(
1✔
248
                                enum_members,
249
                                want_all,
250
                                members_check_module,
251
                                description="Valid values are as follows:",
252
                                )
253

254
                # Document everything else
255
                self.options.undoc_members = user_option_undoc_members  # type: ignore[attr-defined]
1✔
256

257
                methods_text = (
1✔
258
                                f"The {self.class_xref} and its members "
259
                                f"{'also ' if enum_members else ''}have the following methods:"
260
                                )
261

262
                self._do_document_members(
1✔
263
                                non_enum_members,
264
                                want_all,
265
                                members_check_module,
266
                                description=methods_text,
267
                                )
268

269
        def _do_document_members(
1✔
270
                        self,
271
                        members: ObjectMembers,
272
                        want_all: bool,
273
                        members_check_module: bool,
274
                        description: str,
275
                        ) -> None:
276
                # remove members given by exclude-members
277
                if self.options.exclude_members:
1✔
278
                        new_members = []
1✔
279
                        for member in members:
1✔
280
                                if not isinstance(member, ObjectMember):
1✔
281
                                        member = ObjectMember(*member)
×
282
                                if (self.options.exclude_members is ALL or member.__name__ not in self.options.exclude_members):
1✔
283
                                        new_members.append(member)
1✔
284

285
                        members = new_members
1✔
286

287
                # document non-skipped members
288
                memberdocumenters: List[Tuple[Documenter, bool]] = []
1✔
289

290
                description_added = False
1✔
291

292
                for (mname, member, isattr) in self.filter_members(members, want_all):
1✔
293
                        if not description_added:
1✔
294
                                self.add_line(description, self.sourcename)
1✔
295
                                self.add_line('', self.sourcename)
1✔
296
                                description_added = True
1✔
297

298
                        # give explicitly separated module name, so that members
299
                        # of inner classes can be documented
300
                        full_mname = self.modname + "::" + '.'.join(self.objpath + [mname])
1✔
301

302
                        documenter: Documenter
303

304
                        if isinstance(member, Enum) and member in self.object:
1✔
305
                                documenter = EnumMemberDocumenter(self.directive, full_mname, self.indent)
1✔
306

307
                        else:
308
                                classes = [
1✔
309
                                                cls for cls in self.documenters.values()
310
                                                if cls.can_document_member(member, mname, isattr, self)
311
                                                ]
312

313
                                if not classes:
1✔
314
                                        # don't know how to document this member
315
                                        continue
×
316

317
                                # prefer the documenter with the highest priority
318
                                classes.sort(key=lambda cls: cls.priority)
1✔
319
                                documenter = classes[-1](self.directive, full_mname, self.indent)
1✔
320

321
                        memberdocumenters.append((documenter, isattr))
1✔
322

323
                member_order = self.options.member_order or self.env.config.autodoc_member_order
1✔
324

325
                if member_order == "groupwise":
1✔
326
                        # sort by group; relies on stable sort to keep items in the
327
                        # same group sorted alphabetically
328
                        memberdocumenters.sort(key=lambda e: e[0].member_order)
×
329

330
                elif member_order == "bysource" and self.analyzer:
1✔
331
                        # sort by source order, by virtue of the module analyzer
332
                        tagorder = self.analyzer.tagorder
×
333

334
                        def keyfunc(entry: Tuple[Documenter, bool]) -> int:
×
335
                                fullname = entry[0].name.split("::")[1]
×
336
                                return tagorder.get(fullname, len(tagorder))
×
337

338
                        memberdocumenters.sort(key=keyfunc)
×
339

340
                for documenter, isattr in memberdocumenters:
1✔
341
                        documenter.generate(
1✔
342
                                        all_members=True,
343
                                        real_modname=self.real_modname,
344
                                        check_module=members_check_module and not isattr,
345
                                        )
346

347
                # reset current objects
348
                self.env.temp_data["autodoc:module"] = None
1✔
349
                self.env.temp_data["autodoc:class"] = None
1✔
350

351
        real_modname: str
1✔
352

353
        def generate(
1✔
354
                        self,
355
                        more_content: Optional[Any] = None,
356
                        real_modname: Optional[str] = None,
357
                        check_module: bool = False,
358
                        all_members: bool = False,
359
                        ) -> None:
360
                """
361
                Generate reST for the object given by *self.name*, and possibly for its members.
362

363
                :param more_content: Additional content to include in the reST output.
364
                :param real_modname: Module name to use to find attribute documentation.
365
                :param check_module: If :py:obj:`True`, only generate if the object is defined
366
                        in the module name it is imported from.
367
                :param all_members: If :py:obj:`True`, document all members.
368
                """
369

370
                ret = _begin_generate(self, real_modname, check_module)
1✔
371
                if ret is None:
1✔
372
                        return
×
373

374
                sourcename = ret
1✔
375

376
                # Set sourcename as instance variable to avoid passing it around; it will get deleted later
377
                self.sourcename = sourcename
1✔
378

379
                # generate the directive header and options, if applicable
380
                self.add_directive_header("(value)")
1✔
381
                self.add_line('', sourcename)
1✔
382

383
                self.indent += self.content_indent
1✔
384

385
                # add all content (from docstrings, attribute docs etc.)
386
                self.add_content(more_content)
1✔
387

388
                member_type = get_base_object(self.object)
1✔
389

390
                if member_type is not object:
1✔
391
                        # Show the type of the members
392
                        self.add_line(f":Member Type: {format_annotation(member_type)}", self.sourcename)
1✔
393
                        self.add_line('', self.sourcename)
1✔
394

395
                # document members, if possible
396
                self.document_members(all_members)
1✔
397
                del self.sourcename
1✔
398

399
        _generate = generate
1✔
400

401

402
class FlagDocumenter(EnumDocumenter):
1✔
403
        r"""
404
        Sphinx autodoc :class:`~sphinx.ext.autodoc.Documenter` for documenting :class:`~enum.Flag`\s.
405

406
        .. autosummary-widths:: 55/100
407
        """
408

409
        objtype = "flag"
1✔
410
        directivetype = "flag"
1✔
411
        priority = 15
1✔
412
        class_xref = ":class:`~enum.Flag`"
1✔
413

414
        @classmethod
1✔
415
        def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any) -> bool:
1✔
416
                """
417
                Called to see if a member can be documented by this documenter.
418

419
                :param member:
420
                :param membername:
421
                :param isattr:
422
                :param parent:
423
                """
424

425
                return is_flag(member)
1✔
426

427

428
class EnumMemberDocumenter(AttributeDocumenter):
1✔
429
        """
430
        Sphinx autodoc :class:`~sphinx.ext.autodoc.Documenter` for documenting :class:`~enum.Enum` members.
431
        """
432

433
        def import_object(self, raiseerror: bool = False) -> bool:
1✔
434
                """
435
                Import the object given by ``self.modname`` and ``self.objpath`` and set it as ``self.object``.
436

437
                :param raiseerror:
438

439
                :returns: :py:obj:`True` if successful, :py:obj:`False` if an error occurred.
440

441
                .. latex:clearpage::
442
                """
443

444
                return Documenter.import_object(self, raiseerror=raiseerror)
1✔
445

446
        def generate(
1✔
447
                        self,
448
                        more_content: Optional[Any] = None,
449
                        real_modname: Optional[str] = None,
450
                        check_module: bool = False,
451
                        all_members: bool = False
452
                        ) -> None:
453
                """
454
                Generate reST for the object given by ``self.name``, and possibly for its members.
455

456
                :param more_content: Additional content to include in the reST output.
457
                :param real_modname: Module name to use to find attribute documentation.
458
                :param check_module: If :py:obj:`True`, only generate if the object is defined in
459
                        the module name it is imported from.
460
                :param all_members: If :py:obj:`True`, document all members.
461

462

463
                .. versionchanged:: 0.8.0
464

465
                        Multiline docstrings are now correctly represented in the generated output.
466
                """
467

468
                ret = _begin_generate(self, real_modname, check_module)
1✔
469
                if ret is None:
1✔
470
                        return
×
471

472
                sourcename = ret
1✔
473

474
                # generate the directive header and options, if applicable
475
                self.add_directive_header('')
1✔
476
                self.add_line('', sourcename)
1✔
477

478
                # e.g. the module directive doesn't have content
479
                self.indent += self.content_indent
1✔
480

481
                # Add the value's docstring
482
                if self.object.__doc__ and self.object.__doc__ != self.object.__class__.__doc__:
1✔
483
                        # Lines of multiline docstrings need to be added one by one.
484
                        for line in self.object.__doc__.splitlines():
1✔
485
                                self.add_line(line, sourcename)
1✔
486
                        self.add_line('', sourcename)
1✔
487

488
        def add_directive_header(self, sig: str) -> None:
1✔
489
                """
490
                Add the directive header for the Enum member.
491

492
                :param sig:
493
                """
494

495
                ClassLevelDocumenter.add_directive_header(self, sig)
1✔
496
                sourcename = self.get_sourcename()
1✔
497
                if not self.options.annotation:
1✔
498
                        # obtain type annotation for this attribute
499
                        try:
1✔
500
                                annotations = get_type_hints(self.parent)
1✔
501
                        except NameError:
×
502
                                # Failed to evaluate ForwardRef (maybe TYPE_CHECKING)
503
                                annotations = safe_getattr(self.parent, "__annotations__", {})
×
504
                        except (TypeError, KeyError, AttributeError):
×
505
                                # KeyError = a broken class found (refs: https://github.com/sphinx-doc/sphinx/issues/8084)
506
                                # AttributeError is raised on 3.5.2 (fixed by 3.5.3)
507
                                annotations = {}
×
508

509
                        if self.objpath[-1] in annotations:
1✔
510
                                objrepr = stringify_typehint(annotations.get(self.objpath[-1]))
×
511
                                self.add_line("   :type: " + objrepr, sourcename)
×
512
                        else:
513
                                key = ('.'.join(self.objpath[:-1]), self.objpath[-1])
1✔
514
                                if self.analyzer and key in self.analyzer.annotations:
1✔
515
                                        self.add_line("   :type: " + self.analyzer.annotations[key], sourcename)
×
516

517
                elif self.options.annotation is SUPPRESS:
×
518
                        pass
×
519
                else:
520
                        self.add_line("   :annotation: %s" % self.options.annotation, sourcename)
×
521

522
                if not self.options.annotation:
1✔
523
                        with suppress(Exception):
1✔
524
                                if self.object is not INSTANCEATTR:
1✔
525

526
                                        # Workaround for https://github.com/sphinx-doc/sphinx/issues/9272
527
                                        # which broke Enum displays in 4.1.0
528
                                        objrepr = memory_address_re.sub('', repr(self.object)).replace('\n', ' ')
1✔
529
                                        self.add_line(f'   :value: {objrepr}', self.get_sourcename())
1✔
530

531

532
class PyEnumXRefRole(PyXRefRole):
1✔
533
        """
534
        XRefRole for Enum/Flag members.
535

536
        .. versionadded:: 0.4.0
537
        .. autosummary-widths:: 40/100
538
        """
539

540
        def process_link(
1✔
541
                        self,
542
                        env: BuildEnvironment,
543
                        refnode: Element,
544
                        has_explicit_title: bool,
545
                        title: str,
546
                        target: str,
547
                        ) -> Tuple[str, str]:
548
                """
549
                Called after parsing title and target text, and creating the reference node (given in ``refnode``).
550

551
                This method can alter the reference node and must return a new (or the same)
552
                ``(title, target)`` tuple.
553

554
                :param env:
555
                :param refnode:
556
                :param has_explicit_title:
557
                :param title:
558
                :param target:
559

560
                :rtype:
561

562
                .. latex:clearpage::
563
                """
564

565
                refnode["py:module"] = env.ref_context.get("py:module")
1✔
566
                refnode["py:class"] = env.ref_context.get("py:class")
1✔
567

568
                if not has_explicit_title:
1✔
569
                        title = title.lstrip('.')  # only has a meaning for the target
1✔
570
                        target = target.lstrip("~+")  # only has a meaning for the title
1✔
571
                        # if the first character is a tilde, don't display the module/class
572
                        # parts of the contents
573

574
                        if title[0:1] == '~':
1✔
575
                                title = '.'.join(title[1:].split('.')[-2:])
×
576

577
                        elif title[0:1] == '+':
1✔
578
                                title = title[1:]
×
579
                                dot = title.rfind('.')
×
580
                                if dot != -1:
×
581
                                        title = title[dot + 1:]
×
582

583
                # if the first character is a dot, search more specific namespaces first
584
                # else search builtins first
585
                if target[0:1] == '.':
1✔
586
                        target = target[1:]
×
587
                        refnode["refspecific"] = True
×
588

589
                return title, target
1✔
590

591

592
def setup(app: Sphinx) -> Dict[str, Any]:
1✔
593
        """
594
        Setup Sphinx Extension.
595

596
        :param app:
597
        """
598

599
        app.registry.domains["py"].object_types["enum"] = ObjType(_("enum"), "enum", "class", "obj")
1✔
600
        app.add_directive_to_domain("py", "enum", PyClasslike)
1✔
601
        app.add_role_to_domain("py", "enum", PyXRefRole())
1✔
602

603
        app.registry.domains["py"].object_types["flag"] = ObjType(_("flag"), "flag", "enum", "class", "obj")
1✔
604
        app.add_directive_to_domain("py", "flag", PyClasslike)
1✔
605
        app.add_role_to_domain("py", "flag", PyXRefRole())
1✔
606

607
        app.add_role_to_domain("py", "enum:mem", PyEnumXRefRole())
1✔
608
        app.add_role_to_domain("py", "enum:member", PyEnumXRefRole())
1✔
609
        app.add_role_to_domain("py", "flag:mem", PyEnumXRefRole())
1✔
610
        app.add_role_to_domain("py", "flag:member", PyEnumXRefRole())
1✔
611

612
        app.add_autodocumenter(EnumDocumenter)
1✔
613
        app.add_autodocumenter(FlagDocumenter)
1✔
614

615
        app.connect("object-description-transform", add_fallback_css_class({"enum": "class", "flag": "class"}))
1✔
616

617
        return {
1✔
618
                        "version": __version__,
619
                        "parallel_read_safe": True,
620
                        "parallel_write_safe": True,
621
                        }
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc