[Zope-Checkins] CVS: Zope/lib/python/docutils/parsers/rst/directives - __init__.py:1.3 admonitions.py:1.3 body.py:1.3 html.py:1.3 images.py:1.3 misc.py:1.3 parts.py:1.3 references.py:1.3
Andreas Jung
andreas@andreas-jung.com
Thu, 10 Jul 2003 11:50:24 -0400
Update of /cvs-repository/Zope/lib/python/docutils/parsers/rst/directives
In directory cvs.zope.org:/tmp/cvs-serv8556/parsers/rst/directives
Modified Files:
__init__.py admonitions.py body.py html.py images.py misc.py
parts.py references.py
Log Message:
docutils update
=== Zope/lib/python/docutils/parsers/rst/directives/__init__.py 1.2 => 1.3 ===
--- Zope/lib/python/docutils/parsers/rst/directives/__init__.py:1.2 Sat Feb 1 04:26:09 2003
+++ Zope/lib/python/docutils/parsers/rst/directives/__init__.py Thu Jul 10 11:49:44 2003
@@ -60,7 +60,8 @@
- ``options``: A dictionary, mapping known option names to conversion
functions such as `int` or `float`. ``None`` or an empty dict implies no
- options to parse.
+ options to parse. Several directive option conversion functions are defined
+ in this module.
- ``content``: A boolean; true if content is allowed. Client code must handle
the case where content is required but not supplied (an empty content list
@@ -92,9 +93,15 @@
'tip': ('admonitions', 'tip'),
'hint': ('admonitions', 'hint'),
'warning': ('admonitions', 'warning'),
+ 'admonition': ('admonitions', 'admonition'),
+ 'sidebar': ('body', 'sidebar'),
'topic': ('body', 'topic'),
'line-block': ('body', 'line_block'),
'parsed-literal': ('body', 'parsed_literal'),
+ 'rubric': ('body', 'rubric'),
+ 'epigraph': ('body', 'epigraph'),
+ 'highlights': ('body', 'highlights'),
+ 'pull-quote': ('body', 'pull_quote'),
#'questions': ('body', 'question_list'),
'image': ('images', 'image'),
'figure': ('images', 'figure'),
@@ -108,6 +115,8 @@
'raw': ('misc', 'raw'),
'include': ('misc', 'include'),
'replace': ('misc', 'replace'),
+ 'unicode': ('misc', 'unicode_directive'),
+ 'class': ('misc', 'class_directive'),
'restructuredtext-test-directive': ('misc', 'directive_test_function'),}
"""Mapping of directive name to (module name, function name). The directive
name is canonical & must be lowercase. Language-dependent names are defined
@@ -171,9 +180,14 @@
return None, messages
return function, messages
+def register_directive(name, directive):
+ """Register a nonstandard application-defined directive function."""
+ _directives[name] = directive
+
def flag(argument):
"""
Check for a valid flag option (no argument) and return ``None``.
+ (Directive option conversion function.)
Raise ``ValueError`` if an argument is found.
"""
@@ -182,9 +196,10 @@
else:
return None
-def unchanged(argument):
+def unchanged_required(argument):
"""
- Return the argument, unchanged.
+ Return the argument text, unchanged.
+ (Directive option conversion function.)
Raise ``ValueError`` if no argument is found.
"""
@@ -193,9 +208,22 @@
else:
return argument # unchanged!
+def unchanged(argument):
+ """
+ Return the argument text, unchanged.
+ (Directive option conversion function.)
+
+ No argument implies empty string ("").
+ """
+ if argument is None:
+ return u''
+ else:
+ return argument # unchanged!
+
def path(argument):
"""
Return the path argument unwrapped (with newlines removed).
+ (Directive option conversion function.)
Raise ``ValueError`` if no argument is found or if the path contains
internal whitespace.
@@ -212,17 +240,44 @@
def nonnegative_int(argument):
"""
Check for a nonnegative integer argument; raise ``ValueError`` if not.
+ (Directive option conversion function.)
"""
value = int(argument)
if value < 0:
raise ValueError('negative value; must be positive or zero')
return value
+
+def class_option(argument):
+ """
+ Convert the argument into an ID-compatible string and return it.
+ (Directive option conversion function.)
+
+ Raise ``ValueError`` if no argument is found.
+ """
+ if argument is None:
+ raise ValueError('argument required but none supplied')
+ return nodes.make_id(argument)
+
def format_values(values):
return '%s, or "%s"' % (', '.join(['"%s"' % s for s in values[:-1]]),
values[-1])
def choice(argument, values):
+ """
+ Directive option utility function, supplied to enable options whose
+ argument must be a member of a finite set of possible values (must be
+ lower case). A custom conversion function must be written to use it. For
+ example::
+
+ from docutils.parsers.rst import directives
+
+ def yesno(argument):
+ return directives.choice(argument, ('yes', 'no'))
+
+ Raise ``ValueError`` if no argument is found or if the argument's value is
+ not valid (not an entry in the supplied list).
+ """
try:
value = argument.lower().strip()
except AttributeError:
=== Zope/lib/python/docutils/parsers/rst/directives/admonitions.py 1.2 => 1.3 ===
--- Zope/lib/python/docutils/parsers/rst/directives/admonitions.py:1.2 Sat Feb 1 04:26:09 2003
+++ Zope/lib/python/docutils/parsers/rst/directives/admonitions.py Thu Jul 10 11:49:44 2003
@@ -11,64 +11,80 @@
__docformat__ = 'reStructuredText'
-from docutils.parsers.rst import states
+from docutils.parsers.rst import states, directives
from docutils import nodes
-def admonition(node_class, name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- text = '\n'.join(content)
- admonition_node = node_class(text)
- if text:
- state.nested_parse(content, content_offset, admonition_node)
- return [admonition_node]
- else:
+def make_admonition(node_class, name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ if not content:
error = state_machine.reporter.error(
'The "%s" admonition is empty; content required.' % (name),
nodes.literal_block(block_text, block_text), line=lineno)
return [error]
+ text = '\n'.join(content)
+ admonition_node = node_class(text)
+ if arguments:
+ title_text = arguments[0]
+ textnodes, messages = state.inline_text(title_text, lineno)
+ admonition_node += nodes.title(title_text, '', *textnodes)
+ admonition_node += messages
+ if options.has_key('class'):
+ class_value = options['class']
+ else:
+ class_value = 'admonition-' + nodes.make_id(title_text)
+ admonition_node.set_class(class_value)
+ state.nested_parse(content, content_offset, admonition_node)
+ return [admonition_node]
+
+def admonition(*args):
+ return make_admonition(nodes.admonition, *args)
+
+admonition.arguments = (1, 0, 1)
+admonition.options = {'class': directives.class_option}
+admonition.content = 1
def attention(*args):
- return admonition(nodes.attention, *args)
+ return make_admonition(nodes.attention, *args)
attention.content = 1
def caution(*args):
- return admonition(nodes.caution, *args)
+ return make_admonition(nodes.caution, *args)
caution.content = 1
def danger(*args):
- return admonition(nodes.danger, *args)
+ return make_admonition(nodes.danger, *args)
danger.content = 1
def error(*args):
- return admonition(nodes.error, *args)
+ return make_admonition(nodes.error, *args)
error.content = 1
+def hint(*args):
+ return make_admonition(nodes.hint, *args)
+
+hint.content = 1
+
def important(*args):
- return admonition(nodes.important, *args)
+ return make_admonition(nodes.important, *args)
important.content = 1
def note(*args):
- return admonition(nodes.note, *args)
+ return make_admonition(nodes.note, *args)
note.content = 1
def tip(*args):
- return admonition(nodes.tip, *args)
+ return make_admonition(nodes.tip, *args)
tip.content = 1
-def hint(*args):
- return admonition(nodes.hint, *args)
-
-hint.content = 1
-
def warning(*args):
- return admonition(nodes.warning, *args)
+ return make_admonition(nodes.warning, *args)
warning.content = 1
=== Zope/lib/python/docutils/parsers/rst/directives/body.py 1.2 => 1.3 ===
--- Zope/lib/python/docutils/parsers/rst/directives/body.py:1.2 Sat Feb 1 04:26:09 2003
+++ Zope/lib/python/docutils/parsers/rst/directives/body.py Thu Jul 10 11:49:44 2003
@@ -13,13 +13,16 @@
import sys
from docutils import nodes
+from docutils.parsers.rst import directives
def topic(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
+ content_offset, block_text, state, state_machine,
+ node_class=nodes.topic):
if not state_machine.match_titles:
error = state_machine.reporter.error(
- 'Topics may not be nested within topics or body elements.',
+ 'The "%s" directive may not be used within topics, sidebars, '
+ 'or body elements.' % name,
nodes.literal_block(block_text, block_text), line=lineno)
return [error]
if not content:
@@ -30,16 +33,35 @@
return [warning]
title_text = arguments[0]
textnodes, messages = state.inline_text(title_text, lineno)
- title = nodes.title(title_text, '', *textnodes)
+ titles = [nodes.title(title_text, '', *textnodes)]
+ if options.has_key('subtitle'):
+ textnodes, more_messages = state.inline_text(options['subtitle'],
+ lineno)
+ titles.append(nodes.subtitle(options['subtitle'], '', *textnodes))
+ messages.extend(more_messages)
text = '\n'.join(content)
- topic_node = nodes.topic(text, title, *messages)
+ node = node_class(text, *(titles + messages))
+ if options.has_key('class'):
+ node.set_class(options['class'])
if text:
- state.nested_parse(content, content_offset, topic_node)
- return [topic_node]
+ state.nested_parse(content, content_offset, node)
+ return [node]
topic.arguments = (1, 0, 1)
+topic.options = {'class': directives.class_option}
topic.content = 1
+def sidebar(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ return topic(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine,
+ node_class=nodes.sidebar)
+
+sidebar.arguments = (1, 0, 1)
+sidebar.options = {'subtitle': directives.unchanged_required,
+ 'class': directives.class_option}
+sidebar.content = 1
+
def line_block(name, arguments, options, content, lineno,
content_offset, block_text, state, state_machine,
node_class=nodes.line_block):
@@ -50,9 +72,10 @@
return [warning]
text = '\n'.join(content)
text_nodes, messages = state.inline_text(text, lineno)
- node = node_class(text, '', *text_nodes)
+ node = node_class(text, '', *text_nodes, **options)
return [node] + messages
+line_block.options = {'class': directives.class_option}
line_block.content = 1
def parsed_literal(name, arguments, options, content, lineno,
@@ -61,4 +84,39 @@
content_offset, block_text, state, state_machine,
node_class=nodes.literal_block)
+parsed_literal.options = {'class': directives.class_option}
parsed_literal.content = 1
+
+def rubric(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ rubric_text = arguments[0]
+ textnodes, messages = state.inline_text(rubric_text, lineno)
+ rubric = nodes.rubric(rubric_text, '', *textnodes, **options)
+ return [rubric] + messages
+
+rubric.arguments = (1, 0, 1)
+rubric.options = {'class': directives.class_option}
+
+def epigraph(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ block_quote, messages = state.block_quote(content, content_offset)
+ block_quote.set_class('epigraph')
+ return [block_quote] + messages
+
+epigraph.content = 1
+
+def highlights(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ block_quote, messages = state.block_quote(content, content_offset)
+ block_quote.set_class('highlights')
+ return [block_quote] + messages
+
+highlights.content = 1
+
+def pull_quote(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ block_quote, messages = state.block_quote(content, content_offset)
+ block_quote.set_class('pull-quote')
+ return [block_quote] + messages
+
+pull_quote.content = 1
=== Zope/lib/python/docutils/parsers/rst/directives/html.py 1.2 => 1.3 ===
=== Zope/lib/python/docutils/parsers/rst/directives/images.py 1.2 => 1.3 ===
--- Zope/lib/python/docutils/parsers/rst/directives/images.py:1.2 Sat Feb 1 04:26:09 2003
+++ Zope/lib/python/docutils/parsers/rst/directives/images.py Thu Jul 10 11:49:44 2003
@@ -15,6 +15,10 @@
from docutils import nodes, utils
from docutils.parsers.rst import directives
+try:
+ import Image # PIL
+except ImportError:
+ Image = None
align_values = ('top', 'middle', 'bottom', 'left', 'center', 'right')
@@ -38,15 +42,33 @@
'height': directives.nonnegative_int,
'width': directives.nonnegative_int,
'scale': directives.nonnegative_int,
- 'align': align}
+ 'align': align,
+ 'class': directives.class_option}
def figure(name, arguments, options, content, lineno,
content_offset, block_text, state, state_machine):
+ figwidth = options.setdefault('figwidth')
+ figclass = options.setdefault('figclass')
+ del options['figwidth']
+ del options['figclass']
(image_node,) = image(name, arguments, options, content, lineno,
content_offset, block_text, state, state_machine)
if isinstance(image_node, nodes.system_message):
return [image_node]
figure_node = nodes.figure('', image_node)
+ if figwidth == 'image':
+ if Image:
+ # PIL doesn't like Unicode paths:
+ try:
+ i = Image.open(str(image_node['uri']))
+ except (IOError, UnicodeError):
+ pass
+ else:
+ figure_node['width'] = i.size[0]
+ elif figwidth is not None:
+ figure_node['width'] = figwidth
+ if figclass:
+ figure_node.set_class(figclass)
if content:
node = nodes.Element() # anonymous container for parsing
state.nested_parse(content, content_offset, node)
@@ -65,6 +87,14 @@
figure_node += nodes.legend('', *node[1:])
return [figure_node]
+def figwidth_value(argument):
+ if argument.lower() == 'image':
+ return 'image'
+ else:
+ return directives.nonnegative_int(argument)
+
figure.arguments = (1, 0, 1)
-figure.options = image.options
+figure.options = {'figwidth': figwidth_value,
+ 'figclass': directives.class_option}
+figure.options.update(image.options)
figure.content = 1
=== Zope/lib/python/docutils/parsers/rst/directives/misc.py 1.2 => 1.3 ===
--- Zope/lib/python/docutils/parsers/rst/directives/misc.py:1.2 Sat Feb 1 04:26:09 2003
+++ Zope/lib/python/docutils/parsers/rst/directives/misc.py Thu Jul 10 11:49:44 2003
@@ -10,9 +10,11 @@
import sys
import os.path
+import re
from urllib2 import urlopen, URLError
from docutils import io, nodes, statemachine, utils
from docutils.parsers.rst import directives, states
+from docutils.transforms import misc
def include(name, arguments, options, content, lineno,
@@ -31,10 +33,12 @@
path = utils.relative_path(None, path)
try:
include_file = io.FileInput(
- source_path=path, encoding=state.document.settings.input_encoding)
+ source_path=path, encoding=state.document.settings.input_encoding,
+ handle_io_errors=None)
except IOError, error:
severe = state_machine.reporter.severe(
- 'Problems with "%s" directive path:\n%s.' % (name, error),
+ 'Problems with "%s" directive path:\n%s: %s.'
+ % (name, error.__class__.__name__, error),
nodes.literal_block(block_text, block_text), line=lineno)
return [severe]
include_text = include_file.read()
@@ -151,6 +155,65 @@
replace.content = 1
+def unicode_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ r"""
+ Convert Unicode character codes (numbers) to characters. Codes may be
+ decimal numbers, hexadecimal numbers (prefixed by ``0x``, ``x``, ``\x``,
+ ``U+``, ``u``, or ``\u``; e.g. ``U+262E``), or XML-style numeric character
+ entities (e.g. ``☮``). Text following ".." is a comment and is
+ ignored. Spaces are ignored, and any other text remains as-is.
+ """
+ if not isinstance(state, states.SubstitutionDef):
+ error = state_machine.reporter.error(
+ 'Invalid context: the "%s" directive can only be used within a '
+ 'substitution definition.' % (name),
+ nodes.literal_block(block_text, block_text), line=lineno)
+ return [error]
+ codes = arguments[0].split('.. ')[0].split()
+ element = nodes.Element()
+ for code in codes:
+ try:
+ if code.isdigit():
+ element += nodes.Text(unichr(int(code)))
+ else:
+ match = unicode_pattern.match(code)
+ if match:
+ value = match.group(1) or match.group(2)
+ element += nodes.Text(unichr(int(value, 16)))
+ else:
+ element += nodes.Text(code)
+ except ValueError, err:
+ error = state_machine.reporter.error(
+ 'Invalid character code: %s\n%s' % (code, err),
+ nodes.literal_block(block_text, block_text), line=lineno)
+ return [error]
+ return element.children
+
+unicode_directive.arguments = (1, 0, 1)
+unicode_pattern = re.compile(
+ r'(?:0x|x|\x00x|U\+?|\x00u)([0-9a-f]+)$|&#x([0-9a-f]+);$', re.IGNORECASE)
+
+def class_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ """"""
+ class_value = nodes.make_id(arguments[0])
+ if class_value:
+ pending = nodes.pending(misc.ClassAttribute,
+ {'class': class_value, 'directive': name},
+ block_text)
+ state_machine.document.note_pending(pending)
+ return [pending]
+ else:
+ error = state_machine.reporter.error(
+ 'Invalid class attribute value for "%s" directive: %s'
+ % (name, arguments[0]),
+ nodes.literal_block(block_text, block_text), line=lineno)
+ return [error]
+
+class_directive.arguments = (1, 0, 0)
+class_directive.content = 1
+
def directive_test_function(name, arguments, options, content, lineno,
content_offset, block_text, state, state_machine):
if content:
@@ -166,5 +229,5 @@
return [info]
directive_test_function.arguments = (0, 1, 1)
-directive_test_function.options = {'option': directives.unchanged}
+directive_test_function.options = {'option': directives.unchanged_required}
directive_test_function.content = 1
=== Zope/lib/python/docutils/parsers/rst/directives/parts.py 1.2 => 1.3 ===
--- Zope/lib/python/docutils/parsers/rst/directives/parts.py:1.2 Sat Feb 1 04:26:09 2003
+++ Zope/lib/python/docutils/parsers/rst/directives/parts.py Thu Jul 10 11:49:44 2003
@@ -42,7 +42,8 @@
contents.arguments = (0, 1, 1)
contents.options = {'depth': directives.nonnegative_int,
'local': directives.flag,
- 'backlinks': backlinks}
+ 'backlinks': backlinks,
+ 'class': directives.class_option}
def sectnum(name, arguments, options, content, lineno,
content_offset, block_text, state, state_machine):
=== Zope/lib/python/docutils/parsers/rst/directives/references.py 1.2 => 1.3 ===