buildframework/helium/external/python/lib/2.5/docutils-0.5-py2.5.egg/docutils/parsers/rst/roles.py
changeset 179 d8ac696cc51f
parent 1 be27ed110b50
child 180 e02a83d4c571
child 592 3215c239276a
equal deleted inserted replaced
1:be27ed110b50 179:d8ac696cc51f
     1 # $Id: roles.py 4564 2006-05-21 20:44:42Z wiemann $
       
     2 # Author: Edward Loper <edloper@gradient.cis.upenn.edu>
       
     3 # Copyright: This module has been placed in the public domain.
       
     4 
       
     5 """
       
     6 This module defines standard interpreted text role functions, a registry for
       
     7 interpreted text roles, and an API for adding to and retrieving from the
       
     8 registry.
       
     9 
       
    10 The interface for interpreted role functions is as follows::
       
    11 
       
    12     def role_fn(name, rawtext, text, lineno, inliner,
       
    13                 options={}, content=[]):
       
    14         code...
       
    15 
       
    16     # Set function attributes for customization:
       
    17     role_fn.options = ...
       
    18     role_fn.content = ...
       
    19 
       
    20 Parameters:
       
    21 
       
    22 - ``name`` is the local name of the interpreted text role, the role name
       
    23   actually used in the document.
       
    24 
       
    25 - ``rawtext`` is a string containing the entire interpreted text construct.
       
    26   Return it as a ``problematic`` node linked to a system message if there is a
       
    27   problem.
       
    28 
       
    29 - ``text`` is the interpreted text content, with backslash escapes converted
       
    30   to nulls (``\x00``).
       
    31 
       
    32 - ``lineno`` is the line number where the interpreted text beings.
       
    33 
       
    34 - ``inliner`` is the Inliner object that called the role function.
       
    35   It defines the following useful attributes: ``reporter``,
       
    36   ``problematic``, ``memo``, ``parent``, ``document``.
       
    37 
       
    38 - ``options``: A dictionary of directive options for customization, to be
       
    39   interpreted by the role function.  Used for additional attributes for the
       
    40   generated elements and other functionality.
       
    41 
       
    42 - ``content``: A list of strings, the directive content for customization
       
    43   ("role" directive).  To be interpreted by the role function.
       
    44 
       
    45 Function attributes for customization, interpreted by the "role" directive:
       
    46 
       
    47 - ``options``: A dictionary, mapping known option names to conversion
       
    48   functions such as `int` or `float`.  ``None`` or an empty dict implies no
       
    49   options to parse.  Several directive option conversion functions are defined
       
    50   in the `directives` module.
       
    51 
       
    52   All role functions implicitly support the "class" option, unless disabled
       
    53   with an explicit ``{'class': None}``.
       
    54 
       
    55 - ``content``: A boolean; true if content is allowed.  Client code must handle
       
    56   the case where content is required but not supplied (an empty content list
       
    57   will be supplied).
       
    58 
       
    59 Note that unlike directives, the "arguments" function attribute is not
       
    60 supported for role customization.  Directive arguments are handled by the
       
    61 "role" directive itself.
       
    62 
       
    63 Interpreted role functions return a tuple of two values:
       
    64 
       
    65 - A list of nodes which will be inserted into the document tree at the
       
    66   point where the interpreted role was encountered (can be an empty
       
    67   list).
       
    68 
       
    69 - A list of system messages, which will be inserted into the document tree
       
    70   immediately after the end of the current inline block (can also be empty).
       
    71 """
       
    72 
       
    73 __docformat__ = 'reStructuredText'
       
    74 
       
    75 from docutils import nodes, utils
       
    76 from docutils.parsers.rst import directives
       
    77 from docutils.parsers.rst.languages import en as _fallback_language_module
       
    78 
       
    79 DEFAULT_INTERPRETED_ROLE = 'title-reference'
       
    80 """
       
    81 The canonical name of the default interpreted role.  This role is used
       
    82 when no role is specified for a piece of interpreted text.
       
    83 """
       
    84 
       
    85 _role_registry = {}
       
    86 """Mapping of canonical role names to role functions.  Language-dependent role
       
    87 names are defined in the ``language`` subpackage."""
       
    88 
       
    89 _roles = {}
       
    90 """Mapping of local or language-dependent interpreted text role names to role
       
    91 functions."""
       
    92 
       
    93 def role(role_name, language_module, lineno, reporter):
       
    94     """
       
    95     Locate and return a role function from its language-dependent name, along
       
    96     with a list of system messages.  If the role is not found in the current
       
    97     language, check English.  Return a 2-tuple: role function (``None`` if the
       
    98     named role cannot be found) and a list of system messages.
       
    99     """
       
   100     normname = role_name.lower()
       
   101     messages = []
       
   102     msg_text = []
       
   103 
       
   104     if _roles.has_key(normname):
       
   105         return _roles[normname], messages
       
   106 
       
   107     if role_name:
       
   108         canonicalname = None
       
   109         try:
       
   110             canonicalname = language_module.roles[normname]
       
   111         except AttributeError, error:
       
   112             msg_text.append('Problem retrieving role entry from language '
       
   113                             'module %r: %s.' % (language_module, error))
       
   114         except KeyError:
       
   115             msg_text.append('No role entry for "%s" in module "%s".'
       
   116                             % (role_name, language_module.__name__))
       
   117     else:
       
   118         canonicalname = DEFAULT_INTERPRETED_ROLE
       
   119 
       
   120     # If we didn't find it, try English as a fallback.
       
   121     if not canonicalname:
       
   122         try:
       
   123             canonicalname = _fallback_language_module.roles[normname]
       
   124             msg_text.append('Using English fallback for role "%s".'
       
   125                             % role_name)
       
   126         except KeyError:
       
   127             msg_text.append('Trying "%s" as canonical role name.'
       
   128                             % role_name)
       
   129             # The canonical name should be an English name, but just in case:
       
   130             canonicalname = normname
       
   131 
       
   132     # Collect any messages that we generated.
       
   133     if msg_text:
       
   134         message = reporter.info('\n'.join(msg_text), line=lineno)
       
   135         messages.append(message)
       
   136 
       
   137     # Look the role up in the registry, and return it.
       
   138     if _role_registry.has_key(canonicalname):
       
   139         role_fn = _role_registry[canonicalname]
       
   140         register_local_role(normname, role_fn)
       
   141         return role_fn, messages
       
   142     else:
       
   143         return None, messages # Error message will be generated by caller.
       
   144 
       
   145 def register_canonical_role(name, role_fn):
       
   146     """
       
   147     Register an interpreted text role by its canonical name.
       
   148 
       
   149     :Parameters:
       
   150       - `name`: The canonical name of the interpreted role.
       
   151       - `role_fn`: The role function.  See the module docstring.
       
   152     """
       
   153     set_implicit_options(role_fn)
       
   154     _role_registry[name] = role_fn
       
   155 
       
   156 def register_local_role(name, role_fn):
       
   157     """
       
   158     Register an interpreted text role by its local or language-dependent name.
       
   159 
       
   160     :Parameters:
       
   161       - `name`: The local or language-dependent name of the interpreted role.
       
   162       - `role_fn`: The role function.  See the module docstring.
       
   163     """
       
   164     set_implicit_options(role_fn)
       
   165     _roles[name] = role_fn
       
   166 
       
   167 def set_implicit_options(role_fn):
       
   168     """
       
   169     Add customization options to role functions, unless explicitly set or
       
   170     disabled.
       
   171     """
       
   172     if not hasattr(role_fn, 'options') or role_fn.options is None:
       
   173         role_fn.options = {'class': directives.class_option}
       
   174     elif not role_fn.options.has_key('class'):
       
   175         role_fn.options['class'] = directives.class_option
       
   176 
       
   177 def register_generic_role(canonical_name, node_class):
       
   178     """For roles which simply wrap a given `node_class` around the text."""
       
   179     role = GenericRole(canonical_name, node_class)
       
   180     register_canonical_role(canonical_name, role)
       
   181 
       
   182 
       
   183 class GenericRole:
       
   184 
       
   185     """
       
   186     Generic interpreted text role, where the interpreted text is simply
       
   187     wrapped with the provided node class.
       
   188     """
       
   189 
       
   190     def __init__(self, role_name, node_class):
       
   191         self.name = role_name
       
   192         self.node_class = node_class
       
   193 
       
   194     def __call__(self, role, rawtext, text, lineno, inliner,
       
   195                  options={}, content=[]):
       
   196         set_classes(options)
       
   197         return [self.node_class(rawtext, utils.unescape(text), **options)], []
       
   198 
       
   199 
       
   200 class CustomRole:
       
   201 
       
   202     """
       
   203     Wrapper for custom interpreted text roles.
       
   204     """
       
   205 
       
   206     def __init__(self, role_name, base_role, options={}, content=[]):
       
   207         self.name = role_name
       
   208         self.base_role = base_role
       
   209         self.options = None
       
   210         if hasattr(base_role, 'options'):
       
   211             self.options = base_role.options
       
   212         self.content = None
       
   213         if hasattr(base_role, 'content'):
       
   214             self.content = base_role.content
       
   215         self.supplied_options = options
       
   216         self.supplied_content = content
       
   217 
       
   218     def __call__(self, role, rawtext, text, lineno, inliner,
       
   219                  options={}, content=[]):
       
   220         opts = self.supplied_options.copy()
       
   221         opts.update(options)
       
   222         cont = list(self.supplied_content)
       
   223         if cont and content:
       
   224             cont += '\n'
       
   225         cont.extend(content)
       
   226         return self.base_role(role, rawtext, text, lineno, inliner,
       
   227                               options=opts, content=cont)
       
   228 
       
   229 
       
   230 def generic_custom_role(role, rawtext, text, lineno, inliner,
       
   231                         options={}, content=[]):
       
   232     """"""
       
   233     # Once nested inline markup is implemented, this and other methods should
       
   234     # recursively call inliner.nested_parse().
       
   235     set_classes(options)
       
   236     return [nodes.inline(rawtext, utils.unescape(text), **options)], []
       
   237 
       
   238 generic_custom_role.options = {'class': directives.class_option}
       
   239 
       
   240 
       
   241 ######################################################################
       
   242 # Define and register the standard roles:
       
   243 ######################################################################
       
   244 
       
   245 register_generic_role('abbreviation', nodes.abbreviation)
       
   246 register_generic_role('acronym', nodes.acronym)
       
   247 register_generic_role('emphasis', nodes.emphasis)
       
   248 register_generic_role('literal', nodes.literal)
       
   249 register_generic_role('strong', nodes.strong)
       
   250 register_generic_role('subscript', nodes.subscript)
       
   251 register_generic_role('superscript', nodes.superscript)
       
   252 register_generic_role('title-reference', nodes.title_reference)
       
   253 
       
   254 def pep_reference_role(role, rawtext, text, lineno, inliner,
       
   255                        options={}, content=[]):
       
   256     try:
       
   257         pepnum = int(text)
       
   258         if pepnum < 0 or pepnum > 9999:
       
   259             raise ValueError
       
   260     except ValueError:
       
   261         msg = inliner.reporter.error(
       
   262             'PEP number must be a number from 0 to 9999; "%s" is invalid.'
       
   263             % text, line=lineno)
       
   264         prb = inliner.problematic(rawtext, rawtext, msg)
       
   265         return [prb], [msg]
       
   266     # Base URL mainly used by inliner.pep_reference; so this is correct:
       
   267     ref = (inliner.document.settings.pep_base_url
       
   268            + inliner.document.settings.pep_file_url_template % pepnum)
       
   269     set_classes(options)
       
   270     return [nodes.reference(rawtext, 'PEP ' + utils.unescape(text), refuri=ref,
       
   271                             **options)], []
       
   272 
       
   273 register_canonical_role('pep-reference', pep_reference_role)
       
   274 
       
   275 def rfc_reference_role(role, rawtext, text, lineno, inliner,
       
   276                        options={}, content=[]):
       
   277     try:
       
   278         rfcnum = int(text)
       
   279         if rfcnum <= 0:
       
   280             raise ValueError
       
   281     except ValueError:
       
   282         msg = inliner.reporter.error(
       
   283             'RFC number must be a number greater than or equal to 1; '
       
   284             '"%s" is invalid.' % text, line=lineno)
       
   285         prb = inliner.problematic(rawtext, rawtext, msg)
       
   286         return [prb], [msg]
       
   287     # Base URL mainly used by inliner.rfc_reference, so this is correct:
       
   288     ref = inliner.document.settings.rfc_base_url + inliner.rfc_url % rfcnum
       
   289     set_classes(options)
       
   290     node = nodes.reference(rawtext, 'RFC ' + utils.unescape(text), refuri=ref,
       
   291                            **options)
       
   292     return [node], []
       
   293 
       
   294 register_canonical_role('rfc-reference', rfc_reference_role)
       
   295 
       
   296 def raw_role(role, rawtext, text, lineno, inliner, options={}, content=[]):
       
   297     if not options.has_key('format'):
       
   298         msg = inliner.reporter.error(
       
   299             'No format (Writer name) is associated with this role: "%s".\n'
       
   300             'The "raw" role cannot be used directly.\n'
       
   301             'Instead, use the "role" directive to create a new role with '
       
   302             'an associated format.' % role, line=lineno)
       
   303         prb = inliner.problematic(rawtext, rawtext, msg)
       
   304         return [prb], [msg]
       
   305     set_classes(options)
       
   306     node = nodes.raw(rawtext, utils.unescape(text, 1), **options)
       
   307     return [node], []
       
   308 
       
   309 raw_role.options = {'format': directives.unchanged}
       
   310 
       
   311 register_canonical_role('raw', raw_role)
       
   312 
       
   313 
       
   314 ######################################################################
       
   315 # Register roles that are currently unimplemented.
       
   316 ######################################################################
       
   317 
       
   318 def unimplemented_role(role, rawtext, text, lineno, inliner, attributes={}):
       
   319     msg = inliner.reporter.error(
       
   320         'Interpreted text role "%s" not implemented.' % role, line=lineno)
       
   321     prb = inliner.problematic(rawtext, rawtext, msg)
       
   322     return [prb], [msg]
       
   323 
       
   324 register_canonical_role('index', unimplemented_role)
       
   325 register_canonical_role('named-reference', unimplemented_role)
       
   326 register_canonical_role('anonymous-reference', unimplemented_role)
       
   327 register_canonical_role('uri-reference', unimplemented_role)
       
   328 register_canonical_role('footnote-reference', unimplemented_role)
       
   329 register_canonical_role('citation-reference', unimplemented_role)
       
   330 register_canonical_role('substitution-reference', unimplemented_role)
       
   331 register_canonical_role('target', unimplemented_role)
       
   332 
       
   333 # This should remain unimplemented, for testing purposes:
       
   334 register_canonical_role('restructuredtext-unimplemented-role',
       
   335                         unimplemented_role)
       
   336 
       
   337 
       
   338 def set_classes(options):
       
   339     """
       
   340     Auxiliary function to set options['classes'] and delete
       
   341     options['class'].
       
   342     """
       
   343     if options.has_key('class'):
       
   344         assert not options.has_key('classes')
       
   345         options['classes'] = options['class']
       
   346         del options['class']