B
    Afxa/                 @   sJ  d Z ddlZddlmZ ddlmZ ddlmZmZm	Z	m
Z
mZ ddlmZ ddlmZ dd	lmZ dd
lmZmZ erddlmZ ddlmZ e
dZdd Zd ddZd!ddZdd Zd"deede	e e	d df eede	e e	d df eeedef gedee f f dddZ deeeddf eegef dddZ!dS )#z
    pint.registry_helpers
    ~~~~~~~~~~~~~~~~~~~~~

    Miscellaneous methods of the registry written as separate functions.

    :copyright: 2016 by Pint Authors, see AUTHORS for more details..
    :license: BSD, see LICENSE for more details.
    N)	signature)zip_longest)TYPE_CHECKINGCallableIterableTypeVarUnion   )F)DimensionalityError)Quantity)UnitsContainerto_units_container)UnitRegistry)UnitTc             C   s:   d}x$|   D ]\}}||| |  }qW t|dti S )zConvert a unit compatible type to a UnitsContainer.

    Parameters
    ----------
    original_units :
        a UnitsContainer instance.
    values_by_name :
        a map between original names and the new values.

    Returns
    -------

    r	   _units)itemsgetattrr   )Zoriginal_unitsvalues_by_nameqZarg_nameZexponent r   4lib/python3.7/site-packages/pint/registry_helpers.py_replace_units   s    r   c             C   s8   t | tr*d| kr*t| ddd dfS t| |dfS )a#  Convert a unit compatible type to a UnitsContainer,
    checking if it is string field prefixed with an equal
    (which is considered a reference)

    Parameters
    ----------
    a :

    registry :
         (Default value = None)

    Returns
    -------
    UnitsContainer, bool


    =r	   TF)
isinstancestrr   split)aregistryr   r   r   _to_units_container1   s    r    c       	         s  t  }t  t  t  fdd| D  xt D ]\}\}}|d krLq4q4|rt|dkr| \\}}|dkr||kr|| | |df |< q| q| q4| q4W xDD ]<} | \}}t|tsqt | |kstd| |  qW  fdd}|S )Nc                s   g | ]}t | qS r   )r    ).0arg)r   r   r   
<listcomp>V   s    z$_parse_wrap_args.<locals>.<listcomp>r	   TzfFound a missing token while wrapping a function: Not all variable referenced in %s are defined using !c          	      s\  t dd |D }i }x4D ],}|| }|| | d < t|d|||< qW xbD ]Z}|| }t | d |d k	sxt| t|d|t|dti t | d |||< qRW xD ]}t|| | jr| || j|| j	 | d ||< q|rt|| t
r4| || }| |j|j	 | d ||< qtd | d || qW ||fS )Nc             s   s   | ]
}|V  qd S )Nr   )r!   valuer   r   r   	<genexpr>z   s    z7_parse_wrap_args.<locals>._converter.<locals>.<genexpr>r   
_magnituder   zA wrapped function using strict=True requires quantity or a string for all arguments with not None units. (error found for {}, {}))listr   r   AssertionError_convertr   r   r   r&   r   r   Zparse_expression
ValueErrorformat)uregvaluesstrict
new_valuesr   ndxr$   Z	tmp_value)
args_as_ucdefs_args_ndxdependent_args_ndxunit_args_ndxr   r   
_convertery   s4    



$z$_parse_wrap_args.<locals>._converter)	set	enumeratelenr   addr   dictkeysr*   )	argsr   Z	defs_argsr0   r"   is_refkeyr$   r5   r   )r1   r2   r3   r   r4   r   _parse_wrap_argsH   s8    



/r?   c                sb   t | }|j|| x,|j D ]}|j jkr |j j|j< q W  fdd|j D }|i fS )zApply default keyword arguments.

    Named keywords may have been left blank. This function applies the default
    values so that every argument is defined.
    c                s   g | ]} j | qS r   )	arguments)r!   r>   )bound_argumentsr   r   r#      s    z#_apply_defaults.<locals>.<listcomp>)r   Zbind
parametersr-   namer@   defaultr;   )funcr<   kwargsZsigZparamr   )rA   r   _apply_defaults   s    rG   Tr   r   .)r,   retr<   r.   returnc                s(  t  ttfs f x8 D ]0}|dk	rt |jtfstdt||f qW t t ttfrx8D ]0}|dk	rnt |jtfsntdt||f qnW fddD n6dk	rt jtfstdtf t	t
dtf t
dtt f d fdd	}|S )
a  Wraps a function to become pint-aware.

    Use it when a function requires a numerical value but in some specific
    units. The wrapper function will take a pint quantity, convert to the units
    specified in `args` and then call the wrapped function with the resulting
    magnitude.

    The value returned by the wrapped function will be converted to the units
    specified in `ret`.

    Parameters
    ----------
    ureg : pint.UnitRegistry
        a UnitRegistry instance.
    ret : str, pint.Unit, iterable of str, or iterable of pint.Unit
        Units of each of the return values. Use `None` to skip argument conversion.
    args : str, pint.Unit, iterable of str, or iterable of pint.Unit
        Units of each of the input arguments. Use `None` to skip argument conversion.
    strict : bool
        Indicates that only quantities are accepted. (Default value = True)

    Returns
    -------
    callable
        the wrapper function.

    Raises
    ------
    TypeError
        if the number of given arguments does not match the number of function parameters.
        if the any of the provided arguments is not a unit a string or Quantity

    Nz8wraps arguments must by of type str or Unit, not %s (%s)z=wraps 'ret' argument must by of type str or Unit, not %s (%s)c                s   g | ]}t | qS r   )r    )r!   r"   )r,   r   r   r#      s    zwraps.<locals>.<listcomp>.)rE   rI   c                s   t t j}t |kr2td j|t f t fddtjD }t fddtjD }tj	 ||dt
t d fdd}|S )	Nz0%s takes %i parameters, but %i units were passedc             3   s   | ]}t  |r|V  qd S )N)hasattr)r!   attr)rE   r   r   r%   
  s    z+wraps.<locals>.decorator.<locals>.<genexpr>c             3   s   | ]}t  |r|V  qd S )N)rJ   )r!   rK   )rE   r   r   r%     s    )assignedupdated)rI   c                 s   t | |\} }| \} ||}r^ fddD }fddt||D S d d krn|S |d rtd  nd S )Nc             3   s$   | ]\}}|rt | n|V  qd S )N)r   )r!   rr=   )r   r   r   r%     s   z<wraps.<locals>.decorator.<locals>.wrapper.<locals>.<genexpr>c             3   s*   | ]"\}}|d kr|n
  ||V  qd S )N)r   )r!   unitZres)r,   r   r   r%   !  s   r   r	   )rG   	__class__r   r   r   )r-   kwr/   resultZ	out_units)	converterrE   is_ret_containerrH   r.   r,   )r   r   wrapper  s    


z)wraps.<locals>.decorator.<locals>.wrapper)r8   r   rB   	TypeError__name__tuple	functoolsWRAPPER_ASSIGNMENTSWRAPPER_UPDATESwrapsr   r   )rE   count_paramsrL   rM   rU   )r<   rS   rT   rH   r.   r,   )rE   r   	decorator   s    "zwraps.<locals>.decorator)r   r'   rX   r   r   rV   typer?   rP   r    r   r   r   )r,   rH   r<   r.   r"   r^   r   )r<   rS   rT   rH   r.   r,   r   r\      s.    (


2.r\   )r,   r<   rI   c                s$   fdd|D   fdd}|S )a"  Decorator to for quantity type checking for function inputs.

    Use it to ensure that the decorated function input parameters match
    the expected dimension of pint quantity.

    The wrapper function raises:
      - `pint.DimensionalityError` if an argument doesn't match the required dimensions.

    ureg : UnitRegistry
        a UnitRegistry instance.
    args : str or UnitContainer or None
        Dimensions of each of the input arguments.
        Use `None` to skip argument conversion.

    Returns
    -------
    callable
        the wrapped function.

    Raises
    ------
    TypeError
        If the number of given dimensions does not match the number of function
        parameters.
    ValueError
        If the any of the provided dimensions cannot be parsed as a dimension.
    c                s"   g | ]}|d k	r  |nd qS )N)get_dimensionality)r!   dim)r,   r   r   r#   P  s    zcheck.<locals>.<listcomp>c                s   t t j}t |kr2td j|t f t fddtjD }t fddtjD }tj	 ||d fdd}|S )Nz5%s takes %i parameters, but %i dimensions were passedc             3   s   | ]}t  |r|V  qd S )N)rJ   )r!   rK   )rE   r   r   r%   ]  s    z+check.<locals>.decorator.<locals>.<genexpr>c             3   s   | ]}t  |r|V  qd S )N)rJ   )r!   rK   )rE   r   r   r%   `  s    )rL   rM   c                 sd   t | |\}}xHt |D ]:\}}|d kr.q||s|}t|d||qW | |S )Nza quantity of)rG   zipr   checkr`   r   )r<   rF   Z	list_argsemptyra   r$   Zval_dim)
dimensionsrE   r,   r   r   rU   c  s    
z)check.<locals>.decorator.<locals>.wrapper)
r8   r   rB   rV   rW   rX   rY   rZ   r[   r\   )rE   r]   rL   rM   rU   )re   r,   )rE   r   r^   S  s     zcheck.<locals>.decoratorr   )r,   r<   r^   r   )re   r,   r   rc   1  s     rc   )N)N)T)"__doc__rY   inspectr   	itertoolsr   typingr   r   r   r   r   Z_typingr
   errorsr   Zquantityr   utilr   r   r   r   rO   r   r   r   r    r?   rG   r   boolr\   rc   r   r   r   r   <module>	   s(   

c6,r