comparison env/lib/python3.9/site-packages/docutils/parsers/rst/directives/images.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # $Id: images.py 8370 2019-08-27 12:10:39Z milde $
2 # Author: David Goodger <goodger@python.org>
3 # Copyright: This module has been placed in the public domain.
4
5 """
6 Directives for figures and simple images.
7 """
8
9 __docformat__ = 'reStructuredText'
10
11
12 import sys
13
14 from docutils import nodes, utils
15 from docutils.parsers.rst import Directive
16 from docutils.parsers.rst import directives, states
17 from docutils.nodes import fully_normalize_name, whitespace_normalize_name
18 from docutils.parsers.rst.roles import set_classes
19
20 try: # check for the Python Imaging Library
21 import PIL.Image
22 except ImportError:
23 try: # sometimes PIL modules are put in PYTHONPATH's root
24 import Image
25 class PIL(object): pass # dummy wrapper
26 PIL.Image = Image
27 except ImportError:
28 PIL = None
29
30 if sys.version_info >= (3, 0):
31 from urllib.request import url2pathname
32 else:
33 from urllib import url2pathname
34
35
36 class Image(Directive):
37
38 align_h_values = ('left', 'center', 'right')
39 align_v_values = ('top', 'middle', 'bottom')
40 align_values = align_v_values + align_h_values
41
42 def align(argument):
43 # This is not callable as self.align. We cannot make it a
44 # staticmethod because we're saving an unbound method in
45 # option_spec below.
46 return directives.choice(argument, Image.align_values)
47
48 required_arguments = 1
49 optional_arguments = 0
50 final_argument_whitespace = True
51 option_spec = {'alt': directives.unchanged,
52 'height': directives.length_or_unitless,
53 'width': directives.length_or_percentage_or_unitless,
54 'scale': directives.percentage,
55 'align': align,
56 'name': directives.unchanged,
57 'target': directives.unchanged_required,
58 'class': directives.class_option}
59
60 def run(self):
61 if 'align' in self.options:
62 if isinstance(self.state, states.SubstitutionDef):
63 # Check for align_v_values.
64 if self.options['align'] not in self.align_v_values:
65 raise self.error(
66 'Error in "%s" directive: "%s" is not a valid value '
67 'for the "align" option within a substitution '
68 'definition. Valid values for "align" are: "%s".'
69 % (self.name, self.options['align'],
70 '", "'.join(self.align_v_values)))
71 elif self.options['align'] not in self.align_h_values:
72 raise self.error(
73 'Error in "%s" directive: "%s" is not a valid value for '
74 'the "align" option. Valid values for "align" are: "%s".'
75 % (self.name, self.options['align'],
76 '", "'.join(self.align_h_values)))
77 messages = []
78 reference = directives.uri(self.arguments[0])
79 self.options['uri'] = reference
80 reference_node = None
81 if 'target' in self.options:
82 block = states.escape2null(
83 self.options['target']).splitlines()
84 block = [line for line in block]
85 target_type, data = self.state.parse_target(
86 block, self.block_text, self.lineno)
87 if target_type == 'refuri':
88 reference_node = nodes.reference(refuri=data)
89 elif target_type == 'refname':
90 reference_node = nodes.reference(
91 refname=fully_normalize_name(data),
92 name=whitespace_normalize_name(data))
93 reference_node.indirect_reference_name = data
94 self.state.document.note_refname(reference_node)
95 else: # malformed target
96 messages.append(data) # data is a system message
97 del self.options['target']
98 set_classes(self.options)
99 image_node = nodes.image(self.block_text, **self.options)
100 self.add_name(image_node)
101 if reference_node:
102 reference_node += image_node
103 return messages + [reference_node]
104 else:
105 return messages + [image_node]
106
107
108 class Figure(Image):
109
110 def align(argument):
111 return directives.choice(argument, Figure.align_h_values)
112
113 def figwidth_value(argument):
114 if argument.lower() == 'image':
115 return 'image'
116 else:
117 return directives.length_or_percentage_or_unitless(argument, 'px')
118
119 option_spec = Image.option_spec.copy()
120 option_spec['figwidth'] = figwidth_value
121 option_spec['figclass'] = directives.class_option
122 option_spec['align'] = align
123 has_content = True
124
125 def run(self):
126 figwidth = self.options.pop('figwidth', None)
127 figclasses = self.options.pop('figclass', None)
128 align = self.options.pop('align', None)
129 (image_node,) = Image.run(self)
130 if isinstance(image_node, nodes.system_message):
131 return [image_node]
132 figure_node = nodes.figure('', image_node)
133 if figwidth == 'image':
134 if PIL and self.state.document.settings.file_insertion_enabled:
135 imagepath = url2pathname(image_node['uri'])
136 try:
137 img = PIL.Image.open(
138 imagepath.encode(sys.getfilesystemencoding()))
139 except (IOError, UnicodeEncodeError):
140 pass # TODO: warn?
141 else:
142 self.state.document.settings.record_dependencies.add(
143 imagepath.replace('\\', '/'))
144 figure_node['width'] = '%dpx' % img.size[0]
145 del img
146 elif figwidth is not None:
147 figure_node['width'] = figwidth
148 if figclasses:
149 figure_node['classes'] += figclasses
150 if align:
151 figure_node['align'] = align
152 if self.content:
153 node = nodes.Element() # anonymous container for parsing
154 self.state.nested_parse(self.content, self.content_offset, node)
155 first_node = node[0]
156 if isinstance(first_node, nodes.paragraph):
157 caption = nodes.caption(first_node.rawsource, '',
158 *first_node.children)
159 caption.source = first_node.source
160 caption.line = first_node.line
161 figure_node += caption
162 elif not (isinstance(first_node, nodes.comment)
163 and len(first_node) == 0):
164 error = self.state_machine.reporter.error(
165 'Figure caption must be a paragraph or empty comment.',
166 nodes.literal_block(self.block_text, self.block_text),
167 line=self.lineno)
168 return [figure_node, error]
169 if len(node) > 1:
170 figure_node += nodes.legend('', *node[1:])
171 return [figure_node]