Mercurial > genshi > mirror
comparison genshi/template/base.py @ 790:da90cee22560 trunk
Merged the custom-directives branch back into trunk.
author | cmlenz |
---|---|
date | Wed, 10 Sep 2008 20:53:09 +0000 |
parents | 52219748e5c1 |
children | ae8727f7e1e1 |
comparison
equal
deleted
inserted
replaced
788:31432f30a6fb | 790:da90cee22560 |
---|---|
24 import sys | 24 import sys |
25 | 25 |
26 from genshi.core import Attrs, Stream, StreamEventKind, START, TEXT, _ensure | 26 from genshi.core import Attrs, Stream, StreamEventKind, START, TEXT, _ensure |
27 from genshi.input import ParseError | 27 from genshi.input import ParseError |
28 | 28 |
29 __all__ = ['Context', 'Template', 'TemplateError', 'TemplateRuntimeError', | 29 __all__ = ['Context', 'DirectiveFactory', 'Template', 'TemplateError', |
30 'TemplateSyntaxError', 'BadDirectiveError'] | 30 'TemplateRuntimeError', 'TemplateSyntaxError', 'BadDirectiveError'] |
31 __docformat__ = 'restructuredtext en' | 31 __docformat__ = 'restructuredtext en' |
32 | 32 |
33 | 33 |
34 class TemplateError(Exception): | 34 class TemplateError(Exception): |
35 """Base exception class for errors related to template processing.""" | 35 """Base exception class for errors related to template processing.""" |
299 top = ctxt.pop() | 299 top = ctxt.pop() |
300 ctxt.pop() | 300 ctxt.pop() |
301 ctxt.frames[0].update(top) | 301 ctxt.frames[0].update(top) |
302 | 302 |
303 | 303 |
304 class TemplateMeta(type): | 304 class DirectiveFactoryMeta(type): |
305 """Meta class for templates.""" | 305 """Meta class for directive factories.""" |
306 | 306 |
307 def __new__(cls, name, bases, d): | 307 def __new__(cls, name, bases, d): |
308 if 'directives' in d: | 308 if 'directives' in d: |
309 d['_dir_by_name'] = dict(d['directives']) | 309 d['_dir_by_name'] = dict(d['directives']) |
310 d['_dir_order'] = [directive[1] for directive in d['directives']] | 310 d['_dir_order'] = [directive[1] for directive in d['directives']] |
311 | 311 |
312 return type.__new__(cls, name, bases, d) | 312 return type.__new__(cls, name, bases, d) |
313 | 313 |
314 | 314 |
315 class Template(object): | 315 class DirectiveFactory(object): |
316 """Base for classes that provide a set of template directives. | |
317 | |
318 :since: version 0.6 | |
319 """ | |
320 __metaclass__ = DirectiveFactoryMeta | |
321 | |
322 directives = [] | |
323 """A list of `(name, cls)` tuples that define the set of directives | |
324 provided by this factory. | |
325 """ | |
326 | |
327 def compare_directives(self): | |
328 """Return a function that takes two directive classes and compares | |
329 them to determine their relative ordering. | |
330 """ | |
331 def _get_index(cls): | |
332 if cls in self._dir_order: | |
333 return self._dir_order.index(cls) | |
334 return 0 | |
335 return lambda a, b: cmp(_get_index(a[0]), _get_index(b[0])) | |
336 | |
337 def get_directive(self, name): | |
338 """Return the directive class for the given name. | |
339 | |
340 :param name: the directive name as used in the template | |
341 :return: the directive class | |
342 :see: `Directive` | |
343 """ | |
344 return self._dir_by_name.get(name) | |
345 | |
346 | |
347 class Template(DirectiveFactory): | |
316 """Abstract template base class. | 348 """Abstract template base class. |
317 | 349 |
318 This class implements most of the template processing model, but does not | 350 This class implements most of the template processing model, but does not |
319 specify the syntax of templates. | 351 specify the syntax of templates. |
320 """ | 352 """ |
321 __metaclass__ = TemplateMeta | |
322 | 353 |
323 EXEC = StreamEventKind('EXEC') | 354 EXEC = StreamEventKind('EXEC') |
324 """Stream event kind representing a Python code suite to execute.""" | 355 """Stream event kind representing a Python code suite to execute.""" |
325 | 356 |
326 EXPR = StreamEventKind('EXPR') | 357 EXPR = StreamEventKind('EXPR') |
361 self.filename = filename | 392 self.filename = filename |
362 self.loader = loader | 393 self.loader = loader |
363 self.lookup = lookup | 394 self.lookup = lookup |
364 self.allow_exec = allow_exec | 395 self.allow_exec = allow_exec |
365 self._init_filters() | 396 self._init_filters() |
397 self._prepared = False | |
366 | 398 |
367 if isinstance(source, basestring): | 399 if isinstance(source, basestring): |
368 source = StringIO(source) | 400 source = StringIO(source) |
369 else: | 401 else: |
370 source = source | 402 source = source |
371 try: | 403 try: |
372 self.stream = list(self._prepare(self._parse(source, encoding))) | 404 self._stream = self._parse(source, encoding) |
373 except ParseError, e: | 405 except ParseError, e: |
374 raise TemplateSyntaxError(e.msg, self.filepath, e.lineno, e.offset) | 406 raise TemplateSyntaxError(e.msg, self.filepath, e.lineno, e.offset) |
375 | 407 |
376 def __getstate__(self): | 408 def __getstate__(self): |
377 state = self.__dict__.copy() | 409 state = self.__dict__.copy() |
387 | 419 |
388 def _init_filters(self): | 420 def _init_filters(self): |
389 self.filters = [self._flatten, self._eval, self._exec] | 421 self.filters = [self._flatten, self._eval, self._exec] |
390 if self.loader: | 422 if self.loader: |
391 self.filters.append(self._include) | 423 self.filters.append(self._include) |
424 | |
425 def _get_stream(self): | |
426 if not self._prepared: | |
427 self._stream = list(self._prepare(self._stream)) | |
428 self._prepared = True | |
429 return self._stream | |
430 stream = property(_get_stream) | |
392 | 431 |
393 def _parse(self, source, encoding): | 432 def _parse(self, source, encoding): |
394 """Parse the template. | 433 """Parse the template. |
395 | 434 |
396 The parsing stage parses the template and constructs a list of | 435 The parsing stage parses the template and constructs a list of |