1# $Id$
2# Author: David Goodger <goodger@python.org>
3# Copyright: This module has been placed in the public domain.
4
5"""
6This is the Docutils (Python Documentation Utilities) package.
7
8Package Structure
9=================
10
11Modules:
12
13- __init__.py: Contains component base classes, exception classes, and
14 Docutils version information.
15
16- core.py: Contains the ``Publisher`` class and ``publish_*()`` convenience
17 functions.
18
19- frontend.py: Runtime settings (command-line interface, configuration files)
20 processing, for Docutils front-ends.
21
22- io.py: Provides a uniform API for low-level input and output.
23
24- nodes.py: Docutils document tree (doctree) node class library.
25
26- statemachine.py: A finite state machine specialized for
27 regular-expression-based text filters.
28
29Subpackages:
30
31- languages: Language-specific mappings of terms.
32
33- parsers: Syntax-specific input parser modules or packages.
34
35- readers: Context-specific input handlers which understand the data
36 source and manage a parser.
37
38- transforms: Modules used by readers and writers to modify
39 the Docutils document tree.
40
41- utils: Contains the ``Reporter`` system warning class and miscellaneous
42 utilities used by readers, writers, and transforms.
43
44 utils/urischemes.py: Contains a complete mapping of known URI addressing
45 scheme names to descriptions.
46
47- utils/math: Contains functions for conversion of mathematical notation
48 between different formats (LaTeX, MathML, text, ...).
49
50- writers: Format-specific output translators.
51"""
52
53from __future__ import annotations
54
55from collections import namedtuple
56
57TYPE_CHECKING = False
58if TYPE_CHECKING:
59 from collections.abc import Sequence
60 from typing import Any, ClassVar, Literal, Protocol, Union
61
62 from docutils.nodes import Element
63 from docutils.transforms import Transform
64
65 _Components = Literal['reader', 'parser', 'writer', 'input', 'output']
66 _OptionTuple = tuple[str, list[str], dict[str, Any]]
67 _ReleaseLevels = Literal['alpha', 'beta', 'candidate', 'final']
68 _SettingsSpecTuple = Union[
69 tuple[str|None, str|None, Sequence[_OptionTuple]],
70 tuple[str|None, str|None, Sequence[_OptionTuple],
71 str|None, str|None, Sequence[_OptionTuple]],
72 tuple[str|None, str|None, Sequence[_OptionTuple],
73 str|None, str|None, Sequence[_OptionTuple],
74 str|None, str|None, Sequence[_OptionTuple]],
75 ]
76
77 class _UnknownReferenceResolver(Protocol):
78 """Deprecated. Will be removed in Docutils 1.0."""
79 # See `TransformSpec.unknown_reference_resolvers`.
80
81 priority: int
82
83 def __call__(self, node: Element, /) -> bool:
84 ...
85
86__docformat__ = 'reStructuredText'
87
88__version__ = '0.22rc4.dev'
89"""Docutils version identifier (complies with PEP 440)::
90
91 major.minor[.micro][releaselevel[serial]][.dev]
92
93For version comparison operations, use `__version_info__` (see, below)
94rather than parsing the text of `__version__`.
95
96https://docutils.sourceforge.io/docs/dev/policies.html#version-identification
97"""
98
99__version_details__ = ''
100"""Optional extra version details (e.g. 'snapshot 2005-05-29, r3410').
101
102For development and release status, use `__version__ and `__version_info__`.
103"""
104
105
106class VersionInfo(namedtuple('VersionInfo',
107 'major minor micro releaselevel serial release')):
108 __slots__ = ()
109
110 major: int
111 minor: int
112 micro: int
113 releaselevel: _ReleaseLevels
114 serial: int
115 release: bool
116
117 def __new__(cls,
118 major: int = 0, minor: int = 0, micro: int = 0,
119 releaselevel: _ReleaseLevels = 'final',
120 serial: int = 0, release: bool = True,
121 ) -> VersionInfo:
122 releaselevels = ('alpha', 'beta', 'candidate', 'final')
123 if releaselevel not in releaselevels:
124 raise ValueError('releaselevel must be one of %r.'
125 % (releaselevels, ))
126 if releaselevel == 'final':
127 if not release:
128 raise ValueError('releaselevel "final" must not be used '
129 'with development versions (leads to wrong '
130 'version ordering of the related __version__')
131 # cf. https://peps.python.org/pep-0440/#summary-of-permitted-suffixes-and-relative-ordering # NoQA: E501
132 if serial != 0:
133 raise ValueError('"serial" must be 0 for final releases')
134
135 return super().__new__(cls, major, minor, micro,
136 releaselevel, serial, release)
137
138 def __lt__(self, other: object) -> bool:
139 if isinstance(other, tuple):
140 other = VersionInfo(*other)
141 return tuple.__lt__(self, other)
142
143 def __gt__(self, other: object) -> bool:
144 if isinstance(other, tuple):
145 other = VersionInfo(*other)
146 return tuple.__gt__(self, other)
147
148 def __le__(self, other: object) -> bool:
149 if isinstance(other, tuple):
150 other = VersionInfo(*other)
151 return tuple.__le__(self, other)
152
153 def __ge__(self, other: object) -> bool:
154 if isinstance(other, tuple):
155 other = VersionInfo(*other)
156 return tuple.__ge__(self, other)
157
158
159__version_info__ = VersionInfo(
160 major=0,
161 minor=22,
162 micro=0,
163 releaselevel='candidate', # one of 'alpha', 'beta', 'candidate', 'final'
164 serial=4, # pre-release number (0 for final releases and snapshots)
165 release=False # True for official releases and pre-releases
166 )
167"""Comprehensive version information tuple.
168
169https://docutils.sourceforge.io/docs/dev/policies.html#version-identification
170"""
171
172
173class ApplicationError(Exception): pass
174class DataError(ApplicationError): pass
175
176
177class SettingsSpec:
178
179 """
180 Runtime setting specification base class.
181
182 SettingsSpec subclass objects used by `docutils.frontend.OptionParser`.
183 """
184
185 # TODO: replace settings_specs with a new data structure
186 # Backwards compatiblity:
187 # Drop-in components:
188 # Sphinx supplies settings_spec in the current format in some places
189 # Myst parser provides a settings_spec tuple
190 #
191 # Sphinx reads a settings_spec in order to set a default value
192 # in writers/html.py:59
193 # https://github.com/sphinx-doc/sphinx/blob/4.x/sphinx/writers/html.py
194 # This should be changed (before retiring the old format)
195 # to use `settings_default_overrides` instead.
196 settings_spec: ClassVar[_SettingsSpecTuple] = ()
197 """Runtime settings specification. Override in subclasses.
198
199 Defines runtime settings and associated command-line options, as used by
200 `docutils.frontend.OptionParser`. This is a tuple of:
201
202 - Option group title (string or `None` which implies no group, just a list
203 of single options).
204
205 - Description (string or `None`).
206
207 - A sequence of option tuples. Each consists of:
208
209 - Help text (string)
210
211 - List of option strings (e.g. ``['-Q', '--quux']``).
212
213 - Dictionary of keyword arguments sent to the OptionParser/OptionGroup
214 ``add_option`` method.
215
216 Runtime setting names are derived implicitly from long option names
217 ('--a-setting' becomes ``settings.a_setting``) or explicitly from the
218 'dest' keyword argument.
219
220 Most settings will also have a 'validator' keyword & function. The
221 validator function validates setting values (from configuration files
222 and command-line option arguments) and converts them to appropriate
223 types. For example, the ``docutils.frontend.validate_boolean``
224 function, **required by all boolean settings**, converts true values
225 ('1', 'on', 'yes', and 'true') to 1 and false values ('0', 'off',
226 'no', 'false', and '') to 0. Validators need only be set once per
227 setting. See the `docutils.frontend.validate_*` functions.
228
229 See the optparse docs for more details.
230
231 - More triples of group title, description, options, as many times as
232 needed. Thus, `settings_spec` tuples can be simply concatenated.
233 """
234
235 settings_defaults: ClassVar[dict[str, Any] | None] = None
236 """A dictionary of defaults for settings not in `settings_spec` (internal
237 settings, intended to be inaccessible by command-line and config file).
238 Override in subclasses."""
239
240 settings_default_overrides: ClassVar[dict[str, Any] | None] = None
241 """A dictionary of auxiliary defaults, to override defaults for settings
242 defined in other components' `setting_specs`. Override in subclasses."""
243
244 relative_path_settings: ClassVar[tuple[str, ...]] = ()
245 """Settings containing filesystem paths. Override in subclasses.
246 Settings listed here are to be interpreted relative to the current working
247 directory."""
248
249 config_section: ClassVar[str | None] = None
250 """The name of the config file section specific to this component
251 (lowercase, no brackets). Override in subclasses."""
252
253 config_section_dependencies: ClassVar[tuple[str, ...] | None] = None
254 """A list of names of config file sections that are to be applied before
255 `config_section`, in order (from general to specific). In other words,
256 the settings in `config_section` are to be overlaid on top of the settings
257 from these sections. The "general" section is assumed implicitly.
258 Override in subclasses."""
259
260
261class TransformSpec:
262 """
263 Runtime transform specification base class.
264
265 Provides the interface to register "transforms" and helper functions
266 to resolve references with a `docutils.transforms.Transformer`.
267
268 https://docutils.sourceforge.io/docs/ref/transforms.html
269 """
270
271 def get_transforms(self) -> list[type[Transform]]:
272 """Transforms required by this class. Override in subclasses."""
273 if self.default_transforms != ():
274 import warnings
275 warnings.warn('TransformSpec: the "default_transforms" attribute '
276 'will be removed in Docutils 2.0.\n'
277 'Use get_transforms() method instead.',
278 DeprecationWarning)
279 return list(self.default_transforms)
280 return []
281
282 # Deprecated; for compatibility.
283 default_transforms: ClassVar[tuple[()]] = ()
284
285 unknown_reference_resolvers: Sequence[_UnknownReferenceResolver] = ()
286 """List of hook functions which assist in resolving references.
287
288 Deprecated. Will be removed in Docutils 1.0
289 """
290 # Override in subclasses to implement component-specific resolving of
291 # unknown references.
292 #
293 # Unknown references have a 'refname' attribute which doesn't correspond
294 # to any target in the document. Called when the transforms in
295 # `docutils.transforms.references` are unable to find a correct target.
296 #
297 # The list should contain functions which will try to resolve unknown
298 # references, with the following signature::
299 #
300 # def reference_resolver(node: nodes.Element) -> bool:
301 # '''Returns boolean: true if resolved, false if not.'''
302 #
303 # If the function is able to resolve the reference, it should also remove
304 # the 'refname' attribute and mark the node as resolved::
305 #
306 # del node['refname']
307 # node.resolved = True
308 #
309 # Each function must have a "priority" attribute which will affect the
310 # order the unknown_reference_resolvers are run
311 # cf. ../docs/api/transforms.html#transform-priority-range-categories ::
312 #
313 # reference_resolver.priority = 500
314 #
315 # Examples:
316 # The `MoinMoin ReStructured Text Parser`__ provided a resolver for
317 # "WikiWiki links" in the 1.9 version.
318 #
319 # __ https://github.com/moinwiki/moin-1.9/blob/1.9.11/MoinMoin/parser/
320 # text_rst.py
321
322
323class Component(SettingsSpec, TransformSpec):
324
325 """Base class for Docutils components."""
326
327 component_type: ClassVar[_Components | None] = None
328 """Name of the component type ('reader', 'parser', 'writer').
329 Override in subclasses."""
330
331 supported: ClassVar[tuple[str, ...]] = ()
332 """Name and aliases for this component. Override in subclasses."""
333
334 def supports(self, format: str) -> bool:
335 """
336 Is `format` supported by this component?
337
338 To be used by transforms to ask the dependent component if it supports
339 a certain input context or output format.
340 """
341 return format in self.supported