Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/docutils/transforms/universal.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author | shellac |
---|---|
date | Mon, 01 Jun 2020 08:59:25 -0400 |
parents | 79f47841a781 |
children |
comparison
equal
deleted
inserted
replaced
4:79f47841a781 | 5:9b1c78e6ba9c |
---|---|
1 # $Id: universal.py 8393 2019-09-18 10:13:00Z milde $ | |
2 # -*- coding: utf-8 -*- | |
3 # Authors: David Goodger <goodger@python.org>; Ueli Schlaepfer; Günter Milde | |
4 # Maintainer: docutils-develop@lists.sourceforge.net | |
5 # Copyright: This module has been placed in the public domain. | |
6 | |
7 """ | |
8 Transforms needed by most or all documents: | |
9 | |
10 - `Decorations`: Generate a document's header & footer. | |
11 - `Messages`: Placement of system messages stored in | |
12 `nodes.document.transform_messages`. | |
13 - `TestMessages`: Like `Messages`, used on test runs. | |
14 - `FinalReferences`: Resolve remaining references. | |
15 """ | |
16 | |
17 __docformat__ = 'reStructuredText' | |
18 | |
19 import re | |
20 import sys | |
21 import time | |
22 from docutils import nodes, utils | |
23 from docutils.transforms import TransformError, Transform | |
24 from docutils.utils import smartquotes | |
25 | |
26 | |
27 if sys.version_info >= (3, 0): | |
28 unicode = str # noqa | |
29 | |
30 | |
31 class Decorations(Transform): | |
32 | |
33 """ | |
34 Populate a document's decoration element (header, footer). | |
35 """ | |
36 | |
37 default_priority = 820 | |
38 | |
39 def apply(self): | |
40 header_nodes = self.generate_header() | |
41 if header_nodes: | |
42 decoration = self.document.get_decoration() | |
43 header = decoration.get_header() | |
44 header.extend(header_nodes) | |
45 footer_nodes = self.generate_footer() | |
46 if footer_nodes: | |
47 decoration = self.document.get_decoration() | |
48 footer = decoration.get_footer() | |
49 footer.extend(footer_nodes) | |
50 | |
51 def generate_header(self): | |
52 return None | |
53 | |
54 def generate_footer(self): | |
55 # @@@ Text is hard-coded for now. | |
56 # Should be made dynamic (language-dependent). | |
57 # @@@ Use timestamp from the `SOURCE_DATE_EPOCH`_ environment variable | |
58 # for the datestamp? | |
59 # See https://sourceforge.net/p/docutils/patches/132/ | |
60 # and https://reproducible-builds.org/specs/source-date-epoch/ | |
61 settings = self.document.settings | |
62 if settings.generator or settings.datestamp or settings.source_link \ | |
63 or settings.source_url: | |
64 text = [] | |
65 if settings.source_link and settings._source \ | |
66 or settings.source_url: | |
67 if settings.source_url: | |
68 source = settings.source_url | |
69 else: | |
70 source = utils.relative_path(settings._destination, | |
71 settings._source) | |
72 text.extend([ | |
73 nodes.reference('', 'View document source', | |
74 refuri=source), | |
75 nodes.Text('.\n')]) | |
76 if settings.datestamp: | |
77 datestamp = time.strftime(settings.datestamp, time.gmtime()) | |
78 text.append(nodes.Text('Generated on: ' + datestamp + '.\n')) | |
79 if settings.generator: | |
80 text.extend([ | |
81 nodes.Text('Generated by '), | |
82 nodes.reference('', 'Docutils', refuri= | |
83 'http://docutils.sourceforge.net/'), | |
84 nodes.Text(' from '), | |
85 nodes.reference('', 'reStructuredText', refuri='http://' | |
86 'docutils.sourceforge.net/rst.html'), | |
87 nodes.Text(' source.\n')]) | |
88 return [nodes.paragraph('', '', *text)] | |
89 else: | |
90 return None | |
91 | |
92 | |
93 class ExposeInternals(Transform): | |
94 | |
95 """ | |
96 Expose internal attributes if ``expose_internals`` setting is set. | |
97 """ | |
98 | |
99 default_priority = 840 | |
100 | |
101 def not_Text(self, node): | |
102 return not isinstance(node, nodes.Text) | |
103 | |
104 def apply(self): | |
105 if self.document.settings.expose_internals: | |
106 for node in self.document.traverse(self.not_Text): | |
107 for att in self.document.settings.expose_internals: | |
108 value = getattr(node, att, None) | |
109 if value is not None: | |
110 node['internal:' + att] = value | |
111 | |
112 | |
113 class Messages(Transform): | |
114 | |
115 """ | |
116 Place any system messages generated after parsing into a dedicated section | |
117 of the document. | |
118 """ | |
119 | |
120 default_priority = 860 | |
121 | |
122 def apply(self): | |
123 unfiltered = self.document.transform_messages | |
124 threshold = self.document.reporter.report_level | |
125 messages = [] | |
126 for msg in unfiltered: | |
127 if msg['level'] >= threshold and not msg.parent: | |
128 messages.append(msg) | |
129 if messages: | |
130 section = nodes.section(classes=['system-messages']) | |
131 # @@@ get this from the language module? | |
132 section += nodes.title('', 'Docutils System Messages') | |
133 section += messages | |
134 self.document.transform_messages[:] = [] | |
135 self.document += section | |
136 | |
137 | |
138 class FilterMessages(Transform): | |
139 | |
140 """ | |
141 Remove system messages below verbosity threshold. | |
142 """ | |
143 | |
144 default_priority = 870 | |
145 | |
146 def apply(self): | |
147 for node in tuple(self.document.traverse(nodes.system_message)): | |
148 if node['level'] < self.document.reporter.report_level: | |
149 node.parent.remove(node) | |
150 | |
151 | |
152 class TestMessages(Transform): | |
153 | |
154 """ | |
155 Append all post-parse system messages to the end of the document. | |
156 | |
157 Used for testing purposes. | |
158 """ | |
159 | |
160 default_priority = 880 | |
161 | |
162 def apply(self): | |
163 for msg in self.document.transform_messages: | |
164 if not msg.parent: | |
165 self.document += msg | |
166 | |
167 | |
168 class StripComments(Transform): | |
169 | |
170 """ | |
171 Remove comment elements from the document tree (only if the | |
172 ``strip_comments`` setting is enabled). | |
173 """ | |
174 | |
175 default_priority = 740 | |
176 | |
177 def apply(self): | |
178 if self.document.settings.strip_comments: | |
179 for node in tuple(self.document.traverse(nodes.comment)): | |
180 node.parent.remove(node) | |
181 | |
182 | |
183 class StripClassesAndElements(Transform): | |
184 | |
185 """ | |
186 Remove from the document tree all elements with classes in | |
187 `self.document.settings.strip_elements_with_classes` and all "classes" | |
188 attribute values in `self.document.settings.strip_classes`. | |
189 """ | |
190 | |
191 default_priority = 420 | |
192 | |
193 def apply(self): | |
194 if self.document.settings.strip_elements_with_classes: | |
195 self.strip_elements = set( | |
196 self.document.settings.strip_elements_with_classes) | |
197 # Iterate over a tuple as removing the current node | |
198 # corrupts the iterator returned by `traverse`: | |
199 for node in tuple(self.document.traverse(self.check_classes)): | |
200 node.parent.remove(node) | |
201 | |
202 if not self.document.settings.strip_classes: | |
203 return | |
204 strip_classes = self.document.settings.strip_classes | |
205 for node in self.document.traverse(nodes.Element): | |
206 for class_value in strip_classes: | |
207 try: | |
208 node['classes'].remove(class_value) | |
209 except ValueError: | |
210 pass | |
211 | |
212 def check_classes(self, node): | |
213 if not isinstance(node, nodes.Element): | |
214 return False | |
215 for class_value in node['classes'][:]: | |
216 if class_value in self.strip_elements: | |
217 return True | |
218 return False | |
219 | |
220 | |
221 class SmartQuotes(Transform): | |
222 | |
223 """ | |
224 Replace ASCII quotation marks with typographic form. | |
225 | |
226 Also replace multiple dashes with em-dash/en-dash characters. | |
227 """ | |
228 | |
229 default_priority = 850 | |
230 | |
231 nodes_to_skip = (nodes.FixedTextElement, nodes.Special) | |
232 """Do not apply "smartquotes" to instances of these block-level nodes.""" | |
233 | |
234 literal_nodes = (nodes.FixedTextElement, nodes.Special, | |
235 nodes.image, nodes.literal, nodes.math, | |
236 nodes.raw, nodes.problematic) | |
237 """Do apply smartquotes to instances of these inline nodes.""" | |
238 | |
239 smartquotes_action = 'qDe' | |
240 """Setting to select smartquote transformations. | |
241 | |
242 The default 'qDe' educates normal quote characters: (", '), | |
243 em- and en-dashes (---, --) and ellipses (...). | |
244 """ | |
245 | |
246 def __init__(self, document, startnode): | |
247 Transform.__init__(self, document, startnode=startnode) | |
248 self.unsupported_languages = set() | |
249 | |
250 def get_tokens(self, txtnodes): | |
251 # A generator that yields ``(texttype, nodetext)`` tuples for a list | |
252 # of "Text" nodes (interface to ``smartquotes.educate_tokens()``). | |
253 for node in txtnodes: | |
254 if (isinstance(node.parent, self.literal_nodes) | |
255 or isinstance(node.parent.parent, self.literal_nodes)): | |
256 yield ('literal', unicode(node)) | |
257 else: | |
258 # SmartQuotes uses backslash escapes instead of null-escapes | |
259 txt = re.sub('(?<=\x00)([-\\\'".`])', r'\\\1', unicode(node)) | |
260 yield ('plain', txt) | |
261 | |
262 def apply(self): | |
263 smart_quotes = self.document.settings.smart_quotes | |
264 if not smart_quotes: | |
265 return | |
266 try: | |
267 alternative = smart_quotes.startswith('alt') | |
268 except AttributeError: | |
269 alternative = False | |
270 | |
271 document_language = self.document.settings.language_code | |
272 lc_smartquotes = self.document.settings.smartquotes_locales | |
273 if lc_smartquotes: | |
274 smartquotes.smartchars.quotes.update(dict(lc_smartquotes)) | |
275 | |
276 # "Educate" quotes in normal text. Handle each block of text | |
277 # (TextElement node) as a unit to keep context around inline nodes: | |
278 for node in self.document.traverse(nodes.TextElement): | |
279 # skip preformatted text blocks and special elements: | |
280 if isinstance(node, self.nodes_to_skip): | |
281 continue | |
282 # nested TextElements are not "block-level" elements: | |
283 if isinstance(node.parent, nodes.TextElement): | |
284 continue | |
285 | |
286 # list of text nodes in the "text block": | |
287 txtnodes = [txtnode for txtnode in node.traverse(nodes.Text) | |
288 if not isinstance(txtnode.parent, | |
289 nodes.option_string)] | |
290 | |
291 # language: use typographical quotes for language "lang" | |
292 lang = node.get_language_code(document_language) | |
293 # use alternative form if `smart-quotes` setting starts with "alt": | |
294 if alternative: | |
295 if '-x-altquot' in lang: | |
296 lang = lang.replace('-x-altquot', '') | |
297 else: | |
298 lang += '-x-altquot' | |
299 # drop unsupported subtags: | |
300 for tag in utils.normalize_language_tag(lang): | |
301 if tag in smartquotes.smartchars.quotes: | |
302 lang = tag | |
303 break | |
304 else: # language not supported: (keep ASCII quotes) | |
305 if lang not in self.unsupported_languages: | |
306 self.document.reporter.warning('No smart quotes ' | |
307 'defined for language "%s".'%lang, base_node=node) | |
308 self.unsupported_languages.add(lang) | |
309 lang = '' | |
310 | |
311 # Iterator educating quotes in plain text: | |
312 # (see "utils/smartquotes.py" for the attribute setting) | |
313 teacher = smartquotes.educate_tokens(self.get_tokens(txtnodes), | |
314 attr=self.smartquotes_action, language=lang) | |
315 | |
316 for txtnode, newtext in zip(txtnodes, teacher): | |
317 txtnode.parent.replace(txtnode, nodes.Text(newtext, | |
318 rawsource=txtnode.rawsource)) | |
319 | |
320 self.unsupported_languages = set() # reset |