a
    ߙfb/                     @   s   d gZ ddlZddlmZ ddlm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mZ dd	lmZ dd
lmZmZ ddlmZ ddlmZ edZdd ZdddZdd Z G dd dZ!e!j"Z#dS )quantity_input    N)Number)Sequence)wraps   )_typing)UnitUnitBase
UnitsErroradd_enabled_equivalenciesdimensionless_unscaled)FunctionUnitBase)PhysicalTypeget_physical_type)Quantity)StructuredUnitc                 C   sz   g }| D ]l}zt |}W nP ttfyh   zt|j}W n* tttfyb   td|ddY n0 Y n0 || q|S )z
    From a list of target units (either as strings or unit objects) and physical
    types, return a list of Unit objects.
    zInvalid unit or physical type .N)r   	TypeError
ValueErrorr   Z_unitKeyErrorappend)targetsallowed_unitstargetunit r   7lib/python3.9/site-packages/astropy/units/decorators.py_get_allowed_units   s    r   Fc                 C   s4  t |dkrdS t|}t|v r\|s\t|ds\t|tr<dS t|tjr\t|j	tj
r\dS |D ]h}z |jj||d}|rW  q0W q` ty   t|drd}	nd}	td|  d| d	|	 d
Y q`0 q`d|  d| d}	t |dkrddd |D }
t|	 d|
 dnt|	 dt|d  ddS )z}
    Validates the object passed in to the wrapped function, ``arg``, with target
    unit or physical type, ``target``.
    r   Nr   )equivalenciesz4a 'unit' attribute without an 'is_equivalent' methodzno 'unit' attributez
Argument 'z' to function 'z' has z1. You should pass in an astropy Quantity instead.z!' must be in units convertible tor   z, c                 S   s   g | ]}d t | d qS )')str).0Ztargr   r   r   
<listcomp>[       z'_validate_arg_value.<locals>.<listcomp>z	 one of: r   z 'z'.)lenr   r   hasattr
isinstancer   npZndarrayZ
issubdtypeZdtypeZnumberr   is_equivalentAttributeErrorr   joinr
   r    )Z
param_nameZ	func_nameargr   r   strict_dimensionlessr   Zallowed_unitr(   Z	error_msgZ
targ_namesr   r   r   _validate_arg_value.   s>    

r-   c                 C   s   | d t tjfv r| S zt| }W n` ttfy   zt| }W n4 tttfyr   t| t	rntd| dd Y n
0 | Y S Y n0 |S t
| }|t
ju rdd t
| D S |t
jurdS t
| ^}}t|tr|sdS |^}}t|ttfsdS |S )Nzinvalid unit or physical type r   c                 S   s   g | ]}t |qS r   )_parse_annotationr!   tr   r   r   r"   w   r#   z%_parse_annotation.<locals>.<listcomp>F)NoneTypeinspectZ_emptyr   r   r   r   r   r&   r    T
get_originUnionget_args	Annotated
issubclassr   r	   r   )r   r   Zptypeoriginclsannotationsrestr   r   r   r.   a   s0    



r.   c                   @   s,   e Zd Zed	ddZd
ddZdd ZdS )QuantityInputNc                 K   s*   | f i |}|dur"|s"||S |S dS )a	  
        A decorator for validating the units of arguments to functions.

        Unit specifications can be provided as keyword arguments to the
        decorator, or by using function annotation syntax. Arguments to the
        decorator take precedence over any function annotations present.

        A `~astropy.units.UnitsError` will be raised if the unit attribute of
        the argument is not equivalent to the unit specified to the decorator or
        in the annotation. If the argument has no unit attribute, i.e. it is not
        a Quantity object, a `ValueError` will be raised unless the argument is
        an annotation. This is to allow non Quantity annotations to pass
        through.

        Where an equivalency is specified in the decorator, the function will be
        executed with that equivalency in force.

        Notes
        -----

        The checking of arguments inside variable arguments to a function is not
        supported (i.e. \*arg or \**kwargs).

        The original function is accessible by the attributed ``__wrapped__``.
        See :func:`functools.wraps` for details.

        Examples
        --------

        .. code-block:: python

            import astropy.units as u
            @u.quantity_input(myangle=u.arcsec)
            def myfunction(myangle):
                return myangle**2


        .. code-block:: python

            import astropy.units as u
            @u.quantity_input
            def myfunction(myangle: u.arcsec):
                return myangle**2

        Or using a unit-aware Quantity annotation.

        .. code-block:: python

            @u.quantity_input
            def myfunction(myangle: u.Quantity[u.arcsec]):
                return myangle**2

        Also you can specify a return value annotation, which will
        cause the function to always return a `~astropy.units.Quantity` in that
        unit.

        .. code-block:: python

            import astropy.units as u
            @u.quantity_input
            def myfunction(myangle: u.arcsec) -> u.deg**2:
                return myangle**2

        Using equivalencies::

            import astropy.units as u
            @u.quantity_input(myenergy=u.eV, equivalencies=u.mass_energy())
            def myfunction(myenergy):
                return myenergy**2

        Nr   )r:   funckwargsselfr   r   r   as_decorator   s    IzQuantityInput.as_decoratorFc                 K   s   | dg | _|| _|| _d S )Nr   )popr   decorator_kwargsr,   )r@   r>   r,   r?   r   r   r   __init__   s    zQuantityInput.__init__c                    s&   t t fdd}|S )Nc                     s  j | i |}j D ]}|jtjjtjjfv r8q|j|j	vr^|j
|jur^|j
|j	|j< |j	|j }|j jv r j|j }d}n|j}d}t|}|tjju rq|d u r|j
d u rqt|tst|ts|g}n2d |v st|v r|d u rqndd |D }n|}|rdd |D }t|jj|| j j qt j | i |}W d    n1 sj0    Y  j}	tjjd ttjf}
|	|
vrt|	tjtjfvr|	nt|	}t|tst|ts|g}dd |D }tdj|| j j t|dkr||d K }|S )	NFTc                 S   s   g | ]}|d ur|qS )Nr   r/   r   r   r   r"     r#   z;QuantityInput.__call__.<locals>.wrapper.<locals>.<listcomp>c                 S   s    g | ]}t |tttfr|qS r   r&   r    r	   r   r/   r   r   r   r"   %  s   c                 S   s    g | ]}t |tttfr|qS r   rE   r/   r   r   r   r"   :  s   returnr   ) Zbind
parametersvalueskindr2   Z	ParameterZVAR_KEYWORDZVAR_POSITIONALnameZ	argumentsdefaultemptyrC   
annotationr.   r&   r    r   r1   r-   __name__r   r,   r   Zreturn_annotationZ	Signaturer3   NoReturnr4   r7   r5   r$   )Z	func_argsZfunc_kwargsZ
bound_argsZparamr+   r   Zis_annotationZvalid_targetsZreturn_ZraZvalid_emptyr   r@   wrapped_functionZwrapped_signaturer   r   wrapper   sl    



.
z'QuantityInput.__call__.<locals>.wrapper)r2   Z	signaturer   )r@   rQ   rR   r   rP   r   __call__   s    
^zQuantityInput.__call__)N)NF)rN   
__module____qualname__classmethodrA   rD   rS   r   r   r   r   r=      s   N
r=   )F)$__all__r2   Znumbersr   collections.abcr   	functoolsr   Znumpyr'    r   r3   corer   r	   r
   r   r   Zfunction.corer   Zphysicalr   r   Zquantityr   Z
structuredr   typer1   r   r-   r.   r=   rA   r   r   r   r   r   <module>   s&    
3' ?