o
    !2g-9                     @   s~  d dl Z d dlZd dlmZ d dlmZmZ d dlmZmZ d dl	m
Z
 d dl mZmZmZmZmZmZmZmZmZmZmZmZmZ d dlZd dlmZ dd	lmZ dd
lmZ deee  fddZdefddZ eee! ee" ee# ee ee ee ee$ ee% ee& ee f
 Z'ee!e"e#eeee$e%e&ef
 Z(e!e"e#eeee$e%e&h	Z)dedefddZ*G dd dej+Z,G dd de,Z-e"e#ee.dfZ/G dd dej+Z0e!ej1e"ej2e#ej3eej4ee,ee-e$ej5e%ej5e&e0i	Z6e7e68 e)ksJ deeef fddZ9dd Z:edZ;eG dd dee; Z<d+d d!Z=ed"e"d#fed$fee! d%fee!e"f dfgd+d&d'Z>d(e
ddfd)d*Z?dS ),    N)	dataclass)datedatetime)chainislice)Path)AnyGenericIterableIteratorList
NamedTupleOptionalSequenceSetTupleTypeTypeVarUnion)Column   )parametrize)CachewExceptionreturnc                 C   s<   t | dd tkr
d S | j}dd |D }t|dksJ |S )N
__origin__c                 S   s   g | ]
}|t d ur|qS N)type).0e r   E/home/garg/my-data/venv/lib/python3.10/site-packages/cachew/legacy.py
<listcomp>#   s    z"get_union_args.<locals>.<listcomp>r   )getattrr   __args__len)clsargsr   r   r    get_union_args   s   r'   c                 C   s   t | d uS r   )r'   r%   r   r   r    is_union(   s   r)   r%   c                 C   s   | t v S )z
    >>> from typing import Dict, Any
    >>> is_primitive(int)
    True
    >>> is_primitive(set)
    False
    >>> is_primitive(dict)
    True
    )PRIMITIVE_TYPESr(   r   r   r    is_primitiveS   s   
r+   c                   @   sh   e Zd ZejZdZedd Zdd Z	de
e de
e fdd	Zde
e de
e fd
dZdddZdS )IsoDateTimeTc                 C      t S r   )r   selfr   r   r    python_typeg      zIsoDateTime.python_typec                 C      t  r   NotImplementedErrorr/   valuedialectr   r   r    process_literal_paramk      z!IsoDateTime.process_literal_paramr6   r   c                 C   s   |d u rd S |  }t|dd }|d u r|S zdd l}W n ty+   |   | Y S w t||jrC|j}|d us=J ||d | S |S )Ntzinfor    )	isoformatr"   pytzImportError	warn_pytz
isinstance
BaseTzInfozone)r/   r6   r7   isotzr=   rB   r   r   r    process_bind_paramn   s"   zIsoDateTime.process_bind_paramc                 C   s|   |d u rd S | d}t|d }t|dkr|S |d }zdd l}W n ty3   |   | Y S w ||}||S )Nr;   r   r   )	splitr   fromisoformatr$   r=   r>   r?   timezone
astimezone)r/   r6   r7   spldtrB   r=   rD   r   r   r    process_result_value   s   


z IsoDateTime.process_result_valueNc                 C   s   t d d S )NzFinstall pytz for better timezone support while serializing with cachew)warningswarnr.   r   r   r    r?         zIsoDateTime.warn_pytzr   N)__name__
__module____qualname__
sqlalchemyStringimplcache_okpropertyr0   r8   r   r   strrE   rL   r?   r   r   r   r    r,   `   s    
r,   c                       sL   e Zd ZejZdZedd Zdd Z	de
e de
e f fdd	Z  ZS )
IsoDateTc                 C   r-   r   )r   r.   r   r   r    r0      r1   zIsoDate.python_typec                 C   r2   r   r3   r5   r   r   r    r8      r9   zIsoDate.process_literal_paramr6   r   c                    s"   t  ||}|d u rd S | S r   )superrL   r   )r/   r6   r7   res	__class__r   r    rL      s   zIsoDate.process_result_value)rQ   rR   rS   rT   rU   rV   rW   rX   r0   r8   r   rY   r   rL   __classcell__r   r   r]   r    rZ      s    
&rZ   c                   @   sf   e Zd ZdZejZdZedd Z	dd Z
dee deee  fd	d
Zdee dee fddZdS )ExceptionAdaptera8  
    Enables support for caching Exceptions. Exception is treated as JSON and serialized.

    It's useful for defensive error handling, in case of cachew in particular for preserving error state.

    I elaborate on it here: [mypy-driven error handling](https://beepb00p.xyz/mypy-error-handling.html#kiss).
    Tc                 C   r-   r   	Exceptionr.   r   r   r    r0      r1   zExceptionAdapter.python_typec                 C   r2   r   r3   r5   r   r   r    r8      r9   z&ExceptionAdapter.process_literal_paramr6   r   c                    sj   |d u rd S g }|j D ]' t fddtD r|  qt tr+|   q|t  q|S )Nc                 3   s    | ]}t  |V  qd S r   )r@   )r   tar   r    	<genexpr>       z6ExceptionAdapter.process_bind_param.<locals>.<genexpr>)r&   anyjtypesappendr@   r   r<   rY   )r/   r6   r7   sargsr   rd   r    rE      s   

z#ExceptionAdapter.process_bind_paramc                 C   s   |d u rd S t | S r   ra   r5   r   r   r    rL      s   z%ExceptionAdapter.process_result_valueN)rQ   rR   rS   __doc__rT   JSONrV   rW   rX   r0   r8   r   rb   r   r   rE   rY   rL   r   r   r   r    r`      s    
r`   c                 C   s4   d}t | }|durt|dkr|d } d}| |fS )z
    >>> from typing import Optional, NamedTuple
    >>> strip_optional(Optional[int])
    (<class 'int'>, True)
    >>> class X(NamedTuple):
    ...     x: int
    >>> strip_optional(X)
    (<class 'cachew.legacy.X'>, False)
    FNr   r   T)r'   r$   )r%   is_optr&   r   r   r    strip_optional   s   
ro   c                 C   s   t td}t| |r| jS | S )zf
    >>> strip_generic(List[int])
    <class 'list'>
    >>> strip_generic(str)
    <class 'str'>
    _GenericAlias)r"   typingr@   r   )tpGAr   r   r    strip_generic   s   

rt   NTc                   @   s  e Zd ZU dZee ed< eed< eed< e	ed< e	ed< ee
 ed< ee ed< ed%d
e
e dee ddfddZedee fddZdedeee df fddZdee defddZdeee  fddZdd Zdee fddZdd Zd d! Zd&d#d$Zd	S )'NTBindera'  
    >>> class Job(NamedTuple):
    ...    company: str
    ...    title: Optional[str]
    >>> class Person(NamedTuple):
    ...     name: str
    ...     age: int
    ...     job: Optional[Job]

    NTBinder is a helper class for inteacting with sqlite database.
    Hierarchy is flattened:
    >>> binder = NTBinder.make(Person)
    >>> [(c.name, type(c.type)) for c in binder.columns]
    ... # doctest: +NORMALIZE_WHITESPACE
    [('name',         <class 'sqlalchemy.sql.sqltypes.String'>),
     ('age',          <class 'sqlalchemy.sql.sqltypes.Integer'>),
     ('_job_is_null', <class 'sqlalchemy.sql.sqltypes.Boolean'>),
     ('job_company',  <class 'sqlalchemy.sql.sqltypes.String'>),
     ('job_title',    <class 'sqlalchemy.sql.sqltypes.String'>)]


    >>> person = Person(name='alan', age=40, job=None)

    to_row converts object to a sql-friendly tuple. job=None, so we end up with True in _job_is_null field
    >>> tuple(binder.to_row(person))
    ('alan', 40, True, None, None)

    from_row does reverse conversion
    >>> binder.from_row(('alan', 40, True, None, None))
    Person(name='alan', age=40, job=None)

    >>> binder.from_row(('ann', 25, True, None, None, 'extra'))
    Traceback (most recent call last):
    ...
    cachew.utils.CachewException: unconsumed items in iterator ['extra']
    nametype_span	primitiveoptionalunionfieldsNrr   r   zNTBinder[NT]c           
   	   C   s   t | \} }t| }|d ur'tddd |D }|}d}tj|ddf}d}nFd }t| } t| }|r9|d u r9d}|r@d	}d}n-t| }	|	i krSt	|  d
| dt
dd |	 D }tdd |D |rjdnd }t|| |||||dS )N_CachewUnionReprc                 S   s   g | ]	}|j t| fqS r   )rQ   r   )r   xr   r   r    r!   H  s    z!NTBinder.make.<locals>.<listcomp>F_cachew_union_reprrr   rw   r   _cachew_primitiver   z	 (field 'z'): doesn't look like a supported type to cache. See https://github.com/karlicoss/cachew#features for the list of supported types.c                 s   s"    | ]\}}t j||d V  qdS )r   N)rv   make)r   fnameannr   r   r    rf   ^       z NTBinder.make.<locals>.<genexpr>c                 s   s    | ]}|j V  qd S r   )ry   r   fr   r   r    rf   _  s    r   )rw   rx   ry   rz   r{   r|   r}   )ro   r'   r   rv   r   rt   r+   rq   get_type_hintsr   tupleitemssum)
rr   rw   r{   
union_argsCachewUnionr|   rz   r}   ry   annotationsr   r   r    r   ?  sB   
zNTBinder.makec                 C   s   t |  S r   )listiter_columnsr.   r   r   r    columnsj  s   zNTBinder.columnsobj.c                 C   s   t | |S r   )r   _to_row)r/   r   r   r   r    to_rowo  rO   zNTBinder.to_rowrowc                 C   sL   t |}| |}tt|dd}t|dkrtd| |d us$J |S )Nr   r   zunconsumed items in iterator )iter	_from_rowr   r   r$   r   )r/   r   riterr\   	remainingr   r   r    from_rowr  s   
zNTBinder.from_rowc                 #   s    | j r	 V  d S | jd ur.| j}| j\}|di  fdd|jD }||E d H  d S | jr9 d u }|V  nd} d usAJ |rRt| jd D ]}d V  qJd S t fdd| jD E d H  d S )Nc                    s$   i | ]}|j t |jr nd qS r   )rw   r@   rx   r   r   r   r    
<dictcomp>  s   $ z$NTBinder._to_row.<locals>.<dictcomp>Fr   c                 3   s"    | ]}| t |jV  qd S r   )r   r"   rw   r   r   r   r    rf     r   z#NTBinder._to_row.<locals>.<genexpr>r   )	rz   r|   r}   r   r{   rangery   r   from_iterable)r/   r   r   ufr|   is_none_r   r   r    r   {  s$   

$zNTBinder._to_rowc                    s   | j rt S | jd ur+| j}| j\}dd | D }t|dks'J ||d S | jr3t }nd}|rOt| jd D ]}t }|d u sLJ |q>d S | j	 fdd| jD  S )Nc                 S   s   g | ]}|d ur|qS r   r   )r   rr   r   r    r!     s    z&NTBinder._from_row.<locals>.<listcomp>r   r   Fc                 3   s    | ]}|  V  qd S r   )r   r   row_iterr   r    rf     rg   z%NTBinder._from_row.<locals>.<genexpr>)
rz   nextr|   r}   r   r$   r{   r   ry   rx   )r/   r   r   r   union_paramsr   r   r   r   r   r    r     s"   

zNTBinder._from_rowc                 #   s    t   dtdtf fdd}| jr%| jd u rt|| jt| j V  d S | jd u r,dn| jd }| jr?|d| dt	j
V  | jD ]}| D ]}|| |j |jV  qHqBd S )Nrw   r   c                    s,   |  v rd|  } |  v s  |  t| |S )Nr   )addr   )rw   rr   
used_namesr   r    col  s
   

z"NTBinder.iter_columns.<locals>.col r   is_null)setrY   r   rz   rw   AssertionError
PRIMITIVESrx   r{   rT   Booleanr}   r   r   )r/   r   prefixr   cr   r   r    r     s   

zNTBinder.iter_columnsc                 C   s   dd |   D }d|S )Nc                 S   s>   g | ]\}}d | t |j |jrdnd d|j d qS )z  ?r   z <span >)rY   rw   r{   ry   )r   levelr   r   r   r    r!     s   > z$NTBinder.__str__.<locals>.<listcomp>
)flattenjoin)r/   linesr   r   r    __str__  s   
zNTBinder.__str__c                 C      t | S r   rY   r.   r   r   r    __repr__  s   zNTBinder.__repr__r   c                 c   s2    || fV  | j D ]}|j|d dE d H  q	d S )Nr   )r   )r}   r   )r/   r   r   r   r   r    r     s
   

zNTBinder.flattenr   )r   ) rQ   rR   rS   rl   r   rY   __annotations__Typesintboolr   r   r   staticmethodru   r   rX   r   r   r   r   Valuesr   r
   r   r   r   r   r   r   r   r   r   r   r   r    rv     s*   
 %"*	rv   c                  C   s\   g } t jD ]}|j\}| | qdd }|| |tjks J tD ]	}|tjv s+J q"d S )Nc                 S   s   t | dd dS )Nc                 S   r   r   r   )rc   r   r   r    <lambda>  s    z6test_mypy_annotations.<locals>.types.<locals>.<lambda>)key)sorted)tsr   r   r    types  s   z$test_mypy_annotations.<locals>.types)r   r#   rj   r   r*   )vsrc   argr   pr   r   r    test_mypy_annotations  s   
r   )rr   val   Fabacabac                 C   s6   t j| dd}||}|t|}||ksJ d S )Nr   rw   )rv   r   r   r   r   )rr   r   br   vvr   r   r    test_ntbinder_primitive  s   

r   tmp_pathc                    sJ   G dd dt  G  fdddt }dd t|jD g dks#J d S )Nc                   @   s"   e Zd ZU eed< ee ed< dS )z test_unique_columns.<locals>.JobcompanytitleN)rQ   rR   rS   rY   r   r   r   r   r   r    Job     
 r   c                       s"   e Zd ZU eed< e  ed< dS )z#test_unique_columns.<locals>.Breaky	job_titlejobN)rQ   rR   rS   r   r   r   r   r   r   r    Breaky  r   r   c                 S   s   g | ]}|j qS r   r   )r   r   r   r   r    r!     s    z'test_unique_columns.<locals>.<listcomp>)r   _job_is_nulljob_company
_job_title)r   rv   r   r   )r   r   r   r   r    test_unique_columns  s   &r   rP   )@rq   rM   dataclassesr   r   r   	itertoolsr   r   pathlibr   r   r	   r
   r   r   r   r   r   r   r   r   r   r   rT   r   pytestr   utilsr   r'   r   r)   rY   r   floatdictr   rb   r   r   r*   r+   TypeDecoratorr,   rZ   r   ri   r`   rU   IntegerFloatr   rm   r   r   keysro   rt   ru   rv   r   r   r   r   r   r   r    <module>   s    <
;* 
=
	