a
    mzf:                     @   s@  d 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mZm	Z	m
Z
mZmZ zddlmZ ddlmZ W n& ey   ddlZddlmZ Y n0 zddlZW n ey   dZY n0 zddlmZmZ W n& ey   ddlZejZe ZY n0 g d	Zd
ZeeZdZdZ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e&Z'e'Z(G dd de&Z)G dd dZ*e*Z+dd Z,dd Z-d d! Z.d"d# Z/d$d% Z0d\d'd(Z1d)d* Z2G d+d, d,Z3G d-d. d.e3Z4G d/d0 d0e3Z5G d1d2 d2Z6G d3d4 d4Z7G d5d6 d6e7Z8G d7d8 d8e7Z9d]d9d:Z:G d;d< d<e7Z;G d=d> d>e7Z<G d?d@ d@e7Z=G dAdB dBe7Z>dCdD Z?i Z@d^dEdFZAdGdH ZBeBdIe9 eBdJe8 eBdKe; eBdLe< eBdMe= eBdNe> dOdP ZCG dQdR dRe&ZDG dSdT dTZEG dUdV dVe&ZFdWdX ZGdYdZ ZHeId[kr<ddlJZJeJK  eG  eH  dS )_z
Database API
(part of web.py)
    N   )	iteritems)iterssafestrsafeunicodestoragethreadeddict)parse)unquote)debugconfig)UnknownParamstyle	UnknownDBTransactionErrorsqllistsqlorsreparamsqlquoteSQLQuerySQLParamsqlparam
SQLLiteral
sqlliteraldatabaseDBa  [ \f\t]*(\\\r?\n[ \f\t]*)*(#[^\r\n]*)?(((\d+[jJ]|((\d+\.\d*|\.\d+)([eE][-+]?\d+)?|\d+[eE][-+]?\d+)[jJ])|((\d+\.\d*|\.\d+)([eE][-+]?\d+)?|\d+[eE][-+]?\d+)|(0[xX][\da-fA-F]+[lL]?|0[bB][01]+[lL]?|(0[oO][0-7]+)|(0[0-7]*)[lL]?|[1-9]\d*[lL]?))|((\*\*=?|>>=?|<<=?|<>|!=|//=?|[+\-*/%&|^=<>]=?|~)|[][(){}]|(\r?\n|[:;.,`@]))|([uUbB]?[rR]?'[^\n'\\]*(?:\\.[^\n'\\]*)*'|[uUbB]?[rR]?"[^\n"\\]*(?:\\.[^\n"\\]*)*")|[a-zA-Z_]\w*))psycopg2)pymysqlMySQLdbmysql.connector)sqlite3pysqlite2.dbapi2sqlitec                   @   s   e Zd ZdZdS )r   zraised for unsupported dbmsN__name__
__module____qualname____doc__ r'   r'   4/var/www/media/lib/python3.9/site-packages/web/db.pyr   >   s   r   c                   @   s   e Zd Zdd Zdd ZdS )
_ItplErrorc                 C   s   t |  || _|| _d S N)
ValueError__init__textpos)selfr-   r.   r'   r'   r(   r,   E   s    
z_ItplError.__init__c                 C   s   dt | j| jf S )Nz&unfinished expression in %s at char %d)reprr-   r.   r/   r'   r'   r(   __str__J   s    z_ItplError.__str__N)r#   r$   r%   r,   r2   r'   r'   r'   r(   r)   D   s   r)   c                   @   s   e Zd ZdS )r   N)r#   r$   r%   r'   r'   r'   r(   r   N   s   r   c                   @   s   e Zd ZdZdS )r   zl
    raised for unsupported db paramstyles

    (currently supported: qmark, numeric, format, pyformat)
    Nr"   r'   r'   r'   r(   r   R   s   r   c                   @   sX   e Zd ZdZdg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S )r   a  
    Parameter in SQLQuery.

        >>> q = SQLQuery(["SELECT * FROM test WHERE name=", SQLParam("joe")])
        >>> q
        <sql: "SELECT * FROM test WHERE name='joe'">
        >>> q.query()
        'SELECT * FROM test WHERE name=%s'
        >>> q.values()
        ['joe']
    valuec                 C   s
   || _ d S r*   )r3   r/   r3   r'   r'   r(   r,   k   s    zSQLParam.__init__pyformatc                 C   s8   |dkrdS |dkrdS |d u s(|dv r,dS t |d S )Nqmark?numeric:1formatr5   %s)r   )r/   
paramstyler'   r'   r(   
get_markern   s    zSQLParam.get_markerc                 C   s
   t | gS r*   r   r1   r'   r'   r(   sqlqueryw   s    zSQLParam.sqlqueryc                 C   s   |   | S r*   r@   r/   otherr'   r'   r(   __add__z   s    zSQLParam.__add__c                 C   s   ||    S r*   rA   rB   r'   r'   r(   __radd__}   s    zSQLParam.__radd__c                 C   s
   t | jS r*   )strr3   r1   r'   r'   r(   r2      s    zSQLParam.__str__c                 C   s   t |to|j| jkS r*   
isinstancer   r3   rB   r'   r'   r(   __eq__   s    zSQLParam.__eq__c                 C   s   dt | j S )Nz<param: %s>)r0   r3   r1   r'   r'   r(   __repr__   s    zSQLParam.__repr__N)r5   )r#   r$   r%   r&   	__slots__r,   r>   r@   rD   rE   r2   rI   rJ   r'   r'   r'   r(   r   \   s   
	r   c                   @   s   e Zd ZdZdg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dZdd Zd#ddZeeZdd Zdd Zdd Zdd  ZdS )$r   aI  
    You can pass this sort of thing as a clause in any db function.
    Otherwise, you can pass a dictionary to the keyword argument `vars`
    and the function will call reparam for you.

    Internally, consists of `items`, which is a list of strings and
    SQLParams, which get concatenated to produce the actual query.
    itemsNc                 C   s   |du rg | _ nFt|tr"|| _ n4t|tr6|g| _ n t|trNt|j | _ n|g| _ t| j D ],\}}t|tr`t|jtr`|jj| j |< q`dS )a_  Creates a new SQLQuery.

        >>> SQLQuery("x")
        <sql: 'x'>
        >>> q = SQLQuery(['SELECT * FROM ', 'test', ' WHERE x=', SQLParam(1)])
        >>> q
        <sql: 'SELECT * FROM test WHERE x=1'>
        >>> q.query(), q.values()
        ('SELECT * FROM test WHERE x=%s', [1])
        >>> SQLQuery(SQLParam(1))
        <sql: '1'>
        N)	rL   rH   listr   r   	enumerater3   r   v)r/   rL   iitemr'   r'   r(   r,      s    



zSQLQuery.__init__c                 C   s   | j | d S r*   )rL   appendr4   r'   r'   r(   rR      s    zSQLQuery.appendc                 C   s6   t |tr|g}nt |tr$|j}ntS t| j| S r*   rH   rF   r   rL   NotImplementedr/   rC   rL   r'   r'   r(   rD      s    

zSQLQuery.__add__c                 C   s6   t |tr|g}nt |tr$|j}ntS t|| j S r*   rS   rU   r'   r'   r(   rE      s    

zSQLQuery.__radd__c                 C   s>   t |ttfr| j| nt |tr6| j|j ntS | S r*   )rH   rF   r   rL   rR   r   extendrT   rB   r'   r'   r(   __iadd__   s    
zSQLQuery.__iadd__c                 C   s   t |  S r*   )lenqueryr1   r'   r'   r(   __len__   s    zSQLQuery.__len__c                 C   s   t |to|j| jkS r*   )rH   r   rL   rB   r'   r'   r(   rI      s    zSQLQuery.__eq__c                 C   st   g }| j D ]^}t|tr2||}|t| q
t|}|dv r^d|v r^d|vr^|dd}|| q
d|S )a/  
        Returns the query part of the sql query.
            >>> q = SQLQuery(["SELECT * FROM test WHERE name=", SQLParam('joe')])
            >>> q.query()
            'SELECT * FROM test WHERE name=%s'
            >>> q.query(paramstyle='qmark')
            'SELECT * FROM test WHERE name=?'
        r:   %z%% )rL   rH   r   r>   rR   r   replacejoin)r/   r=   sxr'   r'   r(   rY      s    	


zSQLQuery.queryc                 C   s   dd | j D S )z
        Returns the values of the parameters used in the sql query.
            >>> q = SQLQuery(["SELECT * FROM test WHERE name=", SQLParam('joe')])
            >>> q.values()
            ['joe']
        c                 S   s   g | ]}t |tr|jqS r'   rG   ).0rP   r'   r'   r(   
<listcomp>       z#SQLQuery.values.<locals>.<listcomp>)rL   r1   r'   r'   r(   values   s    zSQLQuery.values c                 C   s   |du rt  }|j}|r"|| t| D ]P\}}|dkrL|dkrL|| t|t rd||j q*|dkrpq*q*|| q*|r|| |S )a  
        Joins multiple queries.

        >>> SQLQuery.join(['a', 'b'], ', ')
        <sql: 'a, b'>

        Optionally, prefix and suffix arguments can be provided.

        >>> SQLQuery.join(['a', 'b'], ', ', prefix='(', suffix=')')
        <sql: '(a, b)'>

        If target argument is provided, the items are appended to target
        instead of creating a new SQLQuery.
        Nr   r\   )r   rL   rR   rN   rH   rV   )rL   sepprefixsuffixtargetZtarget_itemsrP   rQ   r'   r'   r(   r^      s     



zSQLQuery.joinc              	   C   sD   z |   tdd |  D  W S  ttfy>   |    Y S 0 d S )Nc                 S   s   g | ]}t |qS r'   )sqlifyra   r`   r'   r'   r(   rb   &  rc   z!SQLQuery._str.<locals>.<listcomp>)rY   tuplerd   r+   	TypeErrorr1   r'   r'   r(   _str$  s     zSQLQuery._strc                 C   s   t |  S r*   )r   rn   r1   r'   r'   r(   r2   *  s    zSQLQuery.__str__c                 C   s   t |  S r*   )r   rn   r1   r'   r'   r(   __unicode__-  s    zSQLQuery.__unicode__c                 C   s   dt t|  S )Nz	<sql: %s>)r0   rF   r1   r'   r'   r(   rJ   0  s    zSQLQuery.__repr__)N)N)re   NNN)r#   r$   r%   r&   rK   r,   rR   rD   rE   rW   rZ   rI   rY   rd   r^   staticmethodrn   r2   ro   rJ   r'   r'   r'   r(   r      s"   	
			
	
%r   c                   @   s    e Zd ZdZdd Zdd ZdS )r   z
    Protects a string from `sqlquote`.

        >>> sqlquote('NOW()')
        <sql: "'NOW()'">
        >>> sqlquote(SQLLiteral('NOW()'))
        <sql: 'NOW()'>
    c                 C   s
   || _ d S r*   rO   )r/   rO   r'   r'   r(   r,   >  s    zSQLLiteral.__init__c                 C   s
   d| j  S )Nz<literal: %r>rq   r1   r'   r'   r(   rJ   A  s    zSQLLiteral.__repr__N)r#   r$   r%   r&   r,   rJ   r'   r'   r'   r(   r   4  s   	r   c                 C   s|   g }| d t| tr"t| } nt| tr8tt| } t| D ](\}}|dkrZ| d | t| q@| d t|S )z
    >>> _sqllist([1, 2, 3])
    <sql: '(1, 2, 3)'>
    >>> _sqllist(set([5, 1, 3, 2]))
    <sql: '(1, 2, 3, 5)'>
    >>> _sqllist((5, 1, 3, 2, 2, 5))
    <sql: '(1, 2, 3, 5)'>
    (r   , ))rR   rH   setrM   rl   rN   r   r   )rd   rL   rP   rO   r'   r'   r(   _sqllistH  s    	





rv   c                 C   sL   t  | |S ]0\}}|r4t||}|t| q|| qt	|dS )a#  
    Takes a string and a dictionary and interpolates the string
    using values from the dictionary. Returns an `SQLQuery` for the result.

        >>> reparam("s = $s", dict(s=True))
        <sql: "s = 't'">
        >>> reparam("s IN $s", dict(s=[1, 2]))
        <sql: 's IN (1, 2)'>
    __builtins__r\   )
SafeEvalsafeevalcopyobject_interpolateevalrR   r   r   r^   )Zstring_
dictionaryresultZlivechunkrO   r'   r'   r(   r   a  s    
   
r   c                 C   sZ   | du rdS | du rdS | du r$dS t | tr6t| S t | tjrNt|  S t| S dS )z
    converts `obj` to its proper SQL version

        >>> sqlify(None)
        'NULL'
        >>> sqlify(True)
        "'t'"
        >>> sqlify(3)
        '3'
    NZNULLTz't'Fz'f')rH   intrF   datetimer0   	isoformat)objr'   r'   r(   rj   z  s    
rj   c                 C   s   t | tr| S d| S dS )z
    Converts the arguments for use in something like a WHERE clause.

        >>> sqllist(['a', 'b'])
        'a, b'
        >>> sqllist('a')
        'a'
    rs   N)rH   rF   r^   )lstr'   r'   r(   r     s    	
r   c                    s|   t |tr:t|}t|}|dkr*tdS |dkr:|d }t |trltdgt fdd|D g  dg S  t| S dS )	a  
    `left is a SQL clause like `tablename.arg = `
    and `lst` is a list of values. Returns a reparam-style
    pair featuring the SQL that ORs together the clause
    for each item in the lst.

        >>> sqlors('foo = ', [])
        <sql: '1=2'>
        >>> sqlors('foo = ', [1])
        <sql: 'foo = 1'>
        >>> sqlors('foo = ', 1)
        <sql: 'foo = 1'>
        >>> sqlors('foo = ', [1,2,3])
        <sql: '(foo = 1 OR foo = 2 OR foo = 3 OR 1=2)'>
    r   z1=2r   rr   c                    s   g | ]} t |d gqS )z OR r   rk   leftr'   r(   rb     rc   zsqlors.<locals>.<listcomp>z1=2)N)rH   r   rM   rX   r   sumr   )r   r   lnr'   r   r(   r     s    

"r    AND c                 C   s   t dd | D |S )a  
    Converts a two-tuple (key, value) iterable `data` to an SQL WHERE clause
    `SQLQuery`.

        >>> sqlwhere((('cust_id', 2), ('order_id',3)))
        <sql: 'cust_id = 2 AND order_id = 3'>
        >>> sqlwhere((('order_id', 3), ('cust_id', 2)), grouping=', ')
        <sql: 'order_id = 3, cust_id = 2'>
        >>> sqlwhere((('a', 'a'), ('b', 'b'))).query()
        'a = %s AND b = %s'
    c                 S   s    g | ]\}}|d  t | qS ) = r   )ra   krO   r'   r'   r(   rb     rc   zsqlwhere.<locals>.<listcomp>)r   r^   )datagroupingr'   r'   r(   sqlwhere  s    r   c                 C   s(   t | tttfrt| S t|  S dS )a8  
    Ensures `a` is quoted properly for use in a SQL query.

        >>> 'WHERE x = ' + sqlquote(True) + ' AND y = ' + sqlquote(3)
        <sql: "WHERE x = 't' AND y = 3">
        >>> 'WHERE x = ' + sqlquote(True) + ' AND y IN ' + sqlquote([2, 3])
        <sql: "WHERE x = 't' AND y IN (2, 3)">
        >>> 'WHERE x = ' + sqlquote(True) + ' AND y IN ' + sqlquote(set([3, 2, 3, 4]))
        <sql: "WHERE x = 't' AND y IN (2, 3, 4)">
        >>> 'WHERE x = ' + sqlquote(True) + ' AND y IN ' + sqlquote((3, 2, 3, 4))
        <sql: "WHERE x = 't' AND y IN (2, 3, 4)">
    N)rH   rM   rl   ru   rv   r   r@   )ar'   r'   r(   r     s    r   c                   @   sN   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZeZ	dddZ
dd ZdS )BaseResultSetz<Base implementation of Result Set, the result of a db query.c                 C   s"   || _ dd |jD | _d| _d S )Nc                 S   s   g | ]}|d  qS )r   r'   rk   r'   r'   r(   rb     rc   z*BaseResultSet.__init__.<locals>.<listcomp>r   )cursordescriptionnames_indexr/   r   r'   r'   r(   r,     s    zBaseResultSet.__init__c                    s.    fdd j  D }  jt|7  _|S )Nc                    s   g | ]}  |qS r'   )_prepare_row)ra   dr1   r'   r(   rb     rc   z&BaseResultSet.list.<locals>.<listcomp>)r   Zfetchallr   rX   )r/   rowsr'   r1   r(   rM     s    zBaseResultSet.listc                 C   s   t tt| j|S r*   )r   dictzipr   r/   rowr'   r'   r(   r     s    zBaseResultSet._prepare_rowc                 C   s   | S r*   r'   r1   r'   r'   r(   __iter__  s    zBaseResultSet.__iter__c                 C   s0   | j  }|d u rt |  jd7  _| |S Nr   )r   fetchoneStopIterationr   r   r   r'   r'   r(   __next__  s
    
zBaseResultSet.__next__Nc                 C   s*   zt t| W S  ty$   | Y S 0 dS )zReturns the first row of this ResultSet or None when there are no
        elements.

        If the optional argument default is specified, that is returned instead
        of None when there are no elements.
        N)nextiterr   )r/   defaultr'   r'   r(   first  s    zBaseResultSet.firstc                 C   sx   || j k rtdt| z:|| j kr>t|  |  j d7  _ q|  j d7  _ t| W S  tyr   tt|Y n0 d S )Nzalready passed r   )r   
IndexErrorrF   r   r   )r/   rP   r'   r'   r(   __getitem__  s    


zBaseResultSet.__getitem__)N)r#   r$   r%   r&   r,   rM   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S )	ResultSetzThe result of a database query.c                 C   s   t | jjS r*   )r   r   rowcountr1   r'   r'   r(   rZ   "  s    zResultSet.__len__N)r#   r$   r%   r&   rZ   r'   r'   r'   r(   r     s   r   c                       s0   e Zd ZdZdd Z fddZdd Z  ZS )SqliteResultSetz\Result Set for sqlite.

    Same functionally as ResultSet except len is not supported.
    c                 C   s   t | | d | _d S r*   )r   r,   _headr   r'   r'   r(   r,   ,  s    zSqliteResultSet.__init__c                    s,   | j d ur|  jd7  _| j S t  S d S r   )r   r   superr   r1   	__class__r'   r(   r   0  s    
zSqliteResultSet.__next__c                 C   s@   | j d u r<zt| | _ |  jd8  _W n ty:   Y dS 0 dS )Nr   FT)r   r   r   r   r1   r'   r'   r(   __bool__7  s    

zSqliteResultSet.__bool__)r#   r$   r%   r&   r,   r   r   __classcell__r'   r'   r   r(   r   &  s   r   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 )TransactionzDatabase transaction.c                    s    | _ t j | _G  fddd}G  fddd}G dd d}| jrp| j drf| | _qx| | _n| | _| j  | j j|  d S )Nc                       s4   e Zd ZdZ fddZ fddZ fddZdS )	z0Transaction.__init__.<locals>.transaction_enginez2Transaction Engine used in top level transactions.c                    s    j dd d S )NFZunloadcommitr1   ctxr'   r(   do_transactN  s    z<Transaction.__init__.<locals>.transaction_engine.do_transactc                    s       d S r*   r   r1   r   r'   r(   	do_commitQ  s    z:Transaction.__init__.<locals>.transaction_engine.do_commitc                    s       d S r*   )rollbackr1   r   r'   r(   do_rollbackT  s    z<Transaction.__init__.<locals>.transaction_engine.do_rollbackNr#   r$   r%   r&   r   r   r   r'   r   r'   r(   transaction_engineK  s   r   c                       s6   e Zd ZdZ fddZdd Zdd Zdd	 Zd
S )z3Transaction.__init__.<locals>.subtransaction_enginez,Transaction Engine used in sub transactions.c                    s"    j  } |t|  d S r*   )dbr   
db_executer   )r/   q	db_cursorr   transaction_countr'   r(   rY   Z  s    
z9Transaction.__init__.<locals>.subtransaction_engine.queryc                 S   s   |  d d S )NzSAVEPOINT webpy_sp_%srY   r1   r'   r'   r(   r   ^  s    z?Transaction.__init__.<locals>.subtransaction_engine.do_transactc                 S   s   |  d d S )NzRELEASE SAVEPOINT webpy_sp_%sr   r1   r'   r'   r(   r   a  s    z=Transaction.__init__.<locals>.subtransaction_engine.do_commitc                 S   s   |  d d S )Nz!ROLLBACK TO SAVEPOINT webpy_sp_%sr   r1   r'   r'   r(   r   d  s    z?Transaction.__init__.<locals>.subtransaction_engine.do_rollbackN)r#   r$   r%   r&   rY   r   r   r   r'   r   r'   r(   subtransaction_engineW  s
   r   c                   @   s    e Zd ZdZdd  Z ZZdS )z*Transaction.__init__.<locals>.dummy_enginezmTransaction Engine used instead of subtransaction_engine
            when sub transactions are not supported.c                 S   s   d S r*   r'   r1   r'   r'   r(   <lambda>k  rc   z3Transaction.__init__.<locals>.dummy_engine.<lambda>Nr   r'   r'   r'   r(   dummy_engineg  s   r   Zignore_nested_transactions)r   rX   transactionsr   getenginer   rR   )r/   r   r   r   r   r'   r   r(   r,   G  s    


zTransaction.__init__c                 C   s   | S r*   r'   r1   r'   r'   r(   	__enter__y  s    zTransaction.__enter__c                 C   s   |d ur|    n|   d S r*   )r   r   )r/   exctypeZexcvalue	tracebackr'   r'   r(   __exit__|  s    
zTransaction.__exit__c                 C   s6   t | jj| jkr2| j  | jjd | j | j_d S r*   )rX   r   r   r   r   r   r1   r'   r'   r(   r     s    
zTransaction.commitc                 C   s6   t | jj| jkr2| j  | jjd | j | j_d S r*   )rX   r   r   r   r   r   r1   r'   r'   r(   r     s    
zTransaction.rollbackN)	r#   r$   r%   r&   r,   r   r   r   r   r'   r'   r'   r(   r   D  s   2r   c                   @   s   e Zd ZdZdd Zdd Zee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d7ddZdd Zd8d!d"Zd9d#d$Zd%d& Zd'd( Zd:d)d*Zd+d, Zd;d-d.Zd<d/d0Zd=d1d2Zd3d4 Zd5d6 ZdS )>r   ZDatabasec                 C   s   | dd || _|| _t | _tdtdd| _d| _zddl	}d| _
W n tyf   d| _
Y n0 | j ddoz| j
| _
dS )	zCreates a database.driverNZ	debug_sqlr   Fr   Tpooling)pop	db_modulekeywordsr   _ctxr   r   printingsupports_multiple_insertDBUtilshas_poolingImportError)r/   r   r   r   r'   r'   r(   r,     s    
zDB.__init__c                 C   s   | j ds| | j  | j S )Nr   )r   r   _load_contextr1   r'   r'   r(   _getctx  s    z
DB._getctxc                    s   d _ g  _jr"j _nj _j _t	 jdsPdd  j_
t	 jdshdd  j_d fdd		} fd
d}| _
| _d S )Nr   r   c                   S   s   d S r*   r'   r'   r'   r'   r(   r     rc   z"DB._load_context.<locals>.<lambda>r   c                   S   s   d S r*   r'   r'   r'   r'   r(   r     rc   Tc                    s$    j   | r jr j d S r*   )r   r   r   _unload_contextr   r   r   r/   r'   r(   r     s    

z DB._load_context.<locals>.commitc                      s     j   jrj d S r*   )r   r   r   r   r   r'   r   r'   r(   r     s    
z"DB._load_context.<locals>.rollback)T)	dbq_countr   r   _connect_with_poolingr   r   _connect_db_executer   hasattrr   r   )r/   r   r   r   r'   r   r(   r     s    zDB._load_contextc                 C   s   |` d S r*   )r   )r/   r   r'   r'   r(   r     s    zDB._unload_contextc                 C   s   | j jf i |S r*   )r   connect)r/   r   r'   r'   r(   r     s    zDB._connectc                    s0    fdd}t dd d u r&| _j S )Nc                     sR   ddl m}  | jdddk r8| jf dji S | jf dji S d S )Nr   PooledDB.z0.9.3ZdbapiZcreator)r   r   __version__splitr   r   r   r/   r'   r(   get_pooled_db  s    z/DB._connect_with_pooling.<locals>.get_pooled_db	_pooleddb)getattrr   
connection)r/   r   r   r'   r   r(   r     s    zDB._connect_with_poolingc                 C   s   | j j S r*   )r   r   r   r1   r'   r'   r(   
_db_cursor  s    zDB._db_cursorc                 C   s<   t | dd}|dkrdS |dkr$dS |dv r0dS t|d	S )
zHReturns parameter marker based on paramstyle attribute if this database.r=   r5   r6   r7   r8   r9   r:   r<   N)r   r   )r/   styler'   r'   r(   _param_marker  s    zDB._param_markerc                 C   s   | j  jd7  _z.t }| |\}}|||}t }W nJ   | jr^tdt|td | j j	rx| j j	d 
  n
| j 
   Y n0 | jrtdt|| d| j jt|f td |S )zexecutes an sql queryr   zERR:)filez%s (%s): %s   )r   r   time_process_queryexecuter   printrF   r   r   r   round)r/   cur	sql_queryr   rY   paramsoutbr'   r'   r(   r     s&    
zDB._db_executec                 C   s&   t | dd}||}| }||fS zBTakes the SQLQuery object and returns query string and parameters.r=   r5   )r   rY   rd   r/   r   r=   rY   r   r'   r'   r(   r     s    
zDB._process_queryc                 C   sv   t |trdt| }nZt |ttfrFt|dkrFt|d |d }n,t |tr\| |}nt |trhn
t	||}|S )Nid = r   r   r   )
rH   r   r   rM   rl   rX   r   r   _where_dictr   )r/   wherevarsr'   r'   r(   _where  s    



z	DB._wherec                 C   sP   g }t t|dd dD ]\}}||d t|  q|rHt|dS d S d S )Nc                 S   s   | d S Nr   r'   tr'   r'   r(   r   &  rc   z DB._where_dict.<locals>.<lambda>keyr   r   )sortedr   rR   r   r   r^   )r/   r  Zwhere_clausesr   rO   r'   r'   r(   r  #  s    zDB._where_dictNFc                 C   sn   |du ri }|s$t |ts$t||}|r,|S |  }| || |jrR| |}n|j}| jj	sj| j
  |S )a]  
        Execute SQL query `sql_query` using dictionary `vars` to interpolate it.
        If `processed=True`, `vars` is a `reparam`-style list to use
        instead of interpolating.

            >>> db = DB(None, {})
            >>> db.query("SELECT * FROM foo", _test=True)
            <sql: 'SELECT * FROM foo'>
            >>> db.query("SELECT * FROM foo WHERE x = $x", vars=dict(x='f'), _test=True)
            <sql: "SELECT * FROM foo WHERE x = 'f'">
            >>> db.query("SELECT * FROM foo WHERE x = " + sqlquote('f'), _test=True)
            <sql: "SELECT * FROM foo WHERE x = 'f'">
        N)rH   r   r   r   r   r   create_result_setr   r   r   r   )r/   r   r  	processed_testr   r   r'   r'   r(   rY   -  s    

zDB.queryc                 C   s   t |S r*   )r   r   r'   r'   r(   r  P  s    zDB.create_result_set*c
              	      sV   du ri   |||||||}
 fdd|
D }t|}|	rH|S  j|ddS )aT  
        Selects `what` from `tables` with clauses `where`, `order`,
        `group`, `limit`, and `offset`. Uses vars to interpolate.
        Otherwise, each clause can be a SQLQuery.

            >>> db = DB(None, {})
            >>> db.select('foo', _test=True)
            <sql: 'SELECT * FROM foo'>
            >>> db.select(['foo', 'bar'], where="foo.bar_id = bar.id", limit=5, _test=True)
            <sql: 'SELECT * FROM foo, bar WHERE foo.bar_id = bar.id LIMIT 5'>
            >>> db.select('foo', where={'id': 5}, _test=True)
            <sql: 'SELECT * FROM foo WHERE id = 5'>
        Nc                    s&   g | ]\}}|d ur  ||qS r*   )
gen_clause)ra   sqlvalr/   r  r'   r(   rb   p  s   zDB.select.<locals>.<listcomp>T)r  )sql_clausesr   r^   rY   )r/   tablesr  whatr  ordergrouplimitoffsetr  r  ZclausesZqoutr'   r  r(   selectS  s    
z	DB.selectc           
   
   K   s$   |  |}	| j||||||||	dS )a  
        Selects from `table` where keys are equal to values in `kwargs`.

            >>> db = DB(None, {})
            >>> db.where('foo', bar_id=3, _test=True)
            <sql: 'SELECT * FROM foo WHERE bar_id = 3'>
            >>> db.where('foo', source=2, crust='dewey', _test=True)
            <sql: "SELECT * FROM foo WHERE crust = 'dewey' AND source = 2">
            >>> db.where('foo', _test=True)
            <sql: 'SELECT * FROM foo'>
        )r  r  r  r  r  r  r  )r  r  )
r/   tabler  r  r  r  r  r  kwargsr  r'   r'   r(   r  |  s    
zDB.wherec              	   C   sJ   d|fdt |fd|fd|fd|fd|o2t| fd|oDt| ffS )NSELECTFROMWHEREGROUP BYORDER BYZLIMITOFFSET)r   r   r@   r/   r  r  r  r  r  r  r  r'   r'   r(   r    s    
zDB.sql_clausesc                 C   s   t |tr*|dkr dt| }qt|}nft |ttfrXt|dkrXt|d |d }n8|dkrvt |trv| |}nt |tr|}n
t	||}dd }|||S )Nr   r  r   r   r   c                 S   s    | r|r| d | S | p|S d S )Nre   r'   )r   r   r'   r'   r(   xjoin  s    zDB.gen_clause.<locals>.xjoin)
rH   r   r   r   rM   rl   rX   r   r  r   )r/   r  r  r  Znoutr%  r'   r'   r(   r    s    



zDB.gen_clausec                 K   s"  dd }|rtt | dd d}ttdd |d}tdd	 td
d |D d}d| || d || }	nt| |}	|r|	S |  }
|dur| |	||}	t|	t	r|	\}}| 
|
| | 
|
| n| 
|
|	 z|
 d }W n ty   d}Y n0 | jjs| j  |S )a3  
        Inserts `values` into `tablename`. Returns current sequence ID.
        Set `seqname` to the ID if it's not the default, or to `False`
        if there isn't one.

            >>> db = DB(None, {})
            >>> q = db.insert('foo', name='bob', age=2, created=SQLLiteral('NOW()'), _test=True)
            >>> q
            <sql: "INSERT INTO foo (age, created, name) VALUES (2, NOW(), 'bob')">
            >>> q.query()
            'INSERT INTO foo (age, created, name) VALUES (%s, NOW(), %s)'
            >>> q.values()
            [2, 'bob']
        c                 S   s   d|  d S )Nrr   rt   r'   )r`   r'   r'   r(   r     s    zDB.insert.<locals>.qc                 S   s   | d S r  r'   r  r'   r'   r(   r     rc   zDB.insert.<locals>.<lambda>r	  c                 S   s   | d S r  r'   r  r'   r'   r(   r     rc   rs   c                 S   s   g | ]}t |qS r'   r   ra   rO   r'   r'   r(   rb     rc   zDB.insert.<locals>.<listcomp>c                 S   s   | d S r   r'   r  r'   r'   r(   r     rc   zINSERT INTO %s z VALUES Fr   N)r  rL   r   r^   map _get_insert_default_values_queryr   _process_insert_queryrH   rl   r   r   	Exceptionr   r   r   )r/   	tablenameseqnamer  rd   r   Zsorted_values_keysZ_valuesr   r   q1q2r   r'   r'   r(   insert  s6    



z	DB.insertc                 C   s   d| S )NzINSERT INTO %s DEFAULT VALUESr'   r/   r  r'   r'   r(   r(    s    z#DB._get_insert_default_values_queryc                    s  |sg S j s6 fdd|D }du r2dS |S |d  }|D ]}| |krFtdqFt|}tdd|f }t|D ]<\}	|	dkr|d tjfd	d|D d|d
dd q r|S  }
dur	|}t
|tr|\}}|
| |
| n|
| zL|
 d }jjtv rTt||t| }nt|t| d |d }W n ty   d}Y n0 jjsj  |S )a  
        Inserts multiple rows into `tablename`. The `values` must be a list of
        dictionaries, one for each row to be inserted, each with the same set
        of keys. Returns the list of ids of the inserted rows.
        Set `seqname` to the ID if it's not the default, or to `False`
        if there isn't one.

            >>> db = DB(None, {})
            >>> db.supports_multiple_insert = True
            >>> values = [{"name": "foo", "email": "foo@example.com"}, {"name": "bar", "email": "bar@example.com"}]
            >>> db.multiple_insert('person', values=values, _test=True)
            <sql: "INSERT INTO person (email, name) VALUES ('foo@example.com', 'foo'), ('bar@example.com', 'bar')">
        c                    s$   g | ]}j f d |qS ))r,  r  )r0  r&  )r  r/   r,  r+  r'   r(   rb     s   z&DB.multiple_insert.<locals>.<listcomp>FNr   zNot all rows have the same keyszINSERT INTO %s (%s) VALUES rs   c                    s   g | ]}t  | qS r'   )r   )ra   r   )r   r'   r(   rb   /  rc   rr   rt   )rf   ri   rg   rh   r   )r   keysr+   r  r   r^   rN   rR   r   r)  rH   rl   r   r   r   r#   mysql_driversrangerX   r*  r   r   r   )r/   r+  rd   r,  r  r   r2  rO   r   rP   r   r.  r/  r'   )r  r   r/   r,  r+  r(   multiple_insert  s^    




zDB.multiple_insertc                 K   s   |du ri }|  ||}t| dd d}dt| d t|d d | }|rV|S |  }| || | jjs|| j	  |j
S )	ag  
        Update `tables` with clause `where` (interpolated using `vars`)
        and setting `values`.

            >>> db = DB(None, {})
            >>> name = 'Joseph'
            >>> q = db.update('foo', where='name = $name', name='bob', age=2,
            ...     created=SQLLiteral('NOW()'), vars=locals(), _test=True)
            >>> q
            <sql: "UPDATE foo SET age = 2, created = NOW(), name = 'bob' WHERE name = 'Joseph'">
            >>> q.query()
            'UPDATE foo SET age = %s, created = NOW(), name = %s WHERE name = %s'
            >>> q.values()
            [2, 'bob', 'Joseph']
        Nc                 S   s   | d S r  r'   r  r'   r'   r(   r   j  rc   zDB.update.<locals>.<lambda>r	  zUPDATE z SET rs    WHERE )r  r  rL   r   r   r   r   r   r   r   r   )r/   r  r  r  r  rd   rY   r   r'   r'   r(   updateV  s.    	
z	DB.updatec                 C   sx   |du ri }|  ||}d| }|r4|dt| 7 }|rD|d| 7 }|rL|S |  }| || | jjsr| j  |jS )a  
        Deletes from `table` with clauses `where` and `using`.

            >>> db = DB(None, {})
            >>> name = 'Joe'
            >>> db.delete('foo', where='name = $name', vars=locals(), _test=True)
            <sql: "DELETE FROM foo WHERE name = 'Joe'">
        NzDELETE FROM z USING r6  )r  r   r   r   r   r   r   r   )r/   r  r  usingr  r  r   r   r'   r'   r(   delete~  s    	
z	DB.deletec                 C   s   |S r*   r'   r/   rY   r+  r,  r'   r'   r(   r)    s    zDB._process_insert_queryc                 C   s
   t | jS )zStart a transaction.)r   r   r1   r'   r'   r(   transaction  s    zDB.transaction)NFF)Nr  NNNNNF)r  NNNNF)NF)NF)NF)NNF)r#   r$   r%   r&   r,   r   propertyr   r   r   r   r   r   r   r   r   r  r  rY   r  r  r  r  r  r0  r(  r5  r7  r9  r)  r;  r'   r'   r'   r(   r     sR   

#        
,      
"
;
T
(
r   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 )
PostgresDBzPostgres driver.c                 K   s   d|v r| d|d< tt| dd d}|jdkrLdd l}|j|jj d|v rb| d|d< d	| _|j	| _	t
| || d
| _d | _d S )Npwpasswordr   	preferredr   r   r   r   postgresT)r   import_driver
pg_driversr#   Zpsycopg2.extensions
extensionsZregister_typeUNICODEdbnamer=   r   r,   r   
_sequences)r/   r   r   r   r'   r'   r(   r,     s    
zPostgresDB.__init__c                 C   s4   |d u r |d }||   vr d }|r0|d| 7 }|S )NZ_id_seqz; SELECT currval('%s'))_get_all_sequencesr:  r'   r'   r(   r)    s    z PostgresDB._process_insert_queryc                 C   s.   | j du r(d}tdd | |D | _ | j S )zDQuery postgres to find names of all sequences used in this database.Nz6SELECT c.relname FROM pg_class c WHERE c.relkind = 'S'c                 S   s   g | ]
}|j qS r'   )Zrelname)ra   cr'   r'   r(   rb     rc   z1PostgresDB._get_all_sequences.<locals>.<listcomp>)rH  ru   rY   )r/   r   r'   r'   r(   rI    s    
zPostgresDB._get_all_sequencesc                 C   s   t | |}|d |S NUTF8)r   r   set_client_encodingr/   r   connr'   r'   r(   r     s    
zPostgresDB._connectc                 C   s   t | |}|jjd |S rK  )r   r   Z_conrM  rN  r'   r'   r(   r     s    z PostgresDB._connect_with_poolingN)	r#   r$   r%   r&   r,   r)  rI  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 )MySQLDBc                 K   s   t t|dd d}|jdkr:d|v r|d |d< |d= nR|jdkr\d|v r|d|d< n0|jdkr|d	d
 d|v r|d |d< |d= d|vrd|d< n|d d u r|d= d | _|_d| _t| || d
| _	d S )Nr   r@  r   r>  r?  r   passwdr   ZbufferedTcharsetutf8r5   mysql)
rC  r3  r   r#   
setdefaultr=   rG  r   r,   r   r/   r   r   r'   r'   r(   r,     s*    



zMySQLDB.__init__c                 C   s   |t dfS )NzSELECT last_insert_id();r?   r:  r'   r'   r(   r)    s    zMySQLDB._process_insert_queryc                 C   s   d| S )NzINSERT INTO %s () VALUES()r'   r1  r'   r'   r(   r(    s    z(MySQLDB._get_insert_default_values_queryN)r#   r$   r%   r,   r)  r(  r'   r'   r'   r(   rP    s   rP  c              	   C   sT   |r
|f} | D ].}zt |dddgW   S  ty:   Y q0 qtdd|  dS )z6Import the first available driver or preferred driver.Nr`   zUnable to import z or )
__import__r   r^   )ZdriversrA  r   r'   r'   r(   rC    s    rC  c                   @   s$   e Zd Zdd Zdd Zdd ZdS )SqliteDBc                 K   sh   t t|dd d}|jdv r$d|_|d|j d| _|j| _|d|d< d	|d
< t	| || d S )Nr   r@  )r   r    r6   Zdetect_typesr!   r   r   Fr   )
rC  sqlite_driversr   r#   r=   rU  ZPARSE_DECLTYPESrG  r   r,   rV  r'   r'   r(   r,     s    
zSqliteDB.__init__c                 C   s   |t dfS )NzSELECT last_insert_rowid();r?   r:  r'   r'   r(   r)  $  s    zSqliteDB._process_insert_queryc                 C   s   t |S r*   )r   r   r'   r'   r(   r  '  s    zSqliteDB.create_result_setN)r#   r$   r%   r,   r)  r  r'   r'   r'   r(   rX    s   rX  c                   @   s*   e Zd ZdZdd Zd
ddZdd	 ZdS )
FirebirdDBzFirebird Database.c                 K   sb   zdd l }W n ty"   d }Y n0 d|v r:|d|d< |d|d< |j| _t| || d S )Nr   r>  r?  r   r   )Zkinterbasdbr*  r   r=   r   r,   rV  r'   r'   r(   r,   .  s    zFirebirdDB.__init__NFc                 C   s   d }t | |||||S r*   )r   r9  )r/   r  r  r8  r  r  r'   r'   r(   r9  <  s    zFirebirdDB.deletec              	   C   s4   dd|fd|fd|fdt |fd|fd|fd|ffS )	N)r  r\   ZFIRSTZSKIPr\   r  r   r!  r"  r   r$  r'   r'   r(   r  A  s    
zFirebirdDB.sql_clauses)NNNF)r#   r$   r%   r&   r,   r9  r  r'   r'   r'   r(   rZ  +  s   
rZ  c                   @   s,   e Zd Zdd Zdd Zdd Zdd Zd	S )
MSSQLDBc                 K   sD   dd l }d|v r|d|d< |d|d< d| _t| || d S )Nr   r>  r?  r   r   mssql)Zpymssqlr   rG  r   r,   rV  r'   r'   r(   r,   O  s    zMSSQLDB.__init__c                 C   s*   t | dd}||}| }|t|fS r   )r   rY   rd   rl   r   r'   r'   r(   r   X  s    
zMSSQLDB._process_queryc                 C   s2   d|fd|fdt |fd|fd|fd|fd|ffS )Nr  ZTOPr  r   r!  r"  r#  r[  r$  r'   r'   r(   r  a  s    
zMSSQLDB.sql_clausesc                 C   s   dS )an  Test LIMIT.

        Fake presence of pymssql module for running tests.
        >>> import sys
        >>> sys.modules['pymssql'] = sys.modules['sys']

        MSSQL has TOP clause instead of LIMIT clause.
        >>> db = MSSQLDB(db='test', user='joe', pw='secret')
        >>> db.select('foo', limit=4, _test=True)
        <sql: 'SELECT * TOP 4 FROM foo'>
        Nr'   r1   r'   r'   r(   r  l  s    zMSSQLDB._testN)r#   r$   r%   r,   r   r  r  r'   r'   r'   r(   r\  N  s   		r\  c                   @   s   e Zd Zdd Zdd ZdS )OracleDBc                 K   s^   dd l }d|v r|d|d< |d|d< d| _d|_|j| _|dd  t| || d S )	Nr   r>  r?  r   Zdsnoracler8   r   )Z	cx_Oracler   rG  r=   r   r,   rV  r'   r'   r(   r,   |  s    zOracleDB.__init__c                 C   s   |d u r|S |d|  S d S )Nz; SELECT %s.currval FROM dualr'   r:  r'   r'   r(   r)    s    zOracleDB._process_insert_queryN)r#   r$   r%   r,   r)  r'   r'   r'   r(   r^  {  s   r^  c                 C   sX   t  t| }|jdkr.|j|jdd dS |j|j|j|jdd |j|jdS dS )a%  
    Takes a URL to a database and parses it into an equivalent dictionary.

        >>> dburl2dict('postgres:///mygreatdb') == {'pw': None, 'dbn': 'postgres', 'db': 'mygreatdb', 'host': None, 'user': None, 'port': None}
        True
        >>> dburl2dict('postgres://james:day@serverfarm.example.net:5432/mygreatdb') == {'pw': 'day', 'dbn': 'postgres', 'db': 'mygreatdb', 'host': 'serverfarm.example.net', 'user': 'james', 'port': 5432}
        True
        >>> dburl2dict('postgres://james:day@serverfarm.example.net/mygreatdb') == {'pw': 'day', 'dbn': 'postgres', 'db': 'mygreatdb', 'host': 'serverfarm.example.net', 'user': 'james', 'port': None}
        True
        >>> dburl2dict('postgres://james:d%40y@serverfarm.example.net/mygreatdb') == {'pw': 'd@y', 'dbn': 'postgres', 'db': 'mygreatdb', 'host': 'serverfarm.example.net', 'user': 'james', 'port': None}
        True
        >>> dburl2dict('mysql://james:d%40y@serverfarm.example.net/mygreatdb') == {'pw': 'd@y', 'dbn': 'mysql', 'db': 'mygreatdb', 'host': 'serverfarm.example.net', 'user': 'james', 'port': None}
        True
        >>> dburl2dict('sqlite:///mygreatdb.db')
        {'db': 'mygreatdb.db', 'dbn': 'sqlite'}
        >>> dburl2dict('sqlite:////absolute/path/mygreatdb.db')
        {'db': '/absolute/path/mygreatdb.db', 'dbn': 'sqlite'}
    r!   r   N)dbnr   )r`  userr>  r   hostport)urlparser
   schemepathusernamer?  hostnamerc  )urlpartsr'   r'   r(   
dburl2dict  s    
rk  c                 K   sN   | s|st jd } | rt| }|d}|tv rBt| f i |S t|dS )zCreates appropriate database using params.

    Pooling will be enabled if DBUtils module is available.
    Pooling can be disabled by passing pooling=False in params.
    ZDATABASE_URLr`  N)osenvironrk  r   
_databasesr   )Zdburlr   r`  r'   r'   r(   r     s    

r   c                 C   s   |t | < dS )a  
    Register a database.

        >>> class LegacyDB(DB):
        ...     def __init__(self, **params):
        ...        pass
        ...
        >>> register_database('legacy', LegacyDB)
        >>> db = database(dbn='legacy', db='test', user='joe', passwd='secret')
    N)rn  )nameZclazzr'   r'   r(   register_database  s    rp  rT  rB  r!   Zfirebirdr]  r_  c                 C   sP  dd }d}g }d}|  d|}|dk r,q(| |d  }|dkr|d| || f |d d }}|r|| |\}}|jd	 \}	}
| |	|
 }|dkr|d }qd|d
krd|d }qd|d| |d |d  f q||v r|d| || f || |d \}}|t| k r| | dkrZ|d t| k rZ| |d  |v rZ|| |d \}}n| | dv r|d d }}|r|| |\}}|jd	 \}	}
| |	|
 }|d dv r|d }n|d dv rv|d }qvnqq|d| |d | f q|d| ||d  f |d |dk }q|t| k rL|d| |d f |S )z
    Takes a format string and returns a list of 2-tuples of the form
    (boolean, string) where boolean says whether string should be evaled
    or not.

    from <http://lfw.org/python/Itpl.py> (public domain, Ka-Ping Yee)
    c                 S   s*   t | |}|d u rt| ||| fS r*   )	tokenprogmatchr)   end)r-   r.   rr  r'   r'   r(   matchorfail  s    
z!_interpolate.<locals>.matchorfail?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_r   $r   {r      }r   z([z)]N)findrR   regsrX   )r;   rt  	namecharschunksr.   dollarnextcharlevelrr  Ztstarttendtokenr'   r'   r(   r|     s`    	

 


r|   c                   @   s&   e Zd ZdddZdd Zdd ZdS )	_NodeNc                 C   s   || _ || _|| _d S r*   typer   second)r/   r  r   r  r'   r'   r(   r,   )  s    z_Node.__init__c                 C   s.   t |to,| j|jko,| j|jko,| j|jkS r*   )rH   r  r  r   r  rB   r'   r'   r(   rI   .  s    



z_Node.__eq__c                 C   s   d| j | j| jf S )NzNode(%r, %r, %r)r  r1   r'   r'   r(   rJ   6  s    z_Node.__repr__)N)r#   r$   r%   r,   rI   rJ   r'   r'   r'   r(   r  (  s   
r  c                   @   sL   e Zd 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S )ParserzParser to parse string templates like "Hello $name".

    Loosely based on <http://lfw.org/python/Itpl.py> (public domain, Ka-Ping Yee)
    ru  c                 C   s   |    d S r*   )resetr1   r'   r'   r(   r,   B  s    zParser.__init__c                 C   s   d| _ d| _d| _d S )Nr   r\   )r.   r  r-   r1   r'   r'   r(   r  E  s    zParser.resetc                 C   s   |    || _|  S )z/Parses the given text and returns a parse tree.)r  r-   	parse_allr/   r-   r'   r'   r(   r	   J  s    zParser.parsec                 c   s8  | j d| j}|dk rq
| j |d  }|| jv rbtd| j | j| V  |d | _|  V  q |dkr| j}|d | _|  }| j | j dkr|  jd7  _td| j | j| V  |V  n
|| _q
q td| j | j|d  V  |d | _|dkr |  jd7  _q | jt| j k r4td| j | jd  V  d S )Nrv  r   r   r-   rw  r   ry  )r-   rz  r.   r|  r  
parse_exprrX   )r/   r~  r  	saved_posexprr'   r'   r(   r  P  s0    



zParser.parse_allc                 C   s2   t | j| j}|d u r&t| j| j|| fS r*   )rq  rr  r-   r.   r)   rs  )r/   rr  r'   r'   r(   rr  q  s    zParser.matchc                 C   s   |o|d dv S )Nr   z0123456789"'r'   r  r'   r'   r(   
is_literalw  s    zParser.is_literalc                 C   s:  |   \}}| | r*td| }ntd| j| j| }|| _| jt| jk r6| j| j dkr| jd t| jk r| j| jd  | jv r|  jd7  _|   \}}| }td||}|| _qF| j| j dkr6| j}|  jd7  _|  }| j| j dkr$|  jd7  _td||}n
|| _q6qFq6qF|S )	Nliteralparamr   r   r   []getitem)	rr  r  r  r  r-   r.   rX   r|  r  )r/   rr  r.   r  attrr  r
  r'   r'   r(   r  z  s8    zParser.parse_exprN)r#   r$   r%   r&   r|  r,   r  r	   r  rr  r  r  r'   r'   r'   r(   r  :  s   !r  c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	rx   z0Safe evaluator for binding params to db queries.c                    s(   t  |}t fdd|D dS )Nc                    s   g | ]} | qS r'   )	eval_node)ra   nodemappingr/   r'   r(   rb     rc   z%SafeEval.safeeval.<locals>.<listcomp>r\   )r  r	   r   r^   )r/   r-   r  nodesr'   r  r(   ry     s    zSafeEval.safeevalc                 C   s$   |j dkr|jS t| ||S d S )Nr-   )r  r   r   	eval_exprr/   r  r  r'   r'   r(   r    s    
zSafeEval.eval_nodec                 C   st   |j dkrt|jS |j dkr6t| |j||jS |j dkr\| |j|| |j| S |j dkrp||j S d S )Nr  r   r  r  )r  astliteral_evalr   r   r  r  r  r'   r'   r(   r    s    



zSafeEval.eval_exprN)r#   r$   r%   r&   ry   r  r  r'   r'   r'   r(   rx     s   rx   c               	   C   s   dd } | dt ddg | dt ddt ddg | d	t ddt d
t dddg | dt ddt d
t ddd dt ddg | dt ddt dt ddd t ddt ddg d S )Nc                 S   s:   t  }t|| }tt| | ||ks6J d| d S )NzExpected %r)r  rM   r	   r   r0   )r-   expectedpr  r'   r'   r(   f  s    ztest_parser.<locals>.fZHellor-   zHello $namezHello r  ro  zHello $name.foor   ZfoozWHERE id=$self.id LIMIT 1	WHERE id=r/   idz LIMIT 1zWHERE id=$self['id'] LIMIT 1r  r  z'id')r  r  r'   r'   r(   test_parser  s*    	r  c                  C   s@   dd } t | dddij | dddijdtdgks<J d S )Nc                 S   s   t  | |S r*   )rx   ry   )r   r  r'   r'   r(   r    s    ztest_safeeval.<locals>.fzWHERE id=$idr  r   r  )r   rL   r   r  r'   r'   r(   test_safeeval  s    r  __main__)r   )N)N)Lr&   r   rl  rer   Z
py3helpersr   utilsr   r   r   r   r   urllibr	   rd  urllib.parser
   r   r  Zwebapir   r   sysstderr__all__ZTOKENcompilerq  rD  r3  rY  r*  r   r+   r)   r   r   r{   r   r   r   r   r   rv   r   rj   r   r   r   r   r   r   r   r   r   r=  rP  rC  rX  rZ  r\  r^  rk  rn  r   rp  r|   r  r  rx   r  r  r#   doctesttestmodr'   r'   r'   r(   <module>   s   



. ( 
7I    6'
#-"






Fa 
