U
    ڲg)                     @  s   d Z ddlmZ ddlmZmZmZ ddlmZ ddlm	Z
 ddlmZmZ ddlmZ dd	lmZ dd
lmZ ddlmZ erddlmZ edZG dd dZeedZeedZdS )z,
Mapping from types/oids to Dumpers/Loaders
    )annotations)AnycastTYPE_CHECKING   )pq)errors)DumperLoader)PyFormat)TypeVar)_psycopg)TypesRegistry)BaseConnectionRVc                   @  s   e Zd ZU dZdZded< ded< ded< d	ed
< i Zded< d5dddddZed dddZeddddZ	ddddddZ
dd dd!d"d#Zd$d%dd&d'd(Zd)d*dd+d,d-Zd)d*d.d+d/d0Zed1d1d2d3d4ZdS )6AdaptersMapa  
    Establish how types should be converted between Python and PostgreSQL in
    an `~psycopg.abc.AdaptContext`.

    `!AdaptersMap` maps Python types to `~psycopg.adapt.Dumper` classes to
    define how Python types are converted to PostgreSQL, and maps OIDs to
    `~psycopg.adapt.Loader` classes to establish how query results are
    converted to Python.

    Every `!AdaptContext` object has an underlying `!AdaptersMap` defining how
    types are converted in that context, exposed as the
    `~psycopg.abc.AdaptContext.adapters` attribute: changing such map allows
    to customise adaptation in a context without changing separated contexts.

    When a context is created from another context (for instance when a
    `~psycopg.Cursor` is created from a `~psycopg.Connection`), the parent's
    `!adapters` are used as template for the child's `!adapters`, so that every
    cursor created from the same connection use the connection's types
    configuration, but separate connections have independent mappings.

    Once created, `!AdaptersMap` are independent. This means that objects
    already created are not affected if a wider scope (e.g. the global one) is
    changed.

    The connections adapters are initialised using a global `!AdptersMap`
    template, exposed as `psycopg.adapters`: changing such mapping allows to
    customise the type mapping for every connections created afterwards.

    The object can start empty or copy from another object of the same class.
    Copies are copy-on-write: if the maps are updated make a copy. This way
    extending e.g. global map by a connection or a connection map from a cursor
    is cheap: a copy is only made on customisation.
    zpsycopg.adaptr   typesz.dict[PyFormat, dict[type | str, type[Dumper]]]_dumperszlist[dict[int, type[Dumper]]]_dumpers_by_oidzlist[dict[int, type[Loader]]]_loaderszdict[type, type]
_optimisedNzAdaptersMap | NonezTypesRegistry | None)templater   c                 C  s   |rz|j  | _ t | _t |_|jd d  | _ddg| _ddg|_|jd d  | _ddg| _ddg|_t|j	| _	nNdd t
D | _ t | _i i g| _ddg| _i i g| _ddg| _|pt | _	d S )NFc                 S  s   i | ]
}|i qS  r   ).0fmtr   r   9/tmp/pip-unpacked-wheel-b_ea6rx_/psycopg/_adapters_map.py
<dictcomp>\   s      z(AdaptersMap.__init__.<locals>.<dictcomp>T)r   copy_dumpers_shared_own_dumpersr   _own_dumpers_by_oidr   _own_loadersr   r   r   _dumpers_owned)selfr   r   r   r   r   __init__G   s$    










zAdaptersMap.__init__)returnc                 C  s   | S Nr   r#   r   r   r   adaptersh   s    zAdaptersMap.adapterszBaseConnection[Any] | Nonec                 C  s   d S r&   r   r'   r   r   r   
connectionl   s    zAdaptersMap.connectionztype | str | Noneztype[Dumper]None)clsdumperr%   c                 C  s   |dks&t |ttfs&td| dtr4| |}|rt|jtj	fD ]:}| j
| sv| j|  | j|< d| j
|< || j| |< qJ|jr| j|j s| j|j  | j|j< d| j|j< || j|j |j< dS )a  
        Configure the context to use `!dumper` to convert objects of type `!cls`.

        If two dumpers with different `~Dumper.format` are registered for the
        same type, the last one registered will be chosen when the query
        doesn't specify a format (i.e. when the value is used with a ``%s``
        "`~PyFormat.AUTO`" placeholder).

        :param cls: The type to manage.
        :param dumper: The dumper to register for `!cls`.

        If `!cls` is specified as string it will be lazy-loaded, so that it
        will be possible to register it without importing it before. In this
        case it should be the fully qualified name of the object (e.g.
        ``"uuid.UUID"``).

        If `!cls` is None, only use the dumper when looking up using
        `get_dumper_by_oid()`, which happens when we know the Postgres type to
        adapt to, but not the Python type that will be adapted (e.g. in COPY
        after using `~psycopg.Copy.set_types()`).

        Nz-dumpers should be registered on classes, got  insteadT)
isinstancestrtype	TypeErrorr   _get_optimisedr   Zfrom_pqformatZAUTOr   r   r   oidr    r   )r#   r+   r,   r   r   r   r   register_dumperp   s&    



zAdaptersMap.register_dumperz	int | strztype[Loader])r4   loaderr%   c                 C  s~   t |tr| j| j}t |ts0td| dtr>| |}|j}| j	| sl| j
|  | j
|< d| j	|< || j
| |< dS )aH  
        Configure the context to use `!loader` to convert data of oid `!oid`.

        :param oid: The PostgreSQL OID or type name to manage.
        :param loader: The loar to register for `!oid`.

        If `oid` is specified as string, it refers to a type name, which is
        looked up in the `types` registry.

        z)loaders should be registered on oid, got r-   TN)r.   r/   r   r4   intr1   r   r2   r3   r!   r   r   )r#   r4   r6   r   r   r   r   register_loader   s    




zAdaptersMap.register_loaderr0   r   )r+   r3   r%   c              	   C  s   z| j | | W S  tk
rF   || j kr8td| | j | }Y nX |jD ]J}||krf||   S |jd |j }||krN|| }||< |  S qNt|}t	d|j
d|j d|j ddS )aL  
        Return the dumper class for the given type and format.

        Raise `~psycopg.ProgrammingError` if a class is not available.

        :param cls: The class to adapt.
        :param format: The format to dump to. If `~psycopg.adapt.PyFormat.AUTO`,
            use the last one of the dumpers registered on `!cls`.
        bad dumper format: .zcannot adapt type z using placeholder '%z' (format: )N)r   KeyError
ValueError__mro__
__module____qualname__popr   eProgrammingError__name__valuename)r#   r+   r3   dmapZsclsZfqndr   r   r   
get_dumper   s"    



zAdaptersMap.get_dumperr7   z	pq.Format)r4   r3   r%   c                 C  s   z| j | }W n" tk
r0   td| Y nX z
|| W S  tk
r   | j|}|r~d|j d| dt|j }nd| dt|j }t	|Y nX dS )z
        Return the dumper class for the given oid and format.

        Raise `~psycopg.ProgrammingError` if a class is not available.

        :param oid: The oid of the type to dump to.
        :param format: The format to dump to.
        r9   zcannot find a dumper for type z (oid z	) format z/cannot find a dumper for unknown type with oid z format N)
r   r<   r=   r   getrF   r   ZFormatrB   rC   )r#   r4   r3   rG   infomsgr   r   r   get_dumper_by_oid   s    	
zAdaptersMap.get_dumper_by_oidztype[Loader] | Nonec                 C  s   | j | |S )z
        Return the loader class for the given oid and format.

        Return `!None` if not found.

        :param oid: The oid of the type to load.
        :param format: The format to load from.
        )r   rJ   )r#   r4   r3   r   r   r   
get_loader  s    	zAdaptersMap.get_loadertype[RV])r+   r%   c                 C  sp   z| j | W S  tk
r    Y nX ddlm} |j|jrbtdtt	|jd}|rb|| j |< |S || j |< |S )zReturn the optimised version of a Dumper or Loader class.

        Return the input class itself if there is no optimised version.
        r   )r   rO   N)
r   r<   Zpsycopgr   r?   
startswithrD   r   getattrr   )r#   r+   r   newr   r   r   r2     s    

zAdaptersMap._get_optimised)NN)rD   r?   r@   __doc____annotations__r   r$   propertyr(   r)   r5   r8   rI   rM   rN   classmethodr2   r   r   r   r   r      s*   
"  !3'r   TFN)rS   
__future__r   typingr   r   r    r   r   rB   abcr	   r
   Z_enumsr   _compatr   Z_cmoduler   Z	_typeinfor   Z_connection_baser   r   r   dictfromkeysr"   r   r   r   r   r   <module>   s"     