__init__.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. # $Id: __init__.py 9037 2022-03-05 23:31:10Z milde $
  2. # Author: David Goodger <goodger@python.org>
  3. # Copyright: This module has been placed in the public domain.
  4. """
  5. This package contains Docutils Writer modules.
  6. """
  7. __docformat__ = 'reStructuredText'
  8. from importlib import import_module
  9. import docutils
  10. from docutils import languages, Component
  11. from docutils.transforms import universal
  12. class Writer(Component):
  13. """
  14. Abstract base class for docutils Writers.
  15. Each writer module or package must export a subclass also called 'Writer'.
  16. Each writer must support all standard node types listed in
  17. `docutils.nodes.node_class_names`.
  18. The `write()` method is the main entry point.
  19. """
  20. component_type = 'writer'
  21. config_section = 'writers'
  22. def get_transforms(self):
  23. return Component.get_transforms(self) + [
  24. universal.Messages,
  25. universal.FilterMessages,
  26. universal.StripClassesAndElements]
  27. document = None
  28. """The document to write (Docutils doctree); set by `write`."""
  29. output = None
  30. """Final translated form of `document` (Unicode string for text, binary
  31. string for other forms); set by `translate`."""
  32. language = None
  33. """Language module for the document; set by `write`."""
  34. destination = None
  35. """`docutils.io` Output object; where to write the document.
  36. Set by `write`."""
  37. def __init__(self):
  38. # Used by HTML and LaTeX writer for output fragments:
  39. self.parts = {}
  40. """Mapping of document part names to fragments of `self.output`.
  41. Values are Unicode strings; encoding is up to the client. The 'whole'
  42. key should contain the entire document output.
  43. """
  44. def write(self, document, destination):
  45. """
  46. Process a document into its final form.
  47. Translate `document` (a Docutils document tree) into the Writer's
  48. native format, and write it out to its `destination` (a
  49. `docutils.io.Output` subclass object).
  50. Normally not overridden or extended in subclasses.
  51. """
  52. self.document = document
  53. self.language = languages.get_language(
  54. document.settings.language_code,
  55. document.reporter)
  56. self.destination = destination
  57. self.translate()
  58. return self.destination.write(self.output)
  59. def translate(self):
  60. """
  61. Do final translation of `self.document` into `self.output`. Called
  62. from `write`. Override in subclasses.
  63. Usually done with a `docutils.nodes.NodeVisitor` subclass, in
  64. combination with a call to `docutils.nodes.Node.walk()` or
  65. `docutils.nodes.Node.walkabout()`. The ``NodeVisitor`` subclass must
  66. support all standard elements (listed in
  67. `docutils.nodes.node_class_names`) and possibly non-standard elements
  68. used by the current Reader as well.
  69. """
  70. raise NotImplementedError('subclass must override this method')
  71. def assemble_parts(self):
  72. """Assemble the `self.parts` dictionary. Extend in subclasses."""
  73. self.parts['whole'] = self.output
  74. self.parts['encoding'] = self.document.settings.output_encoding
  75. self.parts['version'] = docutils.__version__
  76. class UnfilteredWriter(Writer):
  77. """
  78. A writer that passes the document tree on unchanged (e.g. a
  79. serializer.)
  80. Documents written by UnfilteredWriters are typically reused at a
  81. later date using a subclass of `readers.ReReader`.
  82. """
  83. def get_transforms(self):
  84. # Do not add any transforms. When the document is reused
  85. # later, the then-used writer will add the appropriate
  86. # transforms.
  87. return Component.get_transforms(self)
  88. _writer_aliases = {
  89. 'html': 'html4css1', # may change to html5 some day
  90. 'html4': 'html4css1',
  91. 'xhtml10': 'html4css1',
  92. 'html5': 'html5_polyglot',
  93. 'xhtml': 'html5_polyglot',
  94. 's5': 's5_html',
  95. 'latex': 'latex2e',
  96. 'xelatex': 'xetex',
  97. 'luatex': 'xetex',
  98. 'lualatex': 'xetex',
  99. 'odf': 'odf_odt',
  100. 'odt': 'odf_odt',
  101. 'ooffice': 'odf_odt',
  102. 'openoffice': 'odf_odt',
  103. 'libreoffice': 'odf_odt',
  104. 'pprint': 'pseudoxml',
  105. 'pformat': 'pseudoxml',
  106. 'pdf': 'rlpdf',
  107. 'xml': 'docutils_xml'}
  108. def get_writer_class(writer_name):
  109. """Return the Writer class from the `writer_name` module."""
  110. name = writer_name.lower()
  111. name = _writer_aliases.get(name, name)
  112. try:
  113. module = import_module('docutils.writers.'+name)
  114. except ImportError:
  115. try:
  116. module = import_module(name)
  117. except ImportError as err:
  118. raise ImportError(f'Writer "{writer_name}" not found. {err}')
  119. return module.Writer