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
Copyright (C) 2012-2017 Edgewall Software