buildframework/helium/external/python/lib/2.5/docutils-0.5-py2.5.egg/docutils/transforms/__init__.py
changeset 179 d8ac696cc51f
parent 1 be27ed110b50
child 180 e02a83d4c571
child 592 3215c239276a
equal deleted inserted replaced
1:be27ed110b50 179:d8ac696cc51f
     1 # $Id: __init__.py 4975 2007-03-01 18:08:32Z wiemann $
       
     2 # Authors: David Goodger <goodger@python.org>; Ueli Schlaepfer
       
     3 # Copyright: This module has been placed in the public domain.
       
     4 
       
     5 """
       
     6 This package contains modules for standard tree transforms available
       
     7 to Docutils components. Tree transforms serve a variety of purposes:
       
     8 
       
     9 - To tie up certain syntax-specific "loose ends" that remain after the
       
    10   initial parsing of the input plaintext. These transforms are used to
       
    11   supplement a limited syntax.
       
    12 
       
    13 - To automate the internal linking of the document tree (hyperlink
       
    14   references, footnote references, etc.).
       
    15 
       
    16 - To extract useful information from the document tree. These
       
    17   transforms may be used to construct (for example) indexes and tables
       
    18   of contents.
       
    19 
       
    20 Each transform is an optional step that a Docutils component may
       
    21 choose to perform on the parsed document.
       
    22 """
       
    23 
       
    24 __docformat__ = 'reStructuredText'
       
    25 
       
    26 
       
    27 from docutils import languages, ApplicationError, TransformSpec
       
    28 
       
    29 
       
    30 class TransformError(ApplicationError): pass
       
    31 
       
    32 
       
    33 class Transform:
       
    34 
       
    35     """
       
    36     Docutils transform component abstract base class.
       
    37     """
       
    38 
       
    39     default_priority = None
       
    40     """Numerical priority of this transform, 0 through 999 (override)."""
       
    41 
       
    42     def __init__(self, document, startnode=None):
       
    43         """
       
    44         Initial setup for in-place document transforms.
       
    45         """
       
    46 
       
    47         self.document = document
       
    48         """The document tree to transform."""
       
    49 
       
    50         self.startnode = startnode
       
    51         """Node from which to begin the transform.  For many transforms which
       
    52         apply to the document as a whole, `startnode` is not set (i.e. its
       
    53         value is `None`)."""
       
    54 
       
    55         self.language = languages.get_language(
       
    56             document.settings.language_code)
       
    57         """Language module local to this document."""
       
    58 
       
    59     def apply(self, **kwargs):
       
    60         """Override to apply the transform to the document tree."""
       
    61         raise NotImplementedError('subclass must override this method')
       
    62 
       
    63 
       
    64 class Transformer(TransformSpec):
       
    65 
       
    66     """
       
    67     Stores transforms (`Transform` classes) and applies them to document
       
    68     trees.  Also keeps track of components by component type name.
       
    69     """
       
    70 
       
    71     def __init__(self, document):
       
    72         self.transforms = []
       
    73         """List of transforms to apply.  Each item is a 3-tuple:
       
    74         ``(priority string, transform class, pending node or None)``."""
       
    75 
       
    76         self.unknown_reference_resolvers = []
       
    77         """List of hook functions which assist in resolving references"""
       
    78 
       
    79         self.document = document
       
    80         """The `nodes.document` object this Transformer is attached to."""
       
    81 
       
    82         self.applied = []
       
    83         """Transforms already applied, in order."""
       
    84 
       
    85         self.sorted = 0
       
    86         """Boolean: is `self.tranforms` sorted?"""
       
    87 
       
    88         self.components = {}
       
    89         """Mapping of component type name to component object.  Set by
       
    90         `self.populate_from_components()`."""
       
    91 
       
    92         self.serialno = 0
       
    93         """Internal serial number to keep track of the add order of
       
    94         transforms."""
       
    95 
       
    96     def add_transform(self, transform_class, priority=None, **kwargs):
       
    97         """
       
    98         Store a single transform.  Use `priority` to override the default.
       
    99         `kwargs` is a dictionary whose contents are passed as keyword
       
   100         arguments to the `apply` method of the transform.  This can be used to
       
   101         pass application-specific data to the transform instance.
       
   102         """
       
   103         if priority is None:
       
   104             priority = transform_class.default_priority
       
   105         priority_string = self.get_priority_string(priority)
       
   106         self.transforms.append(
       
   107             (priority_string, transform_class, None, kwargs))
       
   108         self.sorted = 0
       
   109 
       
   110     def add_transforms(self, transform_list):
       
   111         """Store multiple transforms, with default priorities."""
       
   112         for transform_class in transform_list:
       
   113             priority_string = self.get_priority_string(
       
   114                 transform_class.default_priority)
       
   115             self.transforms.append(
       
   116                 (priority_string, transform_class, None, {}))
       
   117         self.sorted = 0
       
   118 
       
   119     def add_pending(self, pending, priority=None):
       
   120         """Store a transform with an associated `pending` node."""
       
   121         transform_class = pending.transform
       
   122         if priority is None:
       
   123             priority = transform_class.default_priority
       
   124         priority_string = self.get_priority_string(priority)
       
   125         self.transforms.append(
       
   126             (priority_string, transform_class, pending, {}))
       
   127         self.sorted = 0
       
   128 
       
   129     def get_priority_string(self, priority):
       
   130         """
       
   131         Return a string, `priority` combined with `self.serialno`.
       
   132 
       
   133         This ensures FIFO order on transforms with identical priority.
       
   134         """
       
   135         self.serialno += 1
       
   136         return '%03d-%03d' % (priority, self.serialno)
       
   137 
       
   138     def populate_from_components(self, components):
       
   139         """
       
   140         Store each component's default transforms, with default priorities.
       
   141         Also, store components by type name in a mapping for later lookup.
       
   142         """
       
   143         for component in components:
       
   144             if component is None:
       
   145                 continue
       
   146             self.add_transforms(component.get_transforms())
       
   147             self.components[component.component_type] = component
       
   148         self.sorted = 0
       
   149         # Set up all of the reference resolvers for this transformer. Each
       
   150         # component of this transformer is able to register its own helper
       
   151         # functions to help resolve references.
       
   152         unknown_reference_resolvers = []
       
   153         for i in components:
       
   154             unknown_reference_resolvers.extend(i.unknown_reference_resolvers)
       
   155         decorated_list = [(f.priority, f) for f in unknown_reference_resolvers]
       
   156         decorated_list.sort()
       
   157         self.unknown_reference_resolvers.extend([f[1] for f in decorated_list])
       
   158 
       
   159     def apply_transforms(self):
       
   160         """Apply all of the stored transforms, in priority order."""
       
   161         self.document.reporter.attach_observer(
       
   162             self.document.note_transform_message)
       
   163         while self.transforms:
       
   164             if not self.sorted:
       
   165                 # Unsorted initially, and whenever a transform is added.
       
   166                 self.transforms.sort()
       
   167                 self.transforms.reverse()
       
   168                 self.sorted = 1
       
   169             priority, transform_class, pending, kwargs = self.transforms.pop()
       
   170             transform = transform_class(self.document, startnode=pending)
       
   171             transform.apply(**kwargs)
       
   172             self.applied.append((priority, transform_class, pending, kwargs))