environment.py (21632B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\jinja2\environment.py 2 import os 3 import sys 4 from jinja2 import nodes 5 from jinja2.defaults import * 6 from jinja2.lexer import get_lexer, TokenStream 7 from jinja2.parser import Parser 8 from jinja2.optimizer import optimize 9 from jinja2.compiler import generate 10 from jinja2.runtime import Undefined, new_context 11 from jinja2.exceptions import TemplateSyntaxError, TemplateNotFound, TemplatesNotFound 12 from jinja2.utils import import_string, LRUCache, Markup, missing, concat, consume, internalcode, _encode_filename 13 _spontaneous_environments = LRUCache(10) 14 _make_traceback = None 15 16 def get_spontaneous_environment(*args): 17 try: 18 env = _spontaneous_environments.get(args) 19 except TypeError: 20 return Environment(*args) 21 22 if env is not None: 23 return env 24 _spontaneous_environments[args] = env = Environment(*args) 25 env.shared = True 26 return env 27 28 29 def create_cache(size): 30 if size == 0: 31 return None 32 if size < 0: 33 return {} 34 return LRUCache(size) 35 36 37 def copy_cache(cache): 38 if cache is None: 39 return 40 if type(cache) is dict: 41 return {} 42 return LRUCache(cache.capacity) 43 44 45 def load_extensions(environment, extensions): 46 result = {} 47 for extension in extensions: 48 if isinstance(extension, basestring): 49 extension = import_string(extension) 50 result[extension.identifier] = extension(environment) 51 52 return result 53 54 55 def _environment_sanity_check(environment): 56 return environment 57 58 59 class Environment(object): 60 sandboxed = False 61 overlayed = False 62 linked_to = None 63 shared = False 64 exception_handler = None 65 exception_formatter = None 66 67 def __init__(self, block_start_string = BLOCK_START_STRING, block_end_string = BLOCK_END_STRING, variable_start_string = VARIABLE_START_STRING, variable_end_string = VARIABLE_END_STRING, comment_start_string = COMMENT_START_STRING, comment_end_string = COMMENT_END_STRING, line_statement_prefix = LINE_STATEMENT_PREFIX, line_comment_prefix = LINE_COMMENT_PREFIX, trim_blocks = TRIM_BLOCKS, newline_sequence = NEWLINE_SEQUENCE, extensions = (), optimized = True, undefined = Undefined, finalize = None, autoescape = False, loader = None, cache_size = 50, auto_reload = True, bytecode_cache = None): 68 self.block_start_string = block_start_string 69 self.block_end_string = block_end_string 70 self.variable_start_string = variable_start_string 71 self.variable_end_string = variable_end_string 72 self.comment_start_string = comment_start_string 73 self.comment_end_string = comment_end_string 74 self.line_statement_prefix = line_statement_prefix 75 self.line_comment_prefix = line_comment_prefix 76 self.trim_blocks = trim_blocks 77 self.newline_sequence = newline_sequence 78 self.undefined = undefined 79 self.optimized = optimized 80 self.finalize = finalize 81 self.autoescape = autoescape 82 self.filters = DEFAULT_FILTERS.copy() 83 self.tests = DEFAULT_TESTS.copy() 84 self.globals = DEFAULT_NAMESPACE.copy() 85 self.loader = loader 86 self.bytecode_cache = None 87 self.cache = create_cache(cache_size) 88 self.bytecode_cache = bytecode_cache 89 self.auto_reload = auto_reload 90 self.extensions = load_extensions(self, extensions) 91 _environment_sanity_check(self) 92 93 def add_extension(self, extension): 94 self.extensions.update(load_extensions(self, [extension])) 95 96 def extend(self, **attributes): 97 for key, value in attributes.iteritems(): 98 if not hasattr(self, key): 99 setattr(self, key, value) 100 101 def overlay(self, block_start_string = missing, block_end_string = missing, variable_start_string = missing, variable_end_string = missing, comment_start_string = missing, comment_end_string = missing, line_statement_prefix = missing, line_comment_prefix = missing, trim_blocks = missing, extensions = missing, optimized = missing, undefined = missing, finalize = missing, autoescape = missing, loader = missing, cache_size = missing, auto_reload = missing, bytecode_cache = missing): 102 args = dict(locals()) 103 del args['self'] 104 del args['cache_size'] 105 del args['extensions'] 106 rv = object.__new__(self.__class__) 107 rv.__dict__.update(self.__dict__) 108 rv.overlayed = True 109 rv.linked_to = self 110 for key, value in args.iteritems(): 111 if value is not missing: 112 setattr(rv, key, value) 113 114 if cache_size is not missing: 115 rv.cache = create_cache(cache_size) 116 else: 117 rv.cache = copy_cache(self.cache) 118 rv.extensions = {} 119 for key, value in self.extensions.iteritems(): 120 rv.extensions[key] = value.bind(rv) 121 122 if extensions is not missing: 123 rv.extensions.update(load_extensions(rv, extensions)) 124 return _environment_sanity_check(rv) 125 126 lexer = property(get_lexer, doc='The lexer for this environment.') 127 128 def iter_extensions(self): 129 return iter(sorted(self.extensions.values(), key=lambda x: x.priority)) 130 131 def getitem(self, obj, argument): 132 try: 133 return obj[argument] 134 except (TypeError, LookupError): 135 if isinstance(argument, basestring): 136 try: 137 attr = str(argument) 138 except Exception: 139 pass 140 else: 141 try: 142 return getattr(obj, attr) 143 except AttributeError: 144 pass 145 146 return self.undefined(obj=obj, name=argument) 147 148 def getattr(self, obj, attribute): 149 try: 150 return getattr(obj, attribute) 151 except AttributeError: 152 pass 153 154 try: 155 return obj[attribute] 156 except (TypeError, LookupError, AttributeError): 157 return self.undefined(obj=obj, name=attribute) 158 159 @internalcode 160 def parse(self, source, name = None, filename = None): 161 try: 162 return self._parse(source, name, filename) 163 except TemplateSyntaxError: 164 exc_info = sys.exc_info() 165 166 self.handle_exception(exc_info, source_hint=source) 167 168 def _parse(self, source, name, filename): 169 return Parser(self, source, name, _encode_filename(filename)).parse() 170 171 def lex(self, source, name = None, filename = None): 172 source = unicode(source) 173 try: 174 return self.lexer.tokeniter(source, name, filename) 175 except TemplateSyntaxError: 176 exc_info = sys.exc_info() 177 178 self.handle_exception(exc_info, source_hint=source) 179 180 def preprocess(self, source, name = None, filename = None): 181 return reduce(lambda s, e: e.preprocess(s, name, filename), self.iter_extensions(), unicode(source)) 182 183 def _tokenize(self, source, name, filename = None, state = None): 184 source = self.preprocess(source, name, filename) 185 stream = self.lexer.tokenize(source, name, filename, state) 186 for ext in self.iter_extensions(): 187 stream = ext.filter_stream(stream) 188 if not isinstance(stream, TokenStream): 189 stream = TokenStream(stream, name, filename) 190 191 return stream 192 193 def _generate(self, source, name, filename, defer_init = False): 194 return generate(source, self, name, filename, defer_init=defer_init) 195 196 def _compile(self, source, filename): 197 return compile(source, filename, 'exec') 198 199 @internalcode 200 def compile(self, source, name = None, filename = None, raw = False, defer_init = False): 201 source_hint = None 202 try: 203 if isinstance(source, basestring): 204 source_hint = source 205 source = self._parse(source, name, filename) 206 if self.optimized: 207 source = optimize(source, self) 208 source = self._generate(source, name, filename, defer_init=defer_init) 209 if raw: 210 return source 211 if filename is None: 212 filename = '<template>' 213 else: 214 filename = _encode_filename(filename) 215 return self._compile(source, filename) 216 except TemplateSyntaxError: 217 exc_info = sys.exc_info() 218 219 self.handle_exception(exc_info, source_hint=source) 220 221 def compile_expression(self, source, undefined_to_none = True): 222 parser = Parser(self, source, state='variable') 223 exc_info = None 224 try: 225 expr = parser.parse_expression() 226 if not parser.stream.eos: 227 raise TemplateSyntaxError('chunk after expression', parser.stream.current.lineno, None, None) 228 expr.set_environment(self) 229 except TemplateSyntaxError: 230 exc_info = sys.exc_info() 231 232 if exc_info is not None: 233 self.handle_exception(exc_info, source_hint=source) 234 body = [nodes.Assign(nodes.Name('result', 'store'), expr, lineno=1)] 235 template = self.from_string(nodes.Template(body, lineno=1)) 236 return TemplateExpression(template, undefined_to_none) 237 238 def compile_templates(self, target, extensions = None, filter_func = None, zip = 'deflated', log_function = None, ignore_errors = True, py_compile = False): 239 from jinja2.loaders import ModuleLoader 240 if log_function is None: 241 log_function = lambda x: None 242 if py_compile: 243 import imp, marshal 244 py_header = imp.get_magic() + u'\xff\xff\xff\xff'.encode('iso-8859-15') 245 246 def write_file(filename, data, mode): 247 if zip: 248 info = ZipInfo(filename) 249 info.external_attr = 32309248L 250 zip_file.writestr(info, data) 251 else: 252 f = open(os.path.join(target, filename), mode) 253 try: 254 f.write(data) 255 finally: 256 f.close() 257 258 if zip is not None: 259 from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED, ZIP_STORED 260 zip_file = ZipFile(target, 'w', dict(deflated=ZIP_DEFLATED, stored=ZIP_STORED)[zip]) 261 log_function('Compiling into Zip archive "%s"' % target) 262 else: 263 if not os.path.isdir(target): 264 os.makedirs(target) 265 log_function('Compiling into folder "%s"' % target) 266 try: 267 for name in self.list_templates(extensions, filter_func): 268 source, filename, _ = self.loader.get_source(self, name) 269 try: 270 code = self.compile(source, name, filename, True, True) 271 except TemplateSyntaxError as e: 272 if not ignore_errors: 273 raise 274 log_function('Could not compile "%s": %s' % (name, e)) 275 continue 276 277 filename = ModuleLoader.get_module_filename(name) 278 if py_compile: 279 c = self._compile(code, _encode_filename(filename)) 280 write_file(filename + 'c', py_header + marshal.dumps(c), 'wb') 281 log_function('Byte-compiled "%s" as %s' % (name, filename + 'c')) 282 else: 283 write_file(filename, code, 'w') 284 log_function('Compiled "%s" as %s' % (name, filename)) 285 286 finally: 287 if zip: 288 zip_file.close() 289 290 log_function('Finished compiling templates') 291 292 def list_templates(self, extensions = None, filter_func = None): 293 x = self.loader.list_templates() 294 if extensions is not None: 295 if filter_func is not None: 296 raise TypeError('either extensions or filter_func can be passed, but not both') 297 filter_func = lambda x: '.' in x and x.rsplit('.', 1)[1] in extensions 298 if filter_func is not None: 299 x = filter(filter_func, x) 300 return x 301 302 def handle_exception(self, exc_info = None, rendered = False, source_hint = None): 303 global _make_traceback 304 if exc_info is None: 305 exc_info = sys.exc_info() 306 if _make_traceback is None: 307 from jinja2.debug import make_traceback as _make_traceback 308 traceback = _make_traceback(exc_info, source_hint) 309 if rendered and self.exception_formatter is not None: 310 return self.exception_formatter(traceback) 311 if self.exception_handler is not None: 312 self.exception_handler(traceback) 313 exc_type, exc_value, tb = traceback.standard_exc_info 314 raise exc_type, exc_value, tb 315 316 def join_path(self, template, parent): 317 return template 318 319 @internalcode 320 def _load_template(self, name, globals): 321 if self.loader is None: 322 raise TypeError('no loader for this environment specified') 323 if self.cache is not None: 324 template = self.cache.get(name) 325 if template is not None and (not self.auto_reload or template.is_up_to_date): 326 return template 327 template = self.loader.load(self, name, globals) 328 if self.cache is not None: 329 self.cache[name] = template 330 return template 331 332 @internalcode 333 def get_template(self, name, parent = None, globals = None): 334 if isinstance(name, Template): 335 return name 336 if parent is not None: 337 name = self.join_path(name, parent) 338 return self._load_template(name, self.make_globals(globals)) 339 340 @internalcode 341 def select_template(self, names, parent = None, globals = None): 342 if not names: 343 raise TemplatesNotFound(message=u'Tried to select from an empty list of templates.') 344 globals = self.make_globals(globals) 345 for name in names: 346 if isinstance(name, Template): 347 return name 348 if parent is not None: 349 name = self.join_path(name, parent) 350 try: 351 return self._load_template(name, globals) 352 except TemplateNotFound: 353 pass 354 355 raise TemplatesNotFound(names) 356 357 @internalcode 358 def get_or_select_template(self, template_name_or_list, parent = None, globals = None): 359 if isinstance(template_name_or_list, basestring): 360 return self.get_template(template_name_or_list, parent, globals) 361 if isinstance(template_name_or_list, Template): 362 return template_name_or_list 363 return self.select_template(template_name_or_list, parent, globals) 364 365 def from_string(self, source, globals = None, template_class = None): 366 globals = self.make_globals(globals) 367 cls = template_class or self.template_class 368 return cls.from_code(self, self.compile(source), globals, None) 369 370 def make_globals(self, d): 371 if not d: 372 return self.globals 373 return dict(self.globals, **d) 374 375 376 class Template(object): 377 378 def __new__(cls, source, block_start_string = BLOCK_START_STRING, block_end_string = BLOCK_END_STRING, variable_start_string = VARIABLE_START_STRING, variable_end_string = VARIABLE_END_STRING, comment_start_string = COMMENT_START_STRING, comment_end_string = COMMENT_END_STRING, line_statement_prefix = LINE_STATEMENT_PREFIX, line_comment_prefix = LINE_COMMENT_PREFIX, trim_blocks = TRIM_BLOCKS, newline_sequence = NEWLINE_SEQUENCE, extensions = (), optimized = True, undefined = Undefined, finalize = None, autoescape = False): 379 env = get_spontaneous_environment(block_start_string, block_end_string, variable_start_string, variable_end_string, comment_start_string, comment_end_string, line_statement_prefix, line_comment_prefix, trim_blocks, newline_sequence, frozenset(extensions), optimized, undefined, finalize, autoescape, None, 0, False, None) 380 return env.from_string(source, template_class=cls) 381 382 @classmethod 383 def from_code(cls, environment, code, globals, uptodate = None): 384 namespace = {'environment': environment, 385 '__file__': code.co_filename} 386 exec code in namespace 387 rv = cls._from_namespace(environment, namespace, globals) 388 rv._uptodate = uptodate 389 return rv 390 391 @classmethod 392 def from_module_dict(cls, environment, module_dict, globals): 393 return cls._from_namespace(environment, module_dict, globals) 394 395 @classmethod 396 def _from_namespace(cls, environment, namespace, globals): 397 t = object.__new__(cls) 398 t.environment = environment 399 t.globals = globals 400 t.name = namespace['name'] 401 t.filename = namespace['__file__'] 402 t.blocks = namespace['blocks'] 403 t.root_render_func = namespace['root'] 404 t._module = None 405 t._debug_info = namespace['debug_info'] 406 t._uptodate = None 407 namespace['environment'] = environment 408 namespace['__jinja_template__'] = t 409 return t 410 411 def render(self, *args, **kwargs): 412 vars = dict(*args, **kwargs) 413 try: 414 return concat(self.root_render_func(self.new_context(vars))) 415 except Exception: 416 exc_info = sys.exc_info() 417 418 return self.environment.handle_exception(exc_info, True) 419 420 def stream(self, *args, **kwargs): 421 return TemplateStream(self.generate(*args, **kwargs)) 422 423 def generate(self, *args, **kwargs): 424 vars = dict(*args, **kwargs) 425 try: 426 for event in self.root_render_func(self.new_context(vars)): 427 yield event 428 429 except Exception: 430 exc_info = sys.exc_info() 431 else: 432 return 433 434 yield self.environment.handle_exception(exc_info, True) 435 436 def new_context(self, vars = None, shared = False, locals = None): 437 return new_context(self.environment, self.name, self.blocks, vars, shared, self.globals, locals) 438 439 def make_module(self, vars = None, shared = False, locals = None): 440 return TemplateModule(self, self.new_context(vars, shared, locals)) 441 442 @property 443 def module(self): 444 if self._module is not None: 445 return self._module 446 self._module = rv = self.make_module() 447 return rv 448 449 def get_corresponding_lineno(self, lineno): 450 for template_line, code_line in reversed(self.debug_info): 451 if code_line <= lineno: 452 return template_line 453 454 return 1 455 456 @property 457 def is_up_to_date(self): 458 if self._uptodate is None: 459 return True 460 return self._uptodate() 461 462 @property 463 def debug_info(self): 464 return [ tuple(map(int, x.split('='))) for x in self._debug_info.split('&') ] 465 466 def __repr__(self): 467 if self.name is None: 468 name = 'memory:%x' % id(self) 469 else: 470 name = repr(self.name) 471 return '<%s %s>' % (self.__class__.__name__, name) 472 473 474 class TemplateModule(object): 475 476 def __init__(self, template, context): 477 self._body_stream = list(template.root_render_func(context)) 478 self.__dict__.update(context.get_exported()) 479 self.__name__ = template.name 480 481 def __html__(self): 482 return Markup(concat(self._body_stream)) 483 484 def __str__(self): 485 return unicode(self).encode('utf-8') 486 487 def __unicode__(self): 488 return concat(self._body_stream) 489 490 def __repr__(self): 491 if self.__name__ is None: 492 name = 'memory:%x' % id(self) 493 else: 494 name = repr(self.__name__) 495 return '<%s %s>' % (self.__class__.__name__, name) 496 497 498 class TemplateExpression(object): 499 500 def __init__(self, template, undefined_to_none): 501 self._template = template 502 self._undefined_to_none = undefined_to_none 503 504 def __call__(self, *args, **kwargs): 505 context = self._template.new_context(dict(*args, **kwargs)) 506 consume(self._template.root_render_func(context)) 507 rv = context.vars['result'] 508 if self._undefined_to_none and isinstance(rv, Undefined): 509 rv = None 510 return rv 511 512 513 class TemplateStream(object): 514 515 def __init__(self, gen): 516 self._gen = gen 517 self.disable_buffering() 518 519 def dump(self, fp, encoding = None, errors = 'strict'): 520 close = False 521 if isinstance(fp, basestring): 522 fp = file(fp, 'w') 523 close = True 524 try: 525 if encoding is not None: 526 iterable = (x.encode(encoding, errors) for x in self) 527 else: 528 iterable = self 529 if hasattr(fp, 'writelines'): 530 fp.writelines(iterable) 531 else: 532 for item in iterable: 533 fp.write(item) 534 535 finally: 536 if close: 537 fp.close() 538 539 def disable_buffering(self): 540 self._next = self._gen.next 541 self.buffered = False 542 543 def enable_buffering(self, size = 5): 544 if size <= 1: 545 raise ValueError('buffer size too small') 546 547 def generator(next): 548 buf = [] 549 c_size = 0 550 push = buf.append 551 while 1: 552 try: 553 while c_size < size: 554 c = next() 555 push(c) 556 if c: 557 c_size += 1 558 559 except StopIteration: 560 if not c_size: 561 return 562 563 yield concat(buf) 564 del buf[:] 565 c_size = 0 566 567 self.buffered = True 568 self._next = generator(self._gen.next).next 569 570 def __iter__(self): 571 return self 572 573 def next(self): 574 return self._next() 575 576 577 Environment.template_class = Template