a
    mzfh                     @   s  d Z ddlZddlZddlZddlZddlZddlmZ ddlZddl	m
Z
 ddlmZmZmZmZ ddlmZ g dZdd	lmZ d
d ZG dd dZG dd dZG dd dZG dd dZG dd dZG dd dZG dd dZdZG dd dZG dd deZG dd  d Z G d!d" d"Z!G d#d$ d$eZ"G d%d& d&eZ#G d'd( d(eZ$G d)d* d*eZ%G d+d, d,Z&G d-d. d.Z'eee"e$e#e%e d/Z(g d0Z)g d1Z*e+d2d3 e*D Z,G d4d5 d5Z-G d6d7 d7Z.G d8d9 d9Z/G d:d; d;e/Z0G d<d= d=e0Z1G d>d? d?Z2G d@dA dAe2Z3e2Z4zddBl5m6Z6 e3 Z4Z2W n e7yV   Y n0 dCdD Z8dEdF Z9G dGdH dHe:Z;G dIdJ dJe:Z<g dKZ=G dLdM dMej>Z?G dNdO dOeZ@dPdQ ZAeBdRkrdSejCv re9ejCdT  nddlDZDeDE  dS )Ua  
simple, elegant templating
(part of web.py)

Template design:

Template string is split into tokens and the tokens are combined into nodes.
Parse tree is a nodelist. TextNode and ExpressionNode are simple nodes and
for-loop, if-loop etc are block nodes, which contain multiple child nodes.

Each node can emit some python string. python string emitted by the
root node is validated for safeeval and executed using python in the given environment.

Enough care is taken to make sure the generated code and the template has line to line match,
so that the error messages can point to exact line number in template. (It doesn't work in some cases still.)

Grammar:

    template -> defwith sections
    defwith -> '$def with (' arguments ')' | ''
    sections -> section*
    section -> block | assignment | line

    assignment -> '$ ' <assignment expression>
    line -> (text|expr)*
    text -> <any characters other than $>
    expr -> '$' pyexpr | '$(' pyexpr ')' | '${' pyexpr '}'
    pyexpr -> <python expression>
    N)open   )websafe)
re_compilesafestrsafeunicodestorage)config)TemplateRenderrenderfrender
ParseErrorSecurityErrortest)MutableMappingc                 C   s6   |  dd }|r*| d| | |d fS | dfS dS )z
    Splits the given text at newline.

        >>> splitline('foo\nbar')
        ('foo\n', 'bar')
        >>> splitline('foo')
        ('foo', '')
        >>> splitline('')
        ('', '')
    
r   N )find)textindex r   :/var/www/media/lib/python3.9/site-packages/web/template.py	splitline9   s    r   c                   @   s   e Zd ZdZdd Zd*ddZdd Zd	d
 Zdd Zdd Z	dd Z
dd Zdd Zdd Zd+ddZdd Zdd Zdd Zd d! Zd"d# Zd,d%d&Zd'd( Zd)S )-ParserzParser Base.c                 C   s   t | _t| _d S N)STATEMENT_NODESstatement_nodesKEYWORDSkeywordsselfr   r   r   __init__N   s    zParser.__init__
<template>c                 C   s.   || _ || _| |\}}| |}t||S r   )r   nameread_defwith
read_suiteDefwithNode)r!   r   r$   defwithsuiter   r   r   parseR   s
    
zParser.parsec                 C   s:   | dr.t|\}}|dd   }||fS d|fS d S )Nz	$def withr   r   )
startswithr   strip)r!   r   r(   r   r   r   r%   Z   s
    
zParser.read_defwithc                 C   s   | ddr|d}|d| ||d d  }}| |}|dkrT| |S || jv rj| ||S || jv r~| |S |	 dkr| 
|S | |S )a  Reads one section from the given text.

        section -> block | assignment | line

            >>> read_section = Parser().read_section
            >>> read_section('foo\nbar\n')
            (<line: [t'foo\n']>, 'bar\n')
            >>> read_section('$ a = b + 1\nfoo\n')
            (<assignment: 'a = b + 1'>, 'foo\n')

        read_section('$for in range(10):\n    hello $i\nfoo)
         $Nr   varr   )lstripr+   r   python_lookaheadread_varr   read_block_sectionr   read_keywordr,   read_assignmentreadline)r!   r   r   begin_indenttext2Zaheadr   r   r   read_sectionb   s    






zParser.read_sectionc                    s  t |\}} |}t|dk r*td|d }|d }||dd  }|dkrXn|dkr|d dkr |d	\}} fd
d| D }g }	|D ]}
|	|
j	 |	
td qn |\}}|j	}	dd |	D }dd| }ntdt|||fS )a   Reads a var statement.

        >>> read_var = Parser().read_var
        >>> read_var('var x=10\nfoo')
        (<var: x = 10>, 'foo')
        >>> read_var('var x: hello $name\nfoo')
        (<var: x = join_(u'hello ', escape_(name, True))>, 'foo')
           zInvalid var statementr      =:   r       c                    s   g | ]}  |d  qS )r   )r6   ).0xr    r   r   
<listcomp>       z#Parser.read_var.<locals>.<listcomp>c                 S   s   g | ]}| d qS r   emitr@   noder   r   r   rB      rC   z	join_(%s), )r   python_tokenslenSyntaxErrorsplitr,   read_indented_block
splitlinesextendnodesappendTextNoder6   joinVarNode)r!   r   linetokensr$   sepvalueblocklinesrQ   rA   Zlinenode_partsr   r    r   r2      s.    	
zParser.read_varc                 C   s*   g }|r"|  |\}}|| qt|S )zReads section by section till end of text.

        >>> read_suite = Parser().read_suite
        >>> read_suite('hello $name\nfoo\n')
        [<line: [t'hello ', $name, t'\n']>, <line: [t'foo\n']>]
        )r9   rR   	SuiteNode)r!   r   sectionssectionr   r   r   r&      s
    zParser.read_suitec                 C   sP   t |\}}|dr"|dd }g }|rD| |\}}|| q&t||fS )a  Reads one line from the text. Newline is suppressed if the line ends with \.

        >>> readline = Parser().readline
        >>> readline('hello $name!\nbye!')
        (<line: [t'hello ', $name, t'!\n']>, 'bye!')
        >>> readline('hello $name!\\\nbye!')
        (<line: [t'hello ', $name, t'!']>, 'bye!')
        >>> readline('$f()\n\n')
        (<line: [$f(), t'\n']>, '\n')
        z\
N)r   endswith	read_noderR   LineNode)r!   r   rV   rQ   rH   r   r   r   r6      s    
zParser.readlinec                 C   s   | drtd|dd fS | dr@t|\}}td|fS | dr|dd }| drrd	}|dd }nd
}| j||dS | |S dS )zReads a node from the given text and returns the node and remaining text.

        >>> read_node = Parser().read_node
        >>> read_node('hello $name')
        (t'hello ', '$name')
        >>> read_node('$name')
        ($name, '')
        $$r.   r;   N$#r   r   r=   FTescape)r+   rS   r   	read_expr	read_text)r!   r   rV   rh   r   r   r   rc      s    	



zParser.read_nodec                 C   s>   | d}|dk rt|dfS t|d| ||d fS dS )zReads a text node from the given text.

        >>> read_text = Parser().read_text
        >>> read_text('hello $name')
        (t'hello ', '$name')
        r.   r   r   N)r   rS   )r!   r   r   r   r   r   rj      s    
zParser.read_textc                 C   s    t |\}}t| d |fS Nr   )r   StatementNoder,   r!   r   rV   r   r   r   r4      s    zParser.read_keywordTc                    s   fdd}fdd fddfdd fd	d
dddddd }G dd d}|||  jv r  n|  jj\}}t|d| |d||d fS )ae  Reads a python expression from the text and returns the expression and remaining text.

        expr -> simple_expr | paren_expr
        simple_expr -> id extended_expr
        extended_expr -> attr_access | paren_expr extended_expr | ''
        attr_access -> dot id extended_expr
        paren_expr -> [ tokens ] | ( tokens ) | { tokens }

            >>> read_expr = Parser().read_expr
            >>> read_expr("name")
            ($name, '')
            >>> read_expr("a.b and c")
            ($a.b, ' and c')
            >>> read_expr("a. b")
            ($a, '. b')
            >>> read_expr("name</h1>")
            ($name, '</h1>')
            >>> read_expr("(limit)ing")
            ($(limit), 'ing')
            >>> read_expr('a[1, 2][:3].f(1+2, "weird string[).", 3 + 4) done.')
            ($a[1, 2][:3].f(1+2, "weird string[).", 3 + 4), ' done.')
        c                      s        d S r   r   r   )extended_expr
identifierr   r   simple_expr  s    z%Parser.read_expr.<locals>.simple_exprc                      s   t   d S r   nextr   )rW   r   r   ro     s    z$Parser.read_expr.<locals>.identifierc                     sF     } | d u rd S | jdkr&   n| jv r>    nd S d S )N.)	lookaheadrY   )rt   )attr_accessrn   
paren_exprparensrW   r   r   rn     s    

z'Parser.read_expr.<locals>.extended_exprc                     s2   ddl m}   j| kr.t      d S )Nr   NAME)tokenry   
lookahead2typerr   rx   )rn   ro   rW   r   r   ru      s
    z%Parser.read_expr.<locals>.attr_accessc                     sB   t j} |  } jv r(   qt }|j|krq>qd S r   )rr   rY   rt   )beginendt)rv   rw   rW   r   r   rv   (  s    

z$Parser.read_expr.<locals>.paren_expr)]})([{c                 3   s   t | g  fdd}d}t|D ]p}t|d |d |d |d d}|dur||jkr|\}}|j\}}td	| || ||jdV  |j}|V  q$dS )
a:  tokenize text using python tokenizer.
            Python tokenizer ignores spaces, but they might be important in some cases.
            This function introduces dummy space tokens when it identifies any ignored space.
            Each token is a storage object containing type, value, begin and end.
            c                      s   t  S r   rq   r   ir   r   <lambda>=  rC   z6Parser.read_expr.<locals>.get_tokens.<locals>.<lambda>Nr   r   r;   r>   r|   rY   r}   r~   )itertokenizegenerate_tokensr   r}   r~   )r   r6   r~   r   r\   x1Zx2r   r   r   
get_tokens6  s    
 
z$Parser.read_expr.<locals>.get_tokensc                   @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )z$Parser.read_expr.<locals>.BetterIterz6Iterator like object with 2 support for 2 look aheads.c                 S   s    t || _g | _d| _d | _d S Nr   )r   	iteritemsitemspositioncurrent_itemr!   r   r   r   r   r"   K  s    
z-Parser.read_expr.<locals>.BetterIter.__init__c                 S   s,   t | j| jkr | j|   | j| j S r   rK   r   r   rR   _nextr    r   r   r   rt   Q  s    z.Parser.read_expr.<locals>.BetterIter.lookaheadc                 S   s&   zt | jW S  ty    Y d S 0 d S r   )rr   r   StopIterationr    r   r   r   r   V  s    z*Parser.read_expr.<locals>.BetterIter._nextc                 S   s4   t | j| jd kr$| j|   | j| jd  S Nr   r   r    r   r   r   r{   \  s    z/Parser.read_expr.<locals>.BetterIter.lookahead2c                 S   s   |   | _|  jd7  _| jS r   )rt   r   r   r    r   r   r   __next__a  s    
z-Parser.read_expr.<locals>.BetterIter.__next__N)	__name__
__module____qualname____doc__r"   rt   r   r{   r   r   r   r   r   
BetterIterH  s   r   Nrg   )rt   rY   r   r~   ExpressionNode)r!   r   rh   rp   r   r   rowcolr   )ru   rn   ro   rv   rw   rW   r   ri      s    zParser.read_exprc                 C   s   t |\}}t| |fS )zReads assignment statement from text.

        >>> read_assignment = Parser().read_assignment
        >>> read_assignment('a = b + 1\nfoo')
        (<assignment: 'a = b + 1'>, 'foo')
        )r   AssignmentNoder,   rm   r   r   r   r5   o  s    zParser.read_assignmentc                    s,   t |g  fdd}t|}t|d S )a   Returns the first python token from the given text.

        >>> python_lookahead = Parser().python_lookahead
        >>> python_lookahead('for i in range(10):')
        'for'
        >>> python_lookahead('else:')
        'else'
        >>> python_lookahead(' x = 1')
        ' '
        c                      s   t  S r   rq   r   r   r   r   r     rC   z)Parser.python_lookahead.<locals>.<lambda>r   )r   r   r   rr   r!   r   r6   rW   r   r   r   r1   y  s    

zParser.python_lookaheadc                    s.   t |g  fdd}t|}dd |D S )Nc                      s   t  S r   rq   r   r   r   r   r     rC   z&Parser.python_tokens.<locals>.<lambda>c                 S   s   g | ]}|d  qS )r   r   )r@   r   r   r   r   rB     rC   z(Parser.python_tokens.<locals>.<listcomp>)r   r   r   r   r   r   r   rJ     s    

zParser.python_tokensc                 C   sj   |dkrd|fS d}|rbt |\}}| dkr:|d7 }n"||rb||t|d 7 }nqb|}q||fS )a   Read a block of text. A block is what typically follows a for or it statement.
        It can be in the same line as that of the statement or an indented block.

            >>> read_indented_block = Parser().read_indented_block
            >>> read_indented_block('  a\n  b\nc', '  ')
            ('a\nb\n', 'c')
            >>> read_indented_block('  a\n    b\n  c\nd', '  ')
            ('a\n  b\nc\n', 'd')
            >>> read_indented_block('  a\n\n    b\nc', '  ')
            ('a\n\n  b\n', 'c')
        r   r   N)r   r,   r+   rK   )r!   r   indentrZ   rV   r8   r   r   r   rN     s    

zParser.read_indented_blockc                 C   s.   t |}|d |d|j ||jd fS )zReads a python statement.

        >>> read_statement = Parser().read_statement
        >>> read_statement('for i in range(10): hello $name')
        ('for i in range(10):', ' hello $name')
        r=   N)PythonTokenizerconsume_tillr   )r!   r   tokr   r   r   read_statement  s    
zParser.read_statementr   c           
      C   s   t |\}}| |\}}| |}| rD| dsD| }nLdd }||t|d }|dkrr|| }	n|t|t }	| 	||	\}}| 
|||||fS )a  
            >>> read_block_section = Parser().read_block_section
            >>> read_block_section('for i in range(10): hello $i\nfoo')
            (<block: 'for i in range(10):', [<line: [t'hello ', $i, t'\n']>]>, 'foo')
            >>> read_block_section('for i in range(10):\n        hello $i\n    foo', begin_indent='    ')
            (<block: 'for i in range(10):', [<line: [t'hello ', $i, t'\n']>]>, '    foo')
            >>> read_block_section('for i in range(10):\n  hello $i\nfoo')
            (<block: 'for i in range(10):', [<line: [t'hello ', $i, t'\n']>]>, 'foo')

        With inline comment:

            >>> read_block_section('for i in range(10):  $# inline comment\n hello $i\nfoo')
            (<block: 'for i in range(10):', []>, ' hello $i\nfoo')
        rf   c                 S   s(   t d}|| }|o|d}|p&dS )Nz  +r   r   )r   matchgroup)r   rxr   first_indentr   r   r   find_indent  s    
z.Parser.read_block_section.<locals>.find_indentNcode)r   r   r1   r,   r0   r+   rK   minINDENTrN   create_block_node)
r!   r   r7   rV   stmtkeywordrZ   r   r   r   r   r   r   r3     s    


zParser.read_block_sectionc                 C   s0   || j v r| j | |||S tdt| d S )NzUnknown statement: %s)r   r   repr)r!   r   r   rZ   r7   r   r   r   r     s    
zParser.create_block_nodeN)r#   )T)r   )r   r   r   r   r"   r*   r%   r9   r2   r&   r6   rc   rj   r4   ri   r5   r1   rJ   rN   r   r3   r   r   r   r   r   r   K   s&   
&
z

+r   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	r   z&Utility wrapper over python tokenizer.c                    s2   || _ t|g  fdd}t|| _d| _d S )Nc                      s   t  S r   rq   r   r   r   r   r     rC   z*PythonTokenizer.__init__.<locals>.<lambda>r   )r   r   r   r   rW   r   )r!   r   r6   r   r   r   r"     s
    
zPythonTokenizer.__init__c                 C   s|   zht | }|j|krqfn@|jdkr.| d n*|jdkrD| d n|jdkrX| d |jdkrqfqW n   Y dS 0 dS )	zConsumes tokens till colon.

        >>> tok = PythonTokenizer('for i in range(10): hello $i')
        >>> tok.consume_till(':')
        >>> tok.text[:tok.index]
        'for i in range(10):'
        >>> tok.text[tok.index:]
        ' hello $i'
        r   r   r   r   r   r   r   N)rr   rY   r   )r!   delimr   r   r   r   r     s    






zPythonTokenizer.consume_tillc                 C   s2   t | j\}}}}}|\}}|| _t||||dS )Nr   )rr   rW   r   r   )r!   r|   r   r}   r~   rV   r   r   r   r   r   r     s    zPythonTokenizer.__next__N)r   r   r   r   r"   r   r   r   r   r   r   r     s   #r   c                   @   s$   e Zd Zdd Zdd Zdd ZdS )r'   c                 C   sf   |r&| ddd | _|  jd7  _nd| _|  jd7  _|  jd7  _|  jd7  _|| _d	| _d S )
Nwith__template__r=   z
    __lineoffset__ = -4zdef __template__():z
    __lineoffset__ = -5z
    loop = ForLoop()z3
    self = TemplateResult(); extend_ = self.extendz
    return self)replacer(   r)   r~   )r!   r(   r)   r   r   r   r"     s    zDefwithNode.__init__c                 C   s$   d}|| j  | j|t  | j S )Nz# coding: utf-8
)r(   r)   rF   r   r~   )r!   r   encodingr   r   r   rF   +  s    zDefwithNode.emitc                 C   s   d| j | jf S )Nz<defwith: %s, %s>)r(   r)   r    r   r   r   __repr__/  s    zDefwithNode.__repr__Nr   r   r   r"   rF   r   r   r   r   r   r'     s   r'   c                   @   s&   e Zd Zdd Zd	ddZdd ZdS )
rS   c                 C   s
   || _ d S r   )rY   )r!   rY   r   r   r   r"   4  s    zTextNode.__init__r   c                 C   s   t t| jS r   )r   r   rY   r!   r   r7   r   r   r   rF   7  s    zTextNode.emitc                 C   s   dt | j S )Nr   )r   rY   r    r   r   r   r   :  s    zTextNode.__repr__N)r   r   r   r   r   r   rS   3  s   
rS   c                   @   s(   e Zd Zd
ddZdddZdd Zd	S )r   Tc                 C   s@   |  | _|dr6|dr6d| jdd  d | _|| _d S )Nr   r   r   r   r   r   )r,   rY   r+   rb   rh   r!   rY   rh   r   r   r   r"   ?  s    
zExpressionNode.__init__r   c                 C   s   d| j t| jf S )Nzescape_(%s, %s))rY   boolrh   r   r   r   r   rF   H  s    zExpressionNode.emitc                 C   s   | j rd}nd}d|| jf S )Nr   r=   z$%s%s)rh   rY   )r!   rh   r   r   r   r   K  s    zExpressionNode.__repr__N)T)r   r   r   r   r   r   r   >  s   
	
r   c                   @   s&   e Zd Zdd Zd	ddZdd ZdS )
r   c                 C   s
   || _ d S r   r   )r!   r   r   r   r   r"   T  s    zAssignmentNode.__init__r   c                 C   s   || j  d S rk   r   r   r   r   r   rF   W  s    zAssignmentNode.emitc                 C   s   dt | j S )Nz<assignment: %s>r   r   r    r   r   r   r   Z  s    zAssignmentNode.__repr__N)r   r   r   r   r   r   r   S  s   
r   c                   @   s&   e Zd Zdd Zd	ddZdd ZdS )
rd   c                 C   s
   || _ d S r   )rQ   )r!   rQ   r   r   r   r"   _  s    zLineNode.__init__r   c                 C   s4   dd | j D }|r"t|g| }|dd|  S )Nc                 S   s   g | ]}| d qS rD   rE   rG   r   r   r   rB   c  rC   z!LineNode.emit.<locals>.<listcomp>zextend_([%s])
rI   )rQ   r   rT   )r!   r   text_indentr$   r   r   r   r   rF   b  s    zLineNode.emitc                 C   s   dt | j S )Nz
<line: %s>)r   rQ   r    r   r   r   r   i  s    zLineNode.__repr__N)r   r   r   r   r   r   r   rd   ^  s   
rd   r?   c                   @   s(   e Zd Zd	ddZd
ddZdd ZdS )	BlockNoder   c                 C   s   || _ t || _|| _d S r   )r   r   r&   r)   r7   r!   r   rZ   r7   r   r   r   r"   q  s    zBlockNode.__init__c                 C   s*   | j | }|| j | j|t | }|S r   r7   r   r)   rF   r   r!   r   r   outr   r   r   rF   v  s    
zBlockNode.emitc                 C   s   dt | jt | jf S Nz<block: %s, %s>)r   r   r)   r    r   r   r   r   {  s    zBlockNode.__repr__N)r   )r   r   r   r   r   r   r   p  s   

r   c                   @   s   e Zd ZdddZdd ZdS )ForNoder   c                 C   s\   || _ t|}|d |d |j }||jd }|d |  d }t| ||| d S )Ninr   z loop.setup(z):)original_stmtr   r   r   r,   r   r"   )r!   r   rZ   r7   r   abr   r   r   r"     s    
zForNode.__init__c                 C   s   dt | jt | jf S r   )r   r   r)   r    r   r   r   r     s    zForNode.__repr__N)r   )r   r   r   r"   r   r   r   r   r   r     s   
	r   c                   @   s(   e Zd Zd	ddZd
ddZdd ZdS )CodeNoder   c                 C   s   d| | _ d S rk   r   r   r   r   r   r"     s    zCodeNode.__init__c                 C   s*   dd l }|d|j}||| jdS )Nr   ^r-   )recompileMsubr   rstrip)r!   r   r   r   r   r   r   r   rF     s    zCodeNode.emitc                 C   s   dt | j S )Nz
<code: %s>r   r    r   r   r   r     s    zCodeNode.__repr__N)r   )r   r   r   r   r   r   r     s   

r   c                   @   s&   e Zd Zdd Zd	ddZdd ZdS )
rl   c                 C   s
   || _ d S r   r   )r!   r   r   r   r   r"     s    zStatementNode.__init__r   c                 C   s
   || j  S r   r   r   r   r   r   rF     s    zStatementNode.emitc                 C   s   dt | j S )Nz
<stmt: %s>)r   r   r    r   r   r   r     s    zStatementNode.__repr__N)r   r   r   r   r   r   rl     s   
rl   c                   @   s   e Zd ZdS )IfNodeNr   r   r   r   r   r   r   r     s   r   c                   @   s   e Zd ZdS )ElseNodeNr   r   r   r   r   r     s   r   c                   @   s   e Zd ZdS )ElifNodeNr   r   r   r   r   r     s   r   c                   @   s   e Zd Zdd ZdddZdS )DefNodec                 O   sZ   t j| g|R i | tdd}d|_| jjd| tdd}d|_| jj| d S )Nr   z/self = TemplateResult(); extend_ = self.extend
r   zreturn self
)r   r"   r   r   r)   r_   insertrR   )r!   r   kwr   r   r   r   r"     s    

zDefNode.__init__r   c                 C   s2   | j | }|| j | j|t | }|d | S )Nz__lineoffset__ -= 3
r   r   r   r   r   rF     s    
zDefNode.emitN)r   )r   r   r   r"   rF   r   r   r   r   r     s   r   c                   @   s$   e Zd Zdd Zdd Zdd ZdS )rU   c                 C   s   || _ || _d S r   r$   rY   r!   r$   rY   r   r   r   r"     s    zVarNode.__init__c                 C   s   |dt | j| jf  S )Nzself[%s] = %s
)r   r$   rY   r!   r   r   r   r   r   rF     s    zVarNode.emitc                 C   s   d| j | jf S )Nz<var: %s = %s>r   r    r   r   r   r     s    zVarNode.__repr__Nr   r   r   r   r   rU     s   rU   c                   @   s*   e Zd ZdZdd Zd
ddZdd Zd	S )r^   zSuite is a list of sections.c                 C   s
   || _ d S r   )r_   )r!   r_   r   r   r   r"     s    zSuiteNode.__init__r   c                    s    dd  fdd| jD  S )Nr   r   c                    s   g | ]}|  qS r   rE   )r@   sr   r   r   r   rB     rC   z"SuiteNode.emit.<locals>.<listcomp>)rT   r_   r   r   r   r   rF     s    zSuiteNode.emitc                 C   s
   t | jS r   )r   r_   r    r   r   r   r     s    zSuiteNode.__repr__N)r   )r   r   r   r   r"   rF   r   r   r   r   r   r^     s   
r^   )forwhileifelifelsedefr   )passbreakcontinuereturn)#dict	enumeratefloatintr   listlongreversedsetslicetuplexrangeabsallanycallablechrcmpdivmodfilterhexid
isinstancer   rK   maxr   octordpowrangeTrueFalseNone
__import__c                 C   s$   g | ]}|t jv r|tt |fqS r   )builtins__dict__getattr)r@   r$   r   r   r   rB     s   
rB   c                   @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )ForLoopa  
    Wrapper for expression in for stament to support loop.xxx helpers.

        >>> loop = ForLoop()
        >>> for x in loop.setup(['a', 'b', 'c']):
        ...     print(loop.index, loop.revindex, loop.parity, x)
        ...
        1 3 odd a
        2 2 even b
        3 1 odd c
        >>> loop.index
        Traceback (most recent call last):
            ...
        AttributeError: index
    c                 C   s
   d | _ d S r   )_ctxr    r   r   r   r"   *  s    zForLoop.__init__c                 C   s$   | j d u rt|nt| j |S d S r   )r  AttributeErrorr  r!   r$   r   r   r   __getattr__-  s    

zForLoop.__getattr__c                 C   s   |    | j|S r   )_pushr  setup)r!   seqr   r   r   r  3  s    zForLoop.setupc                 C   s   t | | j| _d S r   )ForLoopContextr  r    r   r   r   r  7  s    zForLoop._pushc                 C   s   | j j| _ d S r   )r  parentr    r   r   r   _pop:  s    zForLoop._popN)	r   r   r   r   r"   r  r  r  r  r   r   r   r   r    s   r  c                   @   s   e Zd ZdZdd Zdd Zedd Zedd Zed	d Z	ed
d Z
edd Zedd Zedd Zedd ZdS )r  z:Stackable context for ForLoop to support nested for loops.c                 C   s   || _ || _d S r   )_forloopr  )r!   Zforloopr  r   r   r   r"   A  s    zForLoopContext.__init__c                 c   sT   zt || _W n   d| _Y n0 d| _|D ]}|  jd7  _|V  q,| j  d S )Nr   r   )rK   lengthr   r  r  )r!   r  r   r   r   r   r  E  s    zForLoopContext.setupc                 C   s
   | j d S r   r   r    r   r   r   r   Q  rC   zForLoopContext.<lambda>c                 C   s
   | j dkS r   r  r    r   r   r   r   R  rC   c                 C   s   | j | jkS r   )r   r  r    r   r   r   r   S  rC   c                 C   s   | j d dkS )Nr;   r   r  r    r   r   r   r   T  rC   c                 C   s   | j d dkS )Nr;   r   r  r    r   r   r   r   U  rC   c                 C   s   ddg| j  S )Noddeven)r  r    r   r   r   r   V  rC   c                 C   s   | j | j S r   r  r   r    r   r   r   r   W  rC   c                 C   s   | j | j d S r   r  r    r   r   r   r   X  rC   N)r   r   r   r   r"   r  propertyZindex0firstlastr  r  ZparityZ	revindex0Zrevindexr   r   r   r   r  >  s   r  c                   @   s>   e Zd Zdd Zdd Zdd Zdd Zd	d
 ZdddZdS )BaseTemplatec                 C   s8   || _ || _|| _|| _|r*| || _n
dd | _d S )Nc                   S   s   dS Nr   r   r   r   r   r   r   d  rC   z'BaseTemplate.__init__.<locals>.<lambda>)filenamer   _globals	_builtins_compiler   )r!   r   r$  r   globalsr  r   r   r   r"   \  s    zBaseTemplate.__init__c                 C   s&   |  | jpi | j}t|| |d S )Nr   )make_envr%  r&  exec)r!   r   envr   r   r   r'  f  s    
zBaseTemplate._compilec                 O   s   d}| j |i |S )NT)r   )r!   r   r   __hidetraceback__r   r   r   __call__l  s    zBaseTemplate.__call__c                 C   s   t ||tt| j| jdS )N)__builtins__r  TemplateResultZescape_Zjoin_)r   r  r/  _escape_join)r!   r(  r  r   r   r   r)  p  s    zBaseTemplate.make_envc                 G   s
   d |S r#  )rT   r   r   r   r   r1  z  s    zBaseTemplate._joinFc                 C   s,   |d u rd}t |}|r(| jr(| |}|S r#  )r   r   r   r   r   r   r0  }  s    

zBaseTemplate._escapeN)F)	r   r   r   r"   r'  r-  r)  r1  r0  r   r   r   r   r"  [  s   

r"  c                   @   st   e Zd ZddddZeeedZi Zddd	Zd
d Zdd Z	e
e	Z	dd ZdddZe
eZdd Zdd ZdS )r
   ztext/html; charset=utf-8z$application/xhtml+xml; charset=utf-8z
text/plain).html.xhtmlz.txt)r2  r3  z.xmlr#   Nc           
      C   s   |pg | _ t|}| ||}tj|\}}	|p@| j|	d }| j	|	d | _
|d u r`| j}|d u rlt}tj| |||||d d S )N)r   r$  r   r(  r  )
extensionsr
   normalize_textcompile_templateospathsplitextFILTERSgetCONTENT_TYPEScontent_typer(  TEMPLATE_BUILTINSr"  r"   )
r!   r   r$  r   r(  r  r4  r   r\   extr   r   r   r"     s$    	

zTemplate.__init__c                 C   s   d | jj| jS )z{
        >>> Template(text='Template text', filename='burndown_chart.html')
        <Template burndown_chart.html>
        z<{} {}>)format	__class__r   r$  r    r   r   r   r     s    zTemplate.__repr__c                 C   sb   |  dd dd } | ds*| d7 } d}t| trR| |rR| t|d } |  dd} | S )z>Normalizes template text by correcting 
, tabs and BOM chars.z
r   u   ï»¿Nz\$re   )r   
expandtabsrb   r  strr+   rK   )r   BOMr   r   r   r5    s    
zTemplate.normalize_textc                 O   sJ   d}ddl m} d|jv r2| jr2|jd| jdd tj| g|R i |S )NTr   )webapiheaderszContent-Type)unique)r   rF  ctxr=  headerr"  r-  )r!   r   r   r,  Zwebr   r   r   r-    s
    zTemplate.__call__c                 C   s.   |pt  }|| |}|jdd }t|S )Nr   )r   )r   r*   rF   r,   r   )r   r$  parserrootnoder   r   r   r   generate_code  s    
zTemplate.generate_codec                 C   s   t  }| jD ]}||}q|S r   )r   r4  )r!   pr?  r   r   r   create_parser  s    

zTemplate.create_parserc                 C   s   t j|||  d}dd }zt||d}W nT ty } z<| jdt|j|j||j|jd f 7  _ W Y d }~n
d }~0 0 t	
||}t || |S )N)rK  c                 S   s2   zt | dd  }|| W S    Y d S 0 d S )Nutf-8r   )r   readrO   )r$  linenor[   r   r   r   get_source_line  s
    
z2Template.compile_template.<locals>.get_source_liner*  z5

Template traceback:
    File %s, line %s
        %sr   )r
   rM  rO  r   rL   msgr   r$  rS  astr*   SafeVisitorwalk)r!   Ztemplate_stringr$  r   rT  Zcompiled_codeerrZast_noder   r   r   r6    s     

zTemplate.compile_template)r#   NNNN)N)r   r   r   r<  r   r:  r(  r"   r   r5  staticmethodr-  rM  rO  r6  r   r   r   r   r
     s(        
	
	r
   c                   @   s$   e Zd Zdd Zdd Zdd ZdS )CompiledTemplatec                 C   s   t | d| || _d S r#  )r
   r"   r   )r!   fr$  r   r   r   r"     s    zCompiledTemplate.__init__c                 G   s   d S r   r   r!   r   r   r   r   r6    s    z!CompiledTemplate.compile_templatec                 G   s   d S r   r   r]  r   r   r   r'  	  s    zCompiledTemplate._compileN)r   r   r   r"   r6  r'  r   r   r   r   r[    s   r[  c                   @   sL   e Zd ZdZdddZdddZdd	 Zd
d Zdd Zdd Z	dd Z
dS )r   a1  The most preferred way of using templates.

        render = web.template.render('templates')
        print render.foo()

    Optional parameter can be `base` can be used to pass output of
    every template through the base template.

        render = web.template.render('templates', base='layout')
    	templatesNc                    s^   |_ |_|d u r"tdd }|r.i _nd _ rTt dsT fdd_n _d S )NdebugFr-  c                    s     | S r   )	_template)pagebaser!   r   r   r   '  rC   z!Render.__init__.<locals>.<lambda>)_loc	_keywordsr	   r;  _cachehasattr_base)r!   loccacherc  r   r   rb  r   r"     s    zRender.__init__c                 C   s0   d| j vri | j d< |s|j}|| j d |< dS )z(Add a global to this rendering instance.r(  N)re  r   )r!   objr$   r   r   r   _add_global+  s
    

zRender._add_globalc                 C   sB   t j| j|}t j|r$d|fS | |}|r:d|fS dS d S )Ndirfile)noneN)r7  r8  rT   rd  isdir	_findfile)r!   r$   r8  r   r   r   _lookup3  s    
zRender._lookupc                 C   s   |  |\}}|dkr6t|f| jd u| jd| jS |dkrt|dd*}t| fd|i| jW  d    S 1 sz0    Y  ntd| d S )Nrm  rj  rc  rn  rP  rQ  r$  zNo template named )	rr  r   rf  rh  re  r   r
   rR  r  )r!   r$   kindr8  Z	tmpl_filer   r   r   _load_template>  s    :zRender._load_templatec                 C   sB   dd t  |d D }|  |s6tj|r6|g}|o@|d S )Nc                 S   s   g | ]}| d s|qS )~)rb   r@   r\  r   r   r   rB   L  s   z$Render._findfile.<locals>.<listcomp>z.*r   )globsortr7  r8  exists)r!   Zpath_prefixrN  r   r   r   rq  K  s    zRender._findfilec                 C   s<   | j d ur.|| j vr$| || j |< | j | S | |S d S r   )rf  ru  r  r   r   r   r`  X  s
    


zRender._templatec                    s:     | jr,ttr, fdd}|S   |S d S )Nc                     s     | i |S r   )rh  )r   r   r!   r   r   r   templated  s    z$Render.__getattr__.<locals>.template)r`  rh  r  r
   )r!   r$   r|  r   r{  r   r  `  s
    
zRender.__getattr__)r^  NN)N)r   r   r   r   r"   rl  rr  ru  rq  r`  r  r   r   r   r   r     s   

r   c                   @   s    e Zd ZeZdd Zdd ZdS )
GAE_Renderc                 O   s   t jj| |g|R i | dd l}t||jr8|| _n$|ddd}t	|d d dg| _| jj
|dt | jj
tj | jj
|di  d S )Nr   /rs   rA   r  r(  )r}  superr"   typesr  
ModuleTypemodr   r   r
  r  updater;  r>  r
   r(  )r!   ri  r   r   r  r$   r   r   r   r"   p  s    zGAE_Render.__init__c                 C   sH   t | j|}dd l}t||jr@t|f| jd u| jd| jS |S d S )Nr   rs  )	r  r  r  r  r  r}  rf  rh  re  )r!   r$   r   r  r   r   r   ru    s    zGAE_Render._load_templateN)r   r   r   r   r  r"   ru  r   r   r   r   r}  l  s   r}  )	appenginec                 K   s    t t| dd fd| i|S )z,Creates a template from the given file path.rP  rQ  r$  )r
   r   rR  )r8  r   r   r   r   r     s    r   c              	   C   sZ  t | D ]H\}}}dd |D }|dd D ]}|dr0|| q0tt j|dddd}|d	 |r|d
d|  |d |D ]}t j||}d|v r|dd\}}	n|}t|dd	 }
t
|
}
t
|
|}|d|d}|| |d |d||t|f  |d||f  t
t|dd	 | q|  q
dS )z"Compiles templates to python code.c                 S   s.   g | ]&}| d s|ds| ds|qS )rs   rv  __init__.py)r+   rb   rw  r   r   r   rB     s
   


z%compile_templates.<locals>.<listcomp>Nrs   r  wrP  rQ  zDfrom web.template import CompiledTemplate, ForLoop, TemplateResult

zimport rI   r   r   r   z

z%s = CompiledTemplate(%s, %s)
z(join_ = %s._join; escape_ = %s._escape

)r7  rX  r+   remover   r8  rT   writerM   rR  r
   r5  rM  r   r   close)rootdirpathdirnames	filenamesdr   r\  r8  r$   r\   r   r   r   r   r   compile_templates  s:    




r  c                   @   s   e Zd ZdS )r   Nr   r   r   r   r   r     s   r   c                   @   s   e Zd ZdZdS )r   z8The template seems to be trying to do something naughty.N)r   r   r   r   r   r   r   r   r     s   r   )VAddAndAssign	Attribute	AugAssignAugLoadAugStoreBinOpBitAndBitOrBitXorBoolOpBreakCallClassDefCompareConstantContinueDelDeleteDictDictCompDivEllipsisEqExceptHandlerExpr
ExpressionExtSliceFloorDivForFunctionDefGeneratorExpGtGtEIfIfExpInIndexInteractiveInvertIsIsNot	JoinedStrLShiftLambdaListListCompLoadLtLtEModModuleMultNameNameConstantNotNotEqNotInNumOrParamPassPowRShiftReturnSetSetCompSliceStoreStrSub	SubscriptSuiteTupleUAddUSubUnaryOpWhileWithYieldaliasarg	argumentscomprehensionr   c                       s   e Zd ZdZ fddZdd Z fddZ fdd	Zd
d Zdd Z	 fddZ
dd Zdd Zdd Zdd Zdd Zdd Z  ZS )rW  a  
    Make sure code is safe by walking through the AST.

    Code considered unsafe if:
        * it has restricted AST nodes (only nodes defined in ALLOWED_AST_NODES are allowed)
        * it is trying to assign to attributes
        * it is trying to access resricted attributes

    Adopted from http://www.zafar.se/bkz/uploads/safe.txt (public domain, Babar K. Zafar)
        * Using ast rather than compiler tree, for jython and Py3 support since Py2.6
        * Simplified with ast.NodeVisitor class
    c                    s    t t| j|i | g | _dS )zBInitialize visitor by generating callbacks for all AST node types.N)r  rW  r"   errors)r!   argskwargsrA  r   r   r"   =  s    zSafeVisitor.__init__c                 C   s4   || _ | | | jr0tddd | jD dS )zJValidate each node in AST and raise SecurityError if the code is not safe.r   c                 S   s   g | ]}t |qS r   )rD  )r@   rY  r   r   r   rB   G  rC   z$SafeVisitor.walk.<locals>.<listcomp>N)r$  visitr  r   rT   )r!   treer$  r   r   r   rX  B  s    
zSafeVisitor.walkc                    s2   t |j}|tvr| || tt| | d S r   )r|   r   ALLOWED_AST_NODES	fail_namer  rW  generic_visit)r!   rH   nodenamer  r   r   r  I  s    
zSafeVisitor.generic_visitc                    s4   |  |}| |r | || tt| | d S r   )get_node_attris_unallowed_attrfail_attributer  rW  r  )r!   rH   attrnamer  r   r   visit_AttributeO  s    

zSafeVisitor.visit_Attributec                 C   s   |  | d S r   )check_assign_targetsr!   rH   r   r   r   visit_AssignU  s    zSafeVisitor.visit_Assignc                 C   s   |  | d S r   )check_assign_targetr  r   r   r   visit_AugAssignX  s    zSafeVisitor.visit_AugAssignc                    s*   |j D ]}| | qtt| | d S r   )targetsr  r  rW  r  )r!   rH   targetr  r   r   r  [  s    
z SafeVisitor.check_assign_targetsc                 C   s,   t |j}|dkr(| |}| || d S )Nr  )r|   r   r  r  )r!   Z
targetnodeZ
targetnamer  r   r   r   r  `  s    

zSafeVisitor.check_assign_targetc                 C   s.   |  |}td| j||f }| j| d S )Nz.%s:%d - execution of '%s' statements is deniedget_node_linenor   r$  r  rR   )r!   rH   r  rS  er   r   r   r  g  s    

zSafeVisitor.fail_namec                 C   s.   |  |}td| j||f }| j| d S )Nz*%s:%d - access to attribute '%s' is deniedr  )r!   rH   r  rS  r  r   r   r   r  o  s    

zSafeVisitor.fail_attributec                 C   s   | dp| dp| dS )Nr\   Zfunc_Zim_)r+   r  r   r   r   r  x  s    zSafeVisitor.is_unallowed_attrc                 C   s   d|j v r|jpd S )Nattr)_fieldsr  r  r   r   r   r  }  s    zSafeVisitor.get_node_attrc                 C   s   |j r|j pdS r   )rS  r  r   r   r   r    s    zSafeVisitor.get_node_lineno)r   r   r   r   r"   rX  r  r  r  r  r  r  r  r  r  r  r  __classcell__r   r   r  r   rW  /  s   	rW  c                   @   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd ZdS )r/  a  Dictionary like object for storing template output.

    The result of a template execution is usually a string, but sometimes it
    contains attributes set using $var. This class provides a simple
    dictionary like interface for storing the output of the template and the
    attributes. The output is stored with a special key __body__. Converting
    the TemplateResult to string or unicode returns the value of __body__.

    When the template is in execution, the output is generated part by part
    and those parts are combined at the end. Parts are added to the
    TemplateResult by calling the `extend` method and the parts are combined
    seamlessly when __body__ is accessed.

        >>> d = TemplateResult(__body__='hello, world', x='foo')
        >>> print(d)
        hello, world
        >>> d.x
        'foo'
        >>> d = TemplateResult()
        >>> d.extend([u'hello', u'world'])
        >>> d
        <TemplateResult: {'__body__': u'helloworld'}>
    c                 O   sL   t |i || jd< | jdd g | jd< | jj| jd< | jdd  d S )N_d__body__r   _partsrP   )r   r  r  
setdefaultr  rP   )r!   r   r   r   r   r   r"     s
    
zTemplateResult.__init__c                 C   s
   | j  S r   )r  keysr    r   r   r   r    s    zTemplateResult.keysc                 C   sN   | j rJd| j }g | j dd< | jd}|r@|| | jd< n
|| jd< dS )z+Prepare value of __body__ by joining parts.r   Nr  )r  rT   r  r;  )r!   rY   bodyr   r   r   _prepare_body  s    zTemplateResult._prepare_bodyc                 C   s   |dkr|    | j| S Nr  r  r  r  r   r   r   __getitem__  s    zTemplateResult.__getitem__c                 C   s   |dkr|    | j||S r  )r  r  __setitem__r   r   r   r   r    s    zTemplateResult.__setitem__c                 C   s   |dkr|    | j|S r  )r  r  __delitem__r  r   r   r   r    s    zTemplateResult.__delitem__c              
   C   s<   z
| | W S  t y6 } zt|W Y d }~n
d }~0 0 d S r   KeyErrorr  r!   keykr   r   r   r    s    
zTemplateResult.__getattr__c                 C   s   || |< d S r   r   )r!   r  rY   r   r   r   __setattr__  s    zTemplateResult.__setattr__c              
   C   s<   z
| |= W n, t y6 } zt|W Y d }~n
d }~0 0 d S r   r  r  r   r   r   __delattr__  s    
zTemplateResult.__delattr__c                 C   s   |    | d S r  r  r    r   r   r   __unicode__  s    zTemplateResult.__unicode__c                 C   s   |    | d S r  r  r    r   r   r   __str__  s    zTemplateResult.__str__c                 C   s   |    d| j S )Nz<TemplateResult: %s>r	  r    r   r   r   r     s    zTemplateResult.__repr__c                 C   s
   | j  S r   )r  __len__r    r   r   r   r    s    zTemplateResult.__len__c                 c   s*   | j  D ]}|dkr|   |V  q
d S r  )r  __iter__r  )r!   r   r   r   r   r    s    zTemplateResult.__iter__N)r   r   r   r   r"   r  r  r
  r  r  r  r  r  r  r  r   r  r  r   r   r   r   r/    s   	r/  c                   C   s   dS )az  Doctest for testing template module.

    Define a utility function to run template test.

        >>> class TestResult:
        ...     def __init__(self, t): self.t = t
        ...     def __getattr__(self, name): return getattr(self.t, name)
        ...     def __repr__(self): return str(self.t)
        ...
        >>> def t(code, **keywords):
        ...     tmpl = Template(code, **keywords)
        ...     return lambda *a, **kw: TestResult(tmpl(*a, **kw))
        ...

    Simple tests.

        >>> t('1')()
        u'1\n'
        >>> t('$def with ()\n1')()
        u'1\n'
        >>> t('$def with (a)\n$a')(1)
        u'1\n'
        >>> t('$def with (a=0)\n$a')(1)
        u'1\n'
        >>> t('$def with (a=0)\n$a')(a=1)
        u'1\n'

    Test complicated expressions.

        >>> t('$def with (x)\n$x.upper()')('hello')
        u'HELLO\n'
        >>> t('$(2 * 3 + 4 * 5)')()
        u'26\n'
        >>> t('${2 * 3 + 4 * 5}')()
        u'26\n'
        >>> t('$def with (limit)\nkeep $(limit)ing.')('go')
        u'keep going.\n'
        >>> t('$def with (a)\n$a.b[0]')(storage(b=[1]))
        u'1\n'

    Test html escaping.

        >>> t('$def with (x)\n$x', filename='a.html')('<html>')
        u'&lt;html&gt;\n'
        >>> t('$def with (x)\n$x', filename='a.txt')('<html>')
        u'<html>\n'

    Test if, for and while.

        >>> t('$if 1: 1')()
        u'1\n'
        >>> t('$if 1:\n    1')()
        u'1\n'
        >>> t('$if 1:\n    1\\')()
        u'1'
        >>> t('$if 0: 0\n$elif 1: 1')()
        u'1\n'
        >>> t('$if 0: 0\n$elif None: 0\n$else: 1')()
        u'1\n'
        >>> t('$if 0 < 1 and 1 < 2: 1')()
        u'1\n'
        >>> t('$for x in [1, 2, 3]: $x')()
        u'1\n2\n3\n'
        >>> t('$def with (d)\n$for k, v in d.items(): $k')({1: 1})
        u'1\n'
        >>> t('$for x in [1, 2, 3]:\n\t$x')()
        u'    1\n    2\n    3\n'
        >>> t('$def with (a)\n$while a and a.pop():1')([1, 2, 3])
        u'1\n1\n1\n'

    The space after : must be ignored.

        >>> t('$if True: foo')()
        u'foo\n'

    Test loop.xxx.

        >>> t("$for i in range(5):$loop.index, $loop.parity")()
        u'1, odd\n2, even\n3, odd\n4, even\n5, odd\n'
        >>> t("$for i in range(2):\n    $for j in range(2):$loop.parent.parity $loop.parity")()
        u'odd odd\nodd even\neven odd\neven even\n'

    Test assignment.

        >>> t('$ a = 1\n$a')()
        u'1\n'
        >>> t('$ a = [1]\n$a[0]')()
        u'1\n'
        >>> t('$ a = {1: 1}\n$list(a.keys())[0]')()
        u'1\n'
        >>> t('$ a = []\n$if not a: 1')()
        u'1\n'
        >>> t('$ a = {}\n$if not a: 1')()
        u'1\n'
        >>> t('$ a = -1\n$a')()
        u'-1\n'
        >>> t('$ a = "1"\n$a')()
        u'1\n'

    Test comments.

        >>> t('$# 0')()
        u'\n'
        >>> t('hello$#comment1\nhello$#comment2')()
        u'hello\nhello\n'
        >>> t('$#comment0\nhello$#comment1\nhello$#comment2')()
        u'\nhello\nhello\n'

    Test unicode.

        >>> t('$def with (a)\n$a')(u'\u203d')
        u'\u203d\n'
        >>> t(u'$def with (a)\n$a $:a')(u'\u203d')
        u'\u203d \u203d\n'
        >>> t(u'$def with ()\nfoo')()
        u'foo\n'
        >>> def f(x): return x
        ...
        >>> t(u'$def with (f)\n$:f("x")')(f)
        u'x\n'
        >>> t('$def with (f)\n$:f("x")')(f)
        u'x\n'

    Test dollar escaping.

        >>> t("Stop, $$money isn't evaluated.")()
        u"Stop, $money isn't evaluated.\n"
        >>> t("Stop, \$money isn't evaluated.")()
        u"Stop, $money isn't evaluated.\n"

    Test space sensitivity.

        >>> t('$def with (x)\n$x')(1)
        u'1\n'
        >>> t('$def with(x ,y)\n$x')(1, 1)
        u'1\n'
        >>> t('$(1 + 2*3 + 4)')()
        u'11\n'

    Make sure globals are working.

        >>> t('$x')()
        Traceback (most recent call last):
            ...
        NameError: global name 'x' is not defined
        >>> t('$x', globals={'x': 1})()
        u'1\n'

    Can't change globals.

        >>> t('$ x = 2\n$x', globals={'x': 1})()
        u'2\n'
        >>> t('$ x = x + 1\n$x', globals={'x': 1})()
        Traceback (most recent call last):
            ...
        UnboundLocalError: local variable 'x' referenced before assignment

    Make sure builtins are customizable.

        >>> t('$min(1, 2)')()
        u'1\n'
        >>> t('$min(1, 2)', builtins={})()
        Traceback (most recent call last):
            ...
        NameError: global name 'min' is not defined

    Test vars.

        >>> x = t('$var x: 1')()
        >>> x.x
        u'1'
        >>> x = t('$var x = 1')()
        >>> x.x
        1
        >>> x = t('$var x:  \n    foo\n    bar')()
        >>> x.x
        u'foo\nbar\n'

    Test BOM chars.

        >>> t('\xef\xbb\xbf$def with(x)\n$x')('foo')
        u'foo\n'

    Test for with weird cases.

        >>> t('$for i in range(10)[1:5]:\n    $i')()
        u'1\n2\n3\n4\n'
        >>> t("$for k, v in sorted({'a': 1, 'b': 2}.items()):\n    $k $v", globals={'sorted':sorted})()
        u'a 1\nb 2\n'

    Test for syntax error.

        >>> try:
        ...     t("$for k, v in ({'a': 1, 'b': 2}.items():\n    $k $v")()
        ... except SyntaxError:
        ...     print("OK")
        ... else:
        ...     print("Expected SyntaxError")
        ...
        OK

    Test datetime.

        >>> import datetime
        >>> t("$def with (date)\n$date.strftime('%m %Y')")(datetime.datetime(2009, 1, 1))
        u'01 2009\n'

    Nr   r   r   r   r   r     s     Rr   __main__z	--compiler;   )Fr   rV  rx  r7  sysr   ior   r  netr   utilsr   r   r   r   rF  r	   __all__collections.abcr   r   r   r   r'   rS   r   r   rd   r   r   r   r   rl   r   r   r   r   rU   r^   r   r   ZTEMPLATE_BUILTIN_NAMESr   r>  r  r  r"  r
   r[  r   r}  r   Zgoogler  ImportErrorr   r  	Exceptionr   r   r  NodeVisitorrW  r/  r   r   argvdoctesttestmodr   r   r   r   <module>   s      4
&	%,z_0[Ud U
