Edgewall Software

Changeset 22 for trunk/markup/input.py


Ignore:
Timestamp:
Jun 20, 2006, 3:05:37 PM (17 years ago)
Author:
cmlenz
Message:
  • Include paths are now interpreted relative to the path of the including template. Closes #3.
  • The filename is now included as first item in the pos tuple of stream events.
  • Simplified the "basic" example so that it actually is basic.
  • Added a more complex example using nested relative includes in examples/includes.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/markup/input.py

    r2 r22  
    2525
    2626
     27class ParseError(Exception):
     28    """Exception raised when fatal syntax errors are found in the input being
     29    parsed."""
     30
     31    def __init__(self, message, filename='<string>', lineno=-1, offset=-1):
     32        Exception.__init__(self, message)
     33        self.filename = filename
     34        self.lineno = lineno
     35        self.offset = offset
     36
     37
    2738class XMLParser(object):
    2839    """Generator-based XML parser based on roughly equivalent code in
    2940    Kid/ElementTree."""
    3041
    31     def __init__(self, source):
     42    def __init__(self, source, filename=None):
    3243        self.source = source
     44        self.filename = filename
    3345
    3446        # Setup the Expat parser
     
    4961        # Location reporting is only support in Python >= 2.4
    5062        if not hasattr(parser, 'CurrentLineNumber'):
    51             self.getpos = self._getpos_unknown
     63            self._getpos = self._getpos_unknown
    5264
    5365        self.expat = parser
    54         self.queue = []
     66        self._queue = []
    5567
    5668    def __iter__(self):
    57         bufsize = 4 * 1024 # 4K
    58         done = False
    59         while True:
    60             while not done and len(self.queue) == 0:
    61                 data = self.source.read(bufsize)
    62                 if data == '': # end of data
    63                     if hasattr(self, 'expat'):
    64                         self.expat.Parse('', True)
    65                         del self.expat # get rid of circular references
    66                     done = True
    67                 else:
    68                     self.expat.Parse(data, False)
    69             for event in self.queue:
    70                 yield event
    71             self.queue = []
    72             if done:
    73                 break
     69        try:
     70            bufsize = 4 * 1024 # 4K
     71            done = False
     72            while True:
     73                while not done and len(self._queue) == 0:
     74                    data = self.source.read(bufsize)
     75                    if data == '': # end of data
     76                        if hasattr(self, 'expat'):
     77                            self.expat.Parse('', True)
     78                            del self.expat # get rid of circular references
     79                        done = True
     80                    else:
     81                        self.expat.Parse(data, False)
     82                for event in self._queue:
     83                    yield event
     84                self._queue = []
     85                if done:
     86                    break
     87        except expat.ExpatError, e:
     88            msg = str(e)
     89            if self.filename:
     90                msg += ', in ' + self.filename
     91            raise ParseError(msg, self.filename, e.lineno, e.offset)
    7492
    7593    def _getpos_unknown(self):
    76         return (-1, -1)
    77 
    78     def getpos(self):
    79         return self.expat.CurrentLineNumber, self.expat.CurrentColumnNumber
     94        return (self.filename or '<string>', -1, -1)
     95
     96    def _getpos(self):
     97        return (self.filename or '<string>', self.expat.CurrentLineNumber,
     98                self.expat.CurrentColumnNumber)
    8099
    81100    def _handle_start(self, tag, attrib):
    82         self.queue.append((Stream.START, (QName(tag), Attributes(attrib.items())),
    83                            self.getpos()))
     101        self._queue.append((Stream.START, (QName(tag), Attributes(attrib.items())),
     102                           self._getpos()))
    84103
    85104    def _handle_end(self, tag):
    86         self.queue.append((Stream.END, QName(tag), self.getpos()))
     105        self._queue.append((Stream.END, QName(tag), self._getpos()))
    87106
    88107    def _handle_data(self, text):
    89         self.queue.append((Stream.TEXT, text, self.getpos()))
     108        self._queue.append((Stream.TEXT, text, self._getpos()))
    90109
    91110    def _handle_prolog(self, version, encoding, standalone):
    92         self.queue.append((Stream.PROLOG, (version, encoding, standalone),
    93                            self.getpos()))
     111        self._queue.append((Stream.PROLOG, (version, encoding, standalone),
     112                           self._getpos()))
    94113
    95114    def _handle_doctype(self, name, sysid, pubid, has_internal_subset):
    96         self.queue.append((Stream.DOCTYPE, (name, pubid, sysid), self.getpos()))
     115        self._queue.append((Stream.DOCTYPE, (name, pubid, sysid), self._getpos()))
    97116
    98117    def _handle_start_ns(self, prefix, uri):
    99         self.queue.append((Stream.START_NS, (prefix or '', uri), self.getpos()))
     118        self._queue.append((Stream.START_NS, (prefix or '', uri), self._getpos()))
    100119
    101120    def _handle_end_ns(self, prefix):
    102         self.queue.append((Stream.END_NS, prefix or '', self.getpos()))
     121        self._queue.append((Stream.END_NS, prefix or '', self._getpos()))
    103122
    104123    def _handle_pi(self, target, data):
    105         self.queue.append((Stream.PI, (target, data), self.getpos()))
     124        self._queue.append((Stream.PI, (target, data), self._getpos()))
    106125
    107126    def _handle_comment(self, text):
    108         self.queue.append((Stream.COMMENT, text, self.getpos()))
     127        self._queue.append((Stream.COMMENT, text, self._getpos()))
    109128
    110129    def _handle_other(self, text):
     
    113132            try:
    114133                text = unichr(htmlentitydefs.name2codepoint[text[1:-1]])
    115                 self.queue.append((Stream.TEXT, text, self.getpos()))
     134                self._queue.append((Stream.TEXT, text, self._getpos()))
    116135            except KeyError:
    117                 lineno, offset = self.getpos()
     136                lineno, offset = self._getpos()
    118137                raise expat.error("undefined entity %s: line %d, column %d" %
    119138                                  (text, lineno, offset))
     
    124143
    125144
    126 class HTMLParser(html.HTMLParser):
     145class HTMLParser(html.HTMLParser, object):
    127146    """Parser for HTML input based on the Python `HTMLParser` module.
    128147   
     
    135154                              'param'])
    136155
    137     def __init__(self, source):
     156    def __init__(self, source, filename=None):
    138157        html.HTMLParser.__init__(self)
    139158        self.source = source
    140         self.queue = []
     159        self.filename = filename
     160        self._queue = []
    141161        self._open_tags = []
    142162
    143163    def __iter__(self):
    144         bufsize = 4 * 1024 # 4K
    145         done = False
    146         while True:
    147             while not done and len(self.queue) == 0:
    148                 data = self.source.read(bufsize)
    149                 if data == '': # end of data
    150                     self.close()
    151                     done = True
    152                 else:
    153                     self.feed(data)
    154             for kind, data, pos in self.queue:
    155                 yield kind, data, pos
    156             self.queue = []
    157             if done:
    158                 open_tags = self._open_tags
    159                 open_tags.reverse()
    160                 for tag in open_tags:
    161                     yield Stream.END, QName(tag), pos
    162                 break
     164        try:
     165            bufsize = 4 * 1024 # 4K
     166            done = False
     167            while True:
     168                while not done and len(self._queue) == 0:
     169                    data = self.source.read(bufsize)
     170                    if data == '': # end of data
     171                        self.close()
     172                        done = True
     173                    else:
     174                        self.feed(data)
     175                for kind, data, pos in self._queue:
     176                    yield kind, data, pos
     177                self._queue = []
     178                if done:
     179                    open_tags = self._open_tags
     180                    open_tags.reverse()
     181                    for tag in open_tags:
     182                        yield Stream.END, QName(tag), pos
     183                    break
     184        except html.HTMLParseError, e:
     185            msg = '%s: line %d, column %d' % (e.msg, e.lineno, e.offset)
     186            if self.filename:
     187                msg += ', in %s' % self.filename
     188            raise ParseError(msg, self.filename, e.lineno, e.offset)
     189
     190    def _getpos(self):
     191        lineno, column = self.getpos()
     192        return (self.filename, lineno, column)
    163193
    164194    def handle_starttag(self, tag, attrib):
    165         pos = self.getpos()
    166         self.queue.append((Stream.START, (QName(tag), Attributes(attrib)), pos))
     195        pos = self._getpos()
     196        self._queue.append((Stream.START, (QName(tag), Attributes(attrib)), pos))
    167197        if tag in self._EMPTY_ELEMS:
    168             self.queue.append((Stream.END, QName(tag), pos))
     198            self._queue.append((Stream.END, QName(tag), pos))
    169199        else:
    170200            self._open_tags.append(tag)
     
    172202    def handle_endtag(self, tag):
    173203        if tag not in self._EMPTY_ELEMS:
    174             pos = self.getpos()
     204            pos = self._getpos()
    175205            while self._open_tags:
    176206                open_tag = self._open_tags.pop()
    177207                if open_tag.lower() == tag.lower():
    178208                    break
    179                 self.queue.append((Stream.END, QName(open_tag), pos))
    180             self.queue.append((Stream.END, QName(tag), pos))
     209                self._queue.append((Stream.END, QName(open_tag), pos))
     210            self._queue.append((Stream.END, QName(tag), pos))
    181211
    182212    def handle_data(self, text):
    183         self.queue.append((Stream.TEXT, text, self.getpos()))
     213        self._queue.append((Stream.TEXT, text, self._getpos()))
    184214
    185215    def handle_charref(self, name):
    186         self.queue.append((Stream.TEXT, Markup('&#%s;' % name), self.getpos()))
     216        self._queue.append((Stream.TEXT, Markup('&#%s;' % name), self._getpos()))
    187217
    188218    def handle_entityref(self, name):
    189         self.queue.append((Stream.TEXT, Markup('&%s;' % name), self.getpos()))
     219        self._queue.append((Stream.TEXT, Markup('&%s;' % name), self._getpos()))
    190220
    191221    def handle_pi(self, data):
    192222        target, data = data.split(maxsplit=1)
    193223        data = data.rstrip('?')
    194         self.queue.append((Stream.PI, (target.strip(), data.strip()),
    195                            self.getpos()))
     224        self._queue.append((Stream.PI, (target.strip(), data.strip()),
     225                           self._getpos()))
    196226
    197227    def handle_comment(self, text):
    198         self.queue.append((Stream.COMMENT, text, self.getpos()))
     228        self._queue.append((Stream.COMMENT, text, self._getpos()))
    199229
    200230
Note: See TracChangeset for help on using the changeset viewer.