a
    ߙfbU                    @   sd  d Z ddl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
 ddlmZ ddlmZmZmZmZ ddlmZ g d	Zd
Zdd Zdd ZG dd dZG dd dZe gZdd Zdd Zdd Zdd Zdd Z dd Z!dd  Z"G d!d" d"e#Z$G d#d$ d$e$e%Z&G d%d& d&e$e%Z'G d'd( d(e$e(Z)G d)d* d*e
Z*G d+d, d,Z+G d-d. d.e+Z,d/d0 Z-G d1d2 d2e,Z.G d3d4 d4e.Z/G d5d6 d6e0Z1G d7d8 d8e,e1d9Z2G d:d; d;e2Z3G d<d= d=e+Z4d>gd?gd@fdAgdBgdCfdDgdEgdFfdGgdHgdIfdJgdKgdLfdMgdNgdOfdPgdQgdRfdSgdTgdUfdVgdWgdXfdYgdZd[gd\fd]gd^gd_fd`gdagdbfdcgddgdefdfgdggdhfdigdjgdkfdlgdmgdnfdogdpgdqfdrgdsgdtfdugdvgdwfdxgdygdzfgZ5d{gd|gd}fd~gdgdfdgdgdfdgdgdfdgdgdfdgdgdfgZ6g ddfddZ7ddddg dfddZ8dd Z9dd Z:e4dg g ddZ;e;Z<e&ej=_&dS )z"
Core units classes and functions
    N)lazyproperty)AstropyWarning)
isiterable   )is_effectively_unitysanitize_scalevalidate_powerresolve_fractionsformat)
UnitsErrorUnitsWarningUnitConversionErrorUnitTypeErrorUnitBase	NamedUnitIrreducibleUnitUnitCompositeUnit
PrefixUnitUnrecognizedUnitdef_unitget_current_unit_registryset_enabled_unitsadd_enabled_unitsset_enabled_equivalenciesadd_enabled_equivalenciesset_enabled_aliasesadd_enabled_aliasesdimensionless_unscaledone      ?c                 C   s   t | ts| g} t }| D ]t}t |tr4|| qt |trH| }n(t|r`t	| }nt
|r|}nq|D ]}t |trt|| qtq|S )z
    Given a list of sequences, modules or dictionaries of units, or
    single units, return a flat set of all the units found.
    )
isinstancelistsetr   adddictvaluesinspectismodulevarsr   )itemsresultitemunitsunit r0   1lib/python3.9/site-packages/astropy/units/core.py_flatten_units_collection$   s"    





r2   c                 C   s   | du rg S g }t | D ]\}}t|dkrB|\}}dd  }}nJt|dkr^|\}}}|}n.t|dkrx|\}}}}ntd| d||t|u r|du s|t|u rt|rt|std| d||||||f q|S )	a  
    Normalizes equivalencies, ensuring each is a 4-tuple of the form::

    (from_unit, to_unit, forward_func, backward_func)

    Parameters
    ----------
    equivalencies : list of equivalency pairs

    Raises
    ------
    ValueError if an equivalency cannot be interpreted
    N   c                 S   s   | S Nr0   xr0   r0   r1   <lambda>W       z*_normalize_equivalencies.<locals>.<lambda>      zInvalid equivalence entry z: )	enumeratelen
ValueErrorr   callableappend)equivalencies
normalizediZequivfunittunitabr0   r0   r1   _normalize_equivalenciesA   s:    

rG   c                   @   s   e Zd ZdZg g i fddZdd Zdd Zdd	 Zed
d Z	edd Z
edd Zdd Zdd Zdd Zedd Zdd Zdd Zedd Zdd Zd d! Zd"S )#_UnitRegistryz2
    Manages a registry of the enabled units.
    c                 C   s   t |tr^|j | _|j | _|j | _|j | _|j | _dd |j	 D | _n6| 
  |   |   | | | | | | d S )Nc                 S   s   i | ]\}}||  qS r0   )copy).0kvr0   r0   r1   
<dictcomp>~   r8   z*_UnitRegistry.__init__.<locals>.<dictcomp>)r"   rH   _equivalenciesrI   _aliases
_all_units	_registry_non_prefix_units_by_physical_typer+   _reset_units_reset_equivalencies_reset_aliasesr   r   r   )selfinitr@   aliasesr0   r0   r1   __init__p   s    



z_UnitRegistry.__init__c                 C   s    t  | _t  | _i | _i | _d S r4   )r$   rP   rR   rQ   rS   rW   r0   r0   r1   rT      s    z_UnitRegistry._reset_unitsc                 C   s   t  | _d S r4   )r$   rN   r[   r0   r0   r1   rU      s    z"_UnitRegistry._reset_equivalenciesc                 C   s
   i | _ d S r4   rO   r[   r0   r0   r1   rV      s    z_UnitRegistry._reset_aliasesc                 C   s   | j S r4   )rQ   r[   r0   r0   r1   registry   s    z_UnitRegistry.registryc                 C   s   | j S r4   )rP   r[   r0   r0   r1   	all_units   s    z_UnitRegistry.all_unitsc                 C   s   | j S r4   )rR   r[   r0   r0   r1   non_prefix_units   s    z_UnitRegistry.non_prefix_unitsc                 C   s   |    | |S )a!  
        Sets the units enabled in the unit registry.

        These units are searched when using
        `UnitBase.find_equivalent_units`, for example.

        Parameters
        ----------
        units : list of sequence, dict, or module
            This is a list of things in which units may be found
            (sequences, dicts or modules), or units themselves.  The
            entire set will be "enabled" for searching through by
            methods like `UnitBase.find_equivalent_units` and
            `UnitBase.compose`.
        )rT   r   )rW   r.   r0   r0   r1   r      s    z_UnitRegistry.set_enabled_unitsc                 C   s   t |}|D ]}|jD ]*}|| jv r|| j| krtd|q|jD ]}|| j|< qH| j| t|tsz| j	| |
 }| j|t | qdS )a<  
        Adds to the set of units enabled in the unit registry.

        These units are searched when using
        `UnitBase.find_equivalent_units`, for example.

        Parameters
        ----------
        units : list of sequence, dict, or module
            This is a list of things in which units may be found
            (sequences, dicts or modules), or units themselves.  The
            entire set will be added to the "enabled" set for
            searching through by methods like
            `UnitBase.find_equivalent_units` and `UnitBase.compose`.
        zvObject with name {!r} already exists in namespace. Filter the set of units to avoid name clashes before enabling them.N)r2   _namesrQ   r=   r   rP   r%   r"   r   rR   _get_physical_type_idrS   
setdefaultr$   )rW   r.   r/   sthashr0   r0   r1   r      s     


z_UnitRegistry.add_enabled_unitsc                 C   s   | j | t S )z
        Get all units in the registry with the same physical type as
        the given unit.

        Parameters
        ----------
        unit : UnitBase instance
        )rS   getra   r$   rW   r/   r0   r0   r1   get_units_with_physical_type   s    	z*_UnitRegistry.get_units_with_physical_typec                 C   s
   t | jS r4   )r#   rN   r[   r0   r0   r1   r@      s    z_UnitRegistry.equivalenciesc                 C   s   |    | |S )a  
        Sets the equivalencies enabled in the unit registry.

        These equivalencies are used if no explicit equivalencies are given,
        both in unit conversion and in finding equivalent units.

        This is meant in particular for allowing angles to be dimensionless.
        Use with care.

        Parameters
        ----------
        equivalencies : list of tuple
            List of equivalent pairs, e.g., as returned by
            `~astropy.units.equivalencies.dimensionless_angles`.
        )rU   r   rW   r@   r0   r0   r1   r      s    z'_UnitRegistry.set_enabled_equivalenciesc                 C   s   t |}|  jt|O  _dS )a  
        Adds to the set of equivalencies enabled in the unit registry.

        These equivalencies are used if no explicit equivalencies are given,
        both in unit conversion and in finding equivalent units.

        This is meant in particular for allowing angles to be dimensionless.
        Use with care.

        Parameters
        ----------
        equivalencies : list of tuple
            List of equivalent pairs, e.g., as returned by
            `~astropy.units.equivalencies.dimensionless_angles`.
        N)rG   rN   r$   rh   r0   r0   r1   r      s    z'_UnitRegistry.add_enabled_equivalenciesc                 C   s   | j S r4   r\   r[   r0   r0   r1   rY     s    z_UnitRegistry.aliasesc                 C   s   |    | | dS )a  
        Set aliases for units.

        Parameters
        ----------
        aliases : dict of str, Unit
            The aliases to set. The keys must be the string aliases, and values
            must be the `astropy.units.Unit` that the alias will be mapped to.

        Raises
        ------
        ValueError
            If the alias already defines a different unit.

        N)rV   r   )rW   rY   r0   r0   r1   r     s    z!_UnitRegistry.set_enabled_aliasesc                 C   s   |  D ]x\}}|| jv rH|| j| krHt| d| j|  d| d|| jv r|| j| krt| d| j|  d| dq|  D ]&\}}|| jvr|| jvr|| j|< qdS )a  
        Add aliases for units.

        Parameters
        ----------
        aliases : dict of str, Unit
            The aliases to add. The keys must be the string aliases, and values
            must be the `astropy.units.Unit` that the alias will be mapped to.

        Raises
        ------
        ValueError
            If the alias already defines a different unit.

        z already means z$, so cannot be used as an alias for .z already is an alias for N)r+   rQ   r=   rO   )rW   rY   aliasr/   r0   r0   r1   r   '  s     z!_UnitRegistry.add_enabled_aliasesN)__name__
__module____qualname____doc__rZ   rT   rU   rV   propertyr]   r^   r_   r   r   rg   r@   r   r   rY   r   r   r0   r0   r0   r1   rH   k   s,   


&

rH   c                   @   s*   e Zd Zg g fddZdd Zdd ZdS )_UnitContextc                 C   s   t t||d d S )N)rX   r@   )_unit_registriesr?   rH   )rW   rX   r@   r0   r0   r1   rZ   G  s    
z_UnitContext.__init__c                 C   s   d S r4   r0   r[   r0   r0   r1   	__enter__K  s    z_UnitContext.__enter__c                 C   s   t   d S r4   )rq   pop)rW   typevaluetbr0   r0   r1   __exit__N  s    z_UnitContext.__exit__N)rk   rl   rm   rZ   rr   rw   r0   r0   r0   r1   rp   F  s   rp   c                   C   s   t d S )N)rq   r0   r0   r0   r1   r   U  s    r   c                 C   s   t t jd}t |  |S )a  
    Sets the units enabled in the unit registry.

    These units are searched when using
    `UnitBase.find_equivalent_units`, for example.

    This may be used either permanently, or as a context manager using
    the ``with`` statement (see example below).

    Parameters
    ----------
    units : list of sequence, dict, or module
        This is a list of things in which units may be found
        (sequences, dicts or modules), or units themselves.  The
        entire set will be "enabled" for searching through by methods
        like `UnitBase.find_equivalent_units` and `UnitBase.compose`.

    Examples
    --------

    >>> from astropy import units as u
    >>> with u.set_enabled_units([u.pc]):
    ...     u.m.find_equivalent_units()
    ...
      Primary name | Unit definition | Aliases
    [
      pc           | 3.08568e+16 m   | parsec  ,
    ]
    >>> u.m.find_equivalent_units()
      Primary name | Unit definition | Aliases
    [
      AU           | 1.49598e+11 m   | au, astronomical_unit            ,
      Angstrom     | 1e-10 m         | AA, angstrom                     ,
      cm           | 0.01 m          | centimeter                       ,
      earthRad     | 6.3781e+06 m    | R_earth, Rearth                  ,
      jupiterRad   | 7.1492e+07 m    | R_jup, Rjup, R_jupiter, Rjupiter ,
      lsec         | 2.99792e+08 m   | lightsecond                      ,
      lyr          | 9.46073e+15 m   | lightyear                        ,
      m            | irreducible     | meter                            ,
      micron       | 1e-06 m         |                                  ,
      pc           | 3.08568e+16 m   | parsec                           ,
      solRad       | 6.957e+08 m     | R_sun, Rsun                      ,
    ]
    r@   )rp   r   r@   r   r.   contextr0   r0   r1   r   Y  s
    .r   c                 C   s   t t }t |  |S )a  
    Adds to the set of units enabled in the unit registry.

    These units are searched when using
    `UnitBase.find_equivalent_units`, for example.

    This may be used either permanently, or as a context manager using
    the ``with`` statement (see example below).

    Parameters
    ----------
    units : list of sequence, dict, or module
        This is a list of things in which units may be found
        (sequences, dicts or modules), or units themselves.  The
        entire set will be added to the "enabled" set for searching
        through by methods like `UnitBase.find_equivalent_units` and
        `UnitBase.compose`.

    Examples
    --------

    >>> from astropy import units as u
    >>> from astropy.units import imperial
    >>> with u.add_enabled_units(imperial):
    ...     u.m.find_equivalent_units()
    ...
      Primary name | Unit definition | Aliases
    [
      AU           | 1.49598e+11 m   | au, astronomical_unit            ,
      Angstrom     | 1e-10 m         | AA, angstrom                     ,
      cm           | 0.01 m          | centimeter                       ,
      earthRad     | 6.3781e+06 m    | R_earth, Rearth                  ,
      ft           | 0.3048 m        | foot                             ,
      fur          | 201.168 m       | furlong                          ,
      inch         | 0.0254 m        |                                  ,
      jupiterRad   | 7.1492e+07 m    | R_jup, Rjup, R_jupiter, Rjupiter ,
      lsec         | 2.99792e+08 m   | lightsecond                      ,
      lyr          | 9.46073e+15 m   | lightyear                        ,
      m            | irreducible     | meter                            ,
      mi           | 1609.34 m       | mile                             ,
      micron       | 1e-06 m         |                                  ,
      mil          | 2.54e-05 m      | thou                             ,
      nmi          | 1852 m          | nauticalmile, NM                 ,
      pc           | 3.08568e+16 m   | parsec                           ,
      solRad       | 6.957e+08 m     | R_sun, Rsun                      ,
      yd           | 0.9144 m        | yard                             ,
    ]
    )rp   r   r   rz   r0   r0   r1   r     s    2
r   c                 C   s   t t }t |  |S )aV  
    Sets the equivalencies enabled in the unit registry.

    These equivalencies are used if no explicit equivalencies are given,
    both in unit conversion and in finding equivalent units.

    This is meant in particular for allowing angles to be dimensionless.
    Use with care.

    Parameters
    ----------
    equivalencies : list of tuple
        list of equivalent pairs, e.g., as returned by
        `~astropy.units.equivalencies.dimensionless_angles`.

    Examples
    --------
    Exponentiation normally requires dimensionless quantities.  To avoid
    problems with complex phases::

        >>> from astropy import units as u
        >>> with u.set_enabled_equivalencies(u.dimensionless_angles()):
        ...     phase = 0.5 * u.cycle
        ...     np.exp(1j*phase)  # doctest: +FLOAT_CMP
        <Quantity -1.+1.2246468e-16j>
    )rp   r   r   r@   r{   r0   r0   r1   r     s    
r   c                 C   s   t t }t |  |S )a>  
    Adds to the equivalencies enabled in the unit registry.

    These equivalencies are used if no explicit equivalencies are given,
    both in unit conversion and in finding equivalent units.

    This is meant in particular for allowing angles to be dimensionless.
    Since no equivalencies are enabled by default, generally it is recommended
    to use `set_enabled_equivalencies`.

    Parameters
    ----------
    equivalencies : list of tuple
        list of equivalent pairs, e.g., as returned by
        `~astropy.units.equivalencies.dimensionless_angles`.
    )rp   r   r   r|   r0   r0   r1   r     s    
r   c                 C   s   t t }t |  |S )a  
    Set aliases for units.

    This is useful for handling alternate spellings for units, or
    misspelled units in files one is trying to read.

    Parameters
    ----------
    aliases : dict of str, Unit
        The aliases to set. The keys must be the string aliases, and values
        must be the `astropy.units.Unit` that the alias will be mapped to.

    Raises
    ------
    ValueError
        If the alias already defines a different unit.

    Examples
    --------
    To temporarily allow for a misspelled 'Angstroem' unit::

        >>> from astropy import units as u
        >>> with u.set_enabled_aliases({'Angstroem': u.Angstrom}):
        ...     print(u.Unit("Angstroem", parse_strict="raise") == u.Angstrom)
        True

    )rp   r   r   rY   r{   r0   r0   r1   r      s    
r   c                 C   s   t t }t |  |S )a[  
    Add aliases for units.

    This is useful for handling alternate spellings for units, or
    misspelled units in files one is trying to read.

    Since no aliases are enabled by default, generally it is recommended
    to use `set_enabled_aliases`.

    Parameters
    ----------
    aliases : dict of str, Unit
        The aliases to add. The keys must be the string aliases, and values
        must be the `astropy.units.Unit` that the alias will be mapped to.

    Raises
    ------
    ValueError
        If the alias already defines a different unit.

    Examples
    --------
    To temporarily allow for a misspelled 'Angstroem' unit::

        >>> from astropy import units as u
        >>> with u.add_enabled_aliases({'Angstroem': u.Angstrom}):
        ...     print(u.Unit("Angstroem", parse_strict="raise") == u.Angstrom)
        True

    )rp   r   r   r}   r0   r0   r1   r   #  s     
r   c                   @   s   e Zd ZdZdS )r   z6
    The base class for unit-specific exceptions.
    Nrk   rl   rm   rn   r0   r0   r0   r1   r   I  s   r   c                   @   s   e Zd ZdZdS )UnitScaleErrorzg
    Used to catch the errors involving scaled units,
    which are not recognized by FITS format.
    Nr~   r0   r0   r0   r1   r   O  s   r   c                   @   s   e Zd ZdZdS )r   z}
    Used specifically for errors related to converting between units or
    interpreting units in terms of other units.
    Nr~   r0   r0   r0   r1   r   W  s   r   c                   @   s   e Zd ZdZdS )r   z
    Used specifically for errors in setting to units not allowed by a class.

    E.g., would be raised if the unit of an `~astropy.coordinates.Angle`
    instances were set to a non-angular unit.
    Nr~   r0   r0   r0   r1   r   ^  s   r   c                   @   s   e Zd ZdZdS )r   z4
    The base class for unit-specific warnings.
    Nr~   r0   r0   r0   r1   r   g  s   r   c                   @   s  e Zd 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edd Zedd Zedd Zedd Zedd Zedd ZejfddZdd Zed d! Zd"d# Zd$d% Zd&d' ZeZeZd(d) Zd*d+ Zd,d- Z d.d/ Z!d0d1 Z"d2d3 Z#d4d5 Z$d6d7 Z%d8d9 Z&d:d; Z'd<d= Z(d>d? Z)d@dA Z*g fdBdCZ+g fdDdEZ,dFdG Z-g fdHdIZ.dJdK Z/e0g fdLdMZ1dNg fdOdPZ2e3 fdQdRZ4g g dSdTdfdUdVZ5g ddSdfdWdXZ6dYdZ Z7e8d[d\ Z9e8d]d^ Z:ed_d` Z;g fdadbZ<G dcdd dde=Z>g ddefdfdgZ?dhdi Z@dS )jr   z
    Abstract base class for units.

    Most of the arithmetic operations on units are defined in this
    base class.

    Should not be instantiated by users directly.
    i  Nc                 C   s   | S r4   r0   )rW   memor0   r0   r1   __deepcopy__|  s    zUnitBase.__deepcopy__c                 C   s   t j| S )z
        Generate latex representation of unit name.  This is used by
        the IPython notebook to print a unit with a nice layout.

        Returns
        -------
        Latex string
        )unit_formatZLatex	to_stringr[   r0   r0   r1   _repr_latex_  s    	zUnitBase._repr_latex_c                 C   s   t j| dS )%Return string representation for unitZunicode_escape)r   Genericr   encoder[   r0   r0   r1   	__bytes__  s    zUnitBase.__bytes__c                 C   s   t j| S )r   r   r   r   r[   r0   r0   r1   __str__  s    zUnitBase.__str__c                 C   s   t j| }d| dS )NzUnit("z")r   )rW   stringr0   r0   r1   __repr__  s    zUnitBase.__repr__c                 C   s,   |   }tdd |jD |j}t|}|S )z
        Returns an identifier that uniquely identifies the physical
        type of this unit.  It is comprised of the bases and powers of
        this unit, without the scale.  Since it is hashable, it is
        useful as a dictionary key.
        c                 S   s   g | ]
}|j qS r0   namerJ   r6   r0   r0   r1   
<listcomp>  r8   z2UnitBase._get_physical_type_id.<locals>.<listcomp>)	decomposezipbasespowerstuple)rW   r/   rr0   r0   r1   ra     s    zUnitBase._get_physical_type_idc                 C   s   t ddS )E
        Returns all of the names associated with this unit.
        DCan not get names from unnamed units. Perhaps you meant to_string()?NAttributeErrorr[   r0   r0   r1   names  s    zUnitBase.namesc                 C   s   t ddS )O
        Returns the canonical (short) name associated with this unit.
        r   Nr   r[   r0   r0   r1   r     s    zUnitBase.namec                 C   s   t ddS )?
        Returns the alias (long) names for this unit.
        zFCan not get aliases from unnamed units. Perhaps you meant to_string()?Nr   r[   r0   r0   r1   rY     s    zUnitBase.aliasesc                 C   s   dS )z/
        Return the scale of the unit.
        r!   r0   r[   r0   r0   r1   scale  s    zUnitBase.scalec                 C   s   | gS )z/
        Return the bases of the unit.
        r0   r[   r0   r0   r1   r     s    zUnitBase.basesc                 C   s   dgS )z0
        Return the powers of the unit.
        r   r0   r[   r0   r0   r1   r     s    zUnitBase.powersc                 C   s   t |}|| S )a  
        Output the unit in the given format as a string.

        Parameters
        ----------
        format : `astropy.units.format.Base` instance or str
            The name of a format or a formatter object.  If not
            provided, defaults to the generic format.
        )r   
get_formatr   )rW   r   fr0   r0   r1   r     s    
zUnitBase.to_stringc                 C   s4   z| j |dW S  ty.   tt| | Y S 0 dS )z&Try to format units using a formatter.r
   N)r   r=   r   str)rW   format_specr0   r0   r1   
__format__  s    zUnitBase.__format__c                 C   s    t | }| dur|t j7 }|S )a:  
        Normalizes equivalencies, ensuring each is a 4-tuple of the form::

        (from_unit, to_unit, forward_func, backward_func)

        Parameters
        ----------
        equivalencies : list of equivalency pairs, or None

        Returns
        -------
        A normalized list, including possible global defaults set by, e.g.,
        `set_enabled_equivalencies`, except when `equivalencies`=`None`,
        in which case the returned list is always empty.

        Raises
        ------
        ValueError if an equivalency cannot be interpreted
        N)rG   r   r@   )r@   rA   r0   r0   r1   rG     s    z!UnitBase._normalize_equivalenciesc                 C   s   t |}td| g|gddS )Nr   F_error_check)r   r   )rW   pr0   r0   r1   __pow__  s    zUnitBase.__pow__c                 C   s|   t |ttfrt|}t |trD| r,| S td| |gddgddS zddlm} |d| | W S  t	yv   t
 Y S 0 d S )Nr   rx   Fr   Quantityr"   bytesr   r   r   is_unityr   quantityr   	TypeErrorNotImplementedrW   mr   r0   r0   r1   __div__  s    
zUnitBase.__div__c                 C   sv   t |ttfrt||  S z@ddlm} t|drH||}||  }|W S ||| d W S W n typ   t Y S 0 d S )Nr   r   r/   rx   	r"   r   r   r   r   r   hasattrr   r   rW   r   r   r,   r0   r0   r1   __rdiv__  s    
zUnitBase.__rdiv__c                 C   s   t |ttfrt|}t |trP| r,| S |  r8|S td| |gddgddS zddlm} |d| | W S  t	y   t
 Y S 0 d S )Nr   Fr   r   r   r   r0   r0   r1   __mul__2  s    
zUnitBase.__mul__c                 C   sr   t |ttfrt||  S z<ddlm} t|drH||}|| 9 }|W S ||| W S W n tyl   t Y S 0 d S )Nr   r   r/   r   r   r0   r0   r1   __rmul__D  s    
zUnitBase.__rmul__c                 C   s:   zddl m} ||| dddW S  ty4   t Y S 0 d S )Nr   r   FT)rI   Zsubok)r   r   	Exceptionr   r   r0   r0   r1   __rlshift__V  s
    zUnitBase.__rlshift__c                 C   s   t d| t tS )NzU>> is not implemented. Did you mean to convert to a Quantity with unit {} using '<<'?)warningswarnr   r   r   )rW   r   r0   r0   r1   __rrshift__]  s    zUnitBase.__rrshift__c                 C   sJ   | j d u rDt| jgdd | jD  dd | jD  }tt|| _ | j S )Nc                 S   s   g | ]
}|j qS r0   r   r   r0   r0   r1   r   f  r8   z%UnitBase.__hash__.<locals>.<listcomp>c                 S   s   g | ]}t |qS r0   r   r   r0   r0   r1   r   g  r8   )_hashr   r   r   r   rd   r   )rW   partsr0   r0   r1   __hash__c  s    

zUnitBase.__hash__c                 C   s   | j  }|dd  |S )Nr   )__dict__rI   rs   )rW   stater0   r0   r1   __getstate__k  s    
zUnitBase.__getstate__c              
   C   sr   | |u rdS zt |dd}W n tttfy8   t Y S 0 t|tsHtS zt| |W S  tyl   Y dS 0 d S )NTsilentparse_strictF)	r   r=   r   r   r   r"   r   r   _torW   otherr0   r0   r1   __eq__r  s    

zUnitBase.__eq__c                 C   s
   | |k S r4   r0   r   r0   r0   r1   __ne__  s    zUnitBase.__ne__c                 C   s   |  t|}|dkpt|S Nr!   r   r   r   rW   r   r   r0   r0   r1   __le__  s    zUnitBase.__le__c                 C   s   |  t|}|dkpt|S r   r   r   r0   r0   r1   __ge__  s    zUnitBase.__ge__c                 C   s
   | |k S r4   r0   r   r0   r0   r1   __lt__  s    zUnitBase.__lt__c                 C   s
   | |k S r4   r0   r   r0   r0   r1   __gt__  s    zUnitBase.__gt__c                 C   s   | d S )Ng      r0   r[   r0   r0   r1   __neg__  s    zUnitBase.__neg__c                    sD      t|tr,t fdd|D S t|dd}| S )a  
        Returns `True` if this unit is equivalent to ``other``.

        Parameters
        ----------
        other : `~astropy.units.Unit`, str, or tuple
            The unit to convert to. If a tuple of units is specified, this
            method returns true if the unit matches any of those in the tuple.

        equivalencies : list of tuple
            A list of equivalence pairs to try if the units are not
            directly convertible.  See :ref:`astropy:unit_equivalencies`.
            This list is in addition to possible global defaults set by, e.g.,
            `set_enabled_equivalencies`.
            Use `None` to turn off all equivalencies.

        Returns
        -------
        bool
        c                 3   s   | ]}j | d V  qdS )ry   N)is_equivalent)rJ   ur@   rW   r0   r1   	<genexpr>  s   z)UnitBase.is_equivalent.<locals>.<genexpr>r   r   )rG   r"   r   anyr   _is_equivalentrW   r   r@   r0   r   r1   r     s    

zUnitBase.is_equivalentc              	   C   s   t |trdS |  | kr"dS t|r|  }| }|D ]p\}}}}|du rz|| |g W  dS  ty|   Y q0 q>||r||s||r>||r> dS q>dS )a  Returns `True` if this unit is equivalent to `other`.
        See `is_equivalent`, except that a proper Unit object should be
        given (i.e., no string) and that the equivalency list should be
        normalized using `_normalize_equivalencies`.
        FTN)r"   r   ra   r<   r   r   r   )rW   r   r@   r/   rE   rF   ZforwardZbackwardr0   r0   r1   r     s.    
zUnitBase._is_equivalentc              	   C   s  dd }|D ]\}}}}|du rbz,|  |    |g}	||	j|dW   S  ty^   Y q0 qz&||}
||}||
||W   S  ty   Y n0 z&||}
||}||
||W   S  ty   Y q0 qdd }||}||}t| d| ddS )	zd
        Internal function (used from `_get_converter`) to apply
        equivalence pairs.
        c                    s    fdd}|S )Nc                    s    t |   S r4   _condition_argrL   funcscale1scale2r0   r1   convert  s    zFUnitBase._apply_equivalencies.<locals>.make_converter.<locals>.convertr0   )r   r   r   r   r0   r   r1   make_converter  s    z5UnitBase._apply_equivalencies.<locals>.make_converterNr!   c                 S   s<   |  d}| j}|dkr,d| d| d}nd| d}|S )NZunscaledunknown'z' ())r   physical_type)r/   unit_strr   r0   r0   r1   get_err_str  s    
z2UnitBase._apply_equivalencies.<locals>.get_err_strz and z are not convertible)r   r   r   r   r   )rW   r/   r   r@   r   rC   rD   rE   rF   Zratio_in_funitr   r   r   r   Z	other_strr0   r0   r1   _apply_equivalencies  s<    



	zUnitBase._apply_equivalenciesc                    s   z |W n ty    Y n0 dkr.tS fddS z|W S  ty } znt|dr|jD ]L\}} ||u rpz$ fddW   W  Y d}~S  ty   Y qp0 qp|W Y d}~n
d}~0 0 dS )zGet a converter for values in ``self`` to ``other``.

        If no conversion is necessary, returns ``unit_scale_converter``
        (which is used as a check in quantity helpers).

        r!   c                    s    t |  S r4   r   val)r   r0   r1   r7     r8   z)UnitBase._get_converter.<locals>.<lambda>r@   c                    s    j d| S )Nry   )_get_converterr   )rF   r@   rW   rD   r0   r1   r7   %  s   N)r   r   unit_scale_converterr   rG   r   r@   r   )rW   r   r@   excrC   rE   r0   )rF   r@   r   rW   rD   r1   r     s(    	
$zUnitBase._get_converterc                 C   st   | |u rdS t |trZ|  }| }|j|jkrZtdd t|j|jD rZ|j|j S td| d|ddS )z
        Returns the scale to the specified unit.

        See `to`, except that a Unit object should be given (i.e., no
        string), and that all defaults are used, i.e., no
        equivalencies and value=1.
        r!   c                 s   s   | ]\}}||u V  qd S r4   r0   )rJ   Z	self_baseZ
other_baser0   r0   r1   r   F  r8   zUnitBase._to.<locals>.<genexpr>r   z' is not a scaled version of 'N)	r"   r   r   r   allr   r   r   r   )rW   r   Zself_decomposedZother_decomposedr0   r0   r1   r   ,  s    
zUnitBase._toc                 C   s.   || u r|t u rt S | jt||d|S dS )a  
        Return the converted values in the specified unit.

        Parameters
        ----------
        other : unit-like
            The unit to convert to.

        value : int, float, or scalar array-like, optional
            Value(s) in the current unit to be converted to the
            specified unit.  If not provided, defaults to 1.0

        equivalencies : list of tuple
            A list of equivalence pairs to try if the units are not
            directly convertible.  See :ref:`astropy:unit_equivalencies`.
            This list is in addition to possible global defaults set by, e.g.,
            `set_enabled_equivalencies`.
            Use `None` to turn off all equivalencies.

        Returns
        -------
        values : scalar or array
            Converted value(s). Input value sequences are returned as
            numpy arrays.

        Raises
        ------
        UnitsError
            If units are inconsistent
        ry   N)UNITYr   r   rW   r   ru   r@   r0   r0   r1   toM  s    
zUnitBase.tor!   c                 C   s   | j |||dS )zI
        Alias for `to` for backward compatibility with pynbody.
        )ru   r@   )r   r   r0   r0   r1   in_unitsr  s    zUnitBase.in_unitsc                 C   s
   t  dS )aO  
        Return a unit object composed of only irreducible units.

        Parameters
        ----------
        bases : sequence of UnitBase, optional
            The bases to decompose into.  When not provided,
            decomposes down to any irreducible units.  When provided,
            the decomposed result will only contain the given units.
            This will raises a `UnitsError` if it's not possible
            to do so.

        Returns
        -------
        unit : `~astropy.units.CompositeUnit`
            New object containing only irreducible unit objects.
        N)NotImplementedErrorrW   r   r0   r0   r1   r   y  s    zUnitBase.decomposer3   r   c               	      sh   fdd}|   }t|}||}	|	d ur@t|	tr<|	|	S ||krX|g||< |gS |g}
|D ]\}}}}|d ur| |r|  j|j }|
t|d| |    n8| |r|  j|j }|
t|d| |    qb| |rb|
t|j qbg }t	|j
dkr,t|gt g}nt t g} D ]}|  }|
D ]}t	|j
dkrt|j
|jD ],\}}||rn|| }|| } qqn||   }|| }t	|j
}||r|dkr|| | n||||f qLq<|D ]2}t	|r|d |d }|||< |  S q|jtdd g }|D ]d\}}}z|j| ||d |d}W n ty   g }Y n0 |D ]}|t	|j
||f qqHt	|r2|jtdd |d d }t }|D ]:\}}}||kr qn|| }||r|| qt	|r2|||< |S || sXtd|  d	}|||< || g||< | gS )
Nc                    s   | j D ]}| vr dS qdS )NFTr   )r/   base	namespacer0   r1   is_final_result  s    
z*UnitBase._compose.<locals>.is_final_resultr!   r   r   keyr@   r   	max_depthdepthcached_resultszCannot represent unit z in terms of the given units)r   rd   re   r"   r   r   r   r?   r   r<   r   r$   r   r   r%   unionsortoperator
itemgetter_composer   ) rW   r@   r   r   r  r  r   r/   r   cachedr.   rC   rD   rE   rF   r   Zpartial_resultsZfinal_resultsZtunit_decomposedr   r   powercomposedZfactoredZ	len_basesZfinal_resultresultsZcomposed_listZsubcomposedZ
min_lengthZ
subresultsr,   r0   r   r1   r    s    



 
 












zUnitBase._composec                    s   du rt |ttf| dd fdd fdd}|   |du r||| jd}t|d	krt j}nDt |t	rt
|| }n(t|r|t| }n|t|}d
d }|| j||d	i dS )a  
        Return the simplest possible composite unit(s) that represent
        the given unit.  Since there may be multiple equally simple
        compositions of the unit, a list of units is always returned.

        Parameters
        ----------
        equivalencies : list of tuple
            A list of equivalence pairs to also list.  See
            :ref:`astropy:unit_equivalencies`.
            This list is in addition to possible global defaults set by, e.g.,
            `set_enabled_equivalencies`.
            Use `None` to turn off all equivalencies.

        units : set of `~astropy.units.Unit`, optional
            If not provided, any known units may be used to compose
            into.  Otherwise, ``units`` is a dict, module or sequence
            containing the units to compose into.

        max_depth : int, optional
            The maximum recursion depth to use when composing into
            composite units.

        include_prefix_units : bool, optional
            When `True`, include prefixed units in the result.
            Default is `True` if a sequence is passed in to ``units``,
            `False` otherwise.

        Returns
        -------
        units : list of `CompositeUnit`
            A list of candidate compositions.  These will all be
            equally simple, but it may not be possible to
            automatically determine which of the candidates are
            better.
        Nc                 S   sL   t | jdkr t |jdkr dS | jD ] }|jD ]}||kr0  dS q0q&dS )Nr   TFr<   r   )rE   rF   ZabZbbr0   r0   r1   has_bases_in_common:  s    

z-UnitBase.compose.<locals>.has_bases_in_commonc                    s   | |rdS  D ]n\}}}}|d urf|  |rF| |rd dS q|  |r| |r dS q|  |rt|r dS qdS )NTF)r   r   r   )r/   r   rC   rD   rE   rF   )r@   r  r0   r1   has_bases_in_common_with_equivC  s    




z8UnitBase.compose.<locals>.has_bases_in_common_with_equivc                    sD   t  }| D ]4}t|tr
s&t|ts
 | r
|| q
|S r4   )r$   r"   r   r   r   r%   )r.   Zfiltered_namespacerD   )
decomposedr  include_prefix_unitsr0   r1   filter_unitsT  s    
z&UnitBase.compose.<locals>.filter_unitsry   r   c                 S   s   t | sg S t| } | jdd d | jdd d | jdd d | jdd d | d }|g}| dd  D ]"}t|t|kr|| |}qn|S )	Nc                 S   s   t | jS r4   )npabsr   r5   r0   r0   r1   r7   w  r8   z8UnitBase.compose.<locals>.sort_results.<locals>.<lambda>r   c                 S   s   t t | jS r4   )r  sumr  r   r5   r0   r0   r1   r7   x  r8   c                 S   s   t | jdk S )Ng        )r  r  r   r5   r0   r0   r1   r7   y  r8   c                 S   s   t | j S r4   )r   r   r5   r0   r0   r1   r7   z  r8   r   r   )r<   r#   r  r   r?   )r  Zlast_resultZfilteredr,   r0   r0   r1   sort_resultsm  s    
z&UnitBase.compose.<locals>.sort_resultsr   )r"   r#   r   rG   r   "_get_units_with_same_physical_typer<   r   r_   r&   r$   r'   r(   r)   r*   r2   r  )rW   r@   r.   r   r  r  r  r0   )r  r@   r  r  r  r1   compose  s.    (
	


zUnitBase.composec                    s@   t |j  fdd}| j d}|j|d}t||dd}|S )a  
        Converts this unit into ones belonging to the given system.
        Since more than one result may be possible, a list is always
        returned.

        Parameters
        ----------
        system : module
            The module that defines the unit system.  Commonly used
            ones include `astropy.units.si` and `astropy.units.cgs`.

            To use your own module it must contain unit objects and a
            sequence member named ``bases`` containing the base units of
            the system.

        Returns
        -------
        units : list of `CompositeUnit`
            The list is ranked so that units containing only the base
            units of that system will appear first.
        c                    sJ   | j }t|dkrtjS d}|D ]}| v r |d7 }q |tt| S d S )Nr   r   )r   r<   r  inffloat)r  Zcompose_basesr  r   r   r0   r1   score  s    
z!UnitBase.to_system.<locals>.scorer   )r.   T)r   reverse)r$   r   r   r  sorted)rW   systemr  r6   r
  r0   r   r1   	to_system  s    
zUnitBase.to_systemc                 C   s   ddl m} | |d S )zL
        Returns a copy of the current `Unit` instance in SI units.
        r   )sir   ) r  r  )rW   r  r0   r0   r1   r    s    zUnitBase.sic                 C   s   ddl m} | |d S )zO
        Returns a copy of the current `Unit` instance with CGS units.
        r   )cgsr   )r   r!  r  )rW   r!  r0   r0   r1   r!    s    zUnitBase.cgsc                 C   s   ddl m} || S )a  
        Physical type(s) dimensionally compatible with the unit.

        Returns
        -------
        `~astropy.units.physical.PhysicalType`
            A representation of the physical type(s) of a unit.

        Examples
        --------
        >>> from astropy import units as u
        >>> u.m.physical_type
        PhysicalType('length')
        >>> (u.m ** 2 / u.s).physical_type
        PhysicalType({'diffusivity', 'kinematic viscosity'})

        Physical types can be compared to other physical types
        (recommended in packages) or to strings.

        >>> area = (u.m ** 2).physical_type
        >>> area == u.m.physical_type ** 2
        True
        >>> area == "area"
        True

        `~astropy.units.physical.PhysicalType` objects can be used for
        dimensional analysis.

        >>> number_density = u.m.physical_type ** -3
        >>> velocity = (u.m / u.s).physical_type
        >>> number_density * velocity
        PhysicalType('particle flux')
        r   )physical)r   r"  Zget_physical_type)rW   r"  r0   r0   r1   r     s    #zUnitBase.physical_typec                 C   s   t  }t|| }|D ]n\}}}}|durr| |rN||vrN||| | |r||vr||| q| |r|t q|S )a  
        Return a list of registered units with the same physical type
        as this unit.

        This function is used by Quantity to add its built-in
        conversions to equivalent units.

        This is a private method, since end users should be encouraged
        to use the more powerful `compose` and `find_equivalent_units`
        methods (which use this under the hood).

        Parameters
        ----------
        equivalencies : list of tuple
            A list of equivalence pairs to also pull options from.
            See :ref:`astropy:unit_equivalencies`.  It must already be
            normalized using `_normalize_equivalencies`.
        N)r   r$   rg   r   updater   r%   r   )rW   r@   Zunit_registryr.   rC   rD   rE   rF   r0   r0   r1   r    s    
z+UnitBase._get_units_with_same_physical_typec                   @   s8   e Zd ZdZdZdZdZdd Zdd Ze	d	d
 Z
dS )zUnitBase.EquivalentUnitsListzb
        A class to handle pretty-printing the result of
        `find_equivalent_units`.
        )zPrimary namezUnit definitionZAliasesr9   zThere are no equivalent unitsc                    s   t | dkr| jS | | }|d| j dg| j }|D ],}t|D ]\}}t|| t |||< qFq:dj|   fdd|D }|dd dg dd |dd  D  dg }d		|S d S )
Nr   z)  {{0:<{0}s}} | {{1:<{1}s}} | {{2:<{2}s}}c                    s   g | ]} j | qS r0   r
   )rJ   liner   r0   r1   r   %  r8   z9UnitBase.EquivalentUnitsList.__repr__.<locals>.<listcomp>r   [c                 S   s   g | ]}| d qS )z ,r0   r   r0   r0   r1   r   (  r8   ]
)
r<   NO_EQUIV_UNITS_MSG_process_equivalent_unitsinsertHEADING_NAMESROW_LENr;   maxr   join)rW   linesZwidthsr$  rB   colr0   r%  r1   r     s$    


z%UnitBase.EquivalentUnitsList.__repr__c           
      C   s   t | dkrd| j dS d}d}d| j }d| j }||j| j }| | }|}|D ]}||j| }	||	7 }qZ||S dS )	zW
            Outputs a HTML table representation within Jupyter notebooks.
            r   z<p>z</p>z#<table style="width:50%">{}</table>z<tr>{}</tr>z<th>{}</th>z<td>{}</td>N)r<   r)  r-  r   r,  r*  )
rW   Zblank_tableZblank_row_containerZheading_row_contentZdata_row_contentZheading_rowZ	data_rowsZall_rowsrowZhtml_rowr0   r0   r1   _repr_html_,  s"    




z(UnitBase.EquivalentUnitsList._repr_html_c                 C   sN   g }| D ]8}|   }||jkr&d}||j|d|jf q|  |S )z\
            Extract attributes, and sort, the equivalent units pre-formatting.
            Zirreduciblez, )r   r   r   r?   r/  rY   r  )Zequiv_units_dataZprocessed_equiv_unitsr   Zirredr0   r0   r1   r*  E  s    
z6UnitBase.EquivalentUnitsList._process_equivalent_unitsN)rk   rl   rm   rn   r,  r-  r)  r   r3  staticmethodr*  r0   r0   r0   r1   EquivalentUnitsList  s   r5  Fc                 C   s.   | j ||d|d}tdd |D }| |S )a4  
        Return a list of all the units that are the same type as ``self``.

        Parameters
        ----------
        equivalencies : list of tuple
            A list of equivalence pairs to also list.  See
            :ref:`astropy:unit_equivalencies`.
            Any list given, including an empty one, supersedes global defaults
            that may be in effect (as set by `set_enabled_equivalencies`)

        units : set of `~astropy.units.Unit`, optional
            If not provided, all defined units will be searched for
            equivalencies.  Otherwise, may be a dict, module or
            sequence containing the units to search for equivalencies.

        include_prefix_units : bool, optional
            When `True`, include prefixed units in the result.
            Default is `False`.

        Returns
        -------
        units : list of `UnitBase`
            A list of unit objects that match ``u``.  A subclass of
            `list` (``EquivalentUnitsList``) is returned that
            pretty-prints the list of units when output.
        r   )r@   r.   r   r  c                 s   s&   | ]}t |jd kr|jd V  qdS )r   r   Nr  r   r0   r0   r1   r   t  s   z1UnitBase.find_equivalent_units.<locals>.<genexpr>)r  r$   r5  )rW   r@   r.   r  r  r0   r0   r1   find_equivalent_unitsT  s    zUnitBase.find_equivalent_unitsc                 C   s   dS )zK
        Returns `True` if the unit is unscaled and dimensionless.
        Fr0   r[   r0   r0   r1   r   x  s    zUnitBase.is_unity)Ark   rl   rm   rn   Z__array_priority__r   r   r   r   r   r   ra   ro   r   r   rY   r   r   r   r   r   r   r   r4  rG   r   r   r   __truediv____rtruediv__r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r$   r   r  r  r  r   r  r!  r   r  r#   r5  r6  r   r0   r0   r0   r1   r   m  s   







/&!%
z
 -


%"E
$r   c                   @   sp   e Zd ZdZdddZdd Zdd Zed	d
 Zedd Z	edd Z
edd Zedd ZdddZdS )r   ah  
    The base class of units that have a name.

    Parameters
    ----------
    st : str, list of str, 2-tuple
        The name of the unit.  If a list of strings, the first element
        is the canonical (short) name, and the rest of the elements
        are aliases.  If a tuple of lists, the first element is a list
        of short names, and the second element is a list of long
        names; all but the first short name are considered "aliases".
        Each name *should* be a valid Python identifier to make it
        easy to access, but this is not required.

    namespace : dict, optional
        When provided, inject the unit, and all of its aliases, in the
        given namespace dictionary.  If a unit by the same name is
        already in the namespace, a ValueError is raised.

    doc : str, optional
        A docstring describing the unit.

    format : dict, optional
        A mapping to format-specific representations of this unit.
        For example, for the ``Ohm`` unit, it might be nice to have it
        displayed as ``\Omega`` by the ``latex`` formatter.  In that
        case, `format` argument should be set to::

            {'latex': r'\Omega'}

    Raises
    ------
    ValueError
        If any of the given unit names are already in the registry.

    ValueError
        If any of the given unit names are not valid Python tokens.
    Nc                    s0  t |  t ttfr0 g| _ g| _g | _nt trt	 dksNt
d d  fdd d D  | _t	| jst
d d d d  | _ d d d  | _n<t	 dkrt
d d d  | _ d g| _ dd  | _|d u ri }|| _|d u r|  }nt|}t|}|| _| | d S )	Nr3   z"st must be string, list or 2-tupler   c                    s   g | ]}| d  vr|qS r   r0   )rJ   nrc   r0   r1   r     r8   z&NamedUnit.__init__.<locals>.<listcomp>r   zmust provide at least one namez$st list must have at least one entry)r   rZ   r"   r   r   r`   _short_names_long_namesr   r<   r=   _format_generate_doctextwrapdedentZfillrn   _inject)rW   rc   docr   r   r0   r;  r1   rZ     s:    

 




zNamedUnit.__init__c                 C   s2   | j }t| j dkr&dj|dd  S |d S dS )z
        Generate a docstring for the unit if the user didn't supply
        one.  This is only used from the constructor and may be
        overridden in subclasses.
        r   z	{1} ({0})Nr3   r   )r   r<   r   )rW   r   r0   r0   r1   r?    s    zNamedUnit._generate_docc                 C   s   | j || jS )a}  
        Get a name for this unit that is specific to a particular
        format.

        Uses the dictionary passed into the `format` kwarg in the
        constructor.

        Parameters
        ----------
        format : str
            The name of the format

        Returns
        -------
        name : str
            The name of the unit for the given format.
        )r>  re   r   rW   r   r0   r0   r1   get_format_name  s    zNamedUnit.get_format_namec                 C   s   | j S )r   r`   r[   r0   r0   r1   r     s    zNamedUnit.namesc                 C   s
   | j d S )r   r   rF  r[   r0   r0   r1   r     s    zNamedUnit.namec                 C   s   | j dd S )r   r   NrF  r[   r0   r0   r1   rY     s    zNamedUnit.aliasesc                 C   s   | j S )zK
        Returns all of the short names associated with this unit.
        )r<  r[   r0   r0   r1   short_names  s    zNamedUnit.short_namesc                 C   s   | j S )zJ
        Returns all of the long names associated with this unit.
        )r=  r[   r0   r0   r1   
long_names	  s    zNamedUnit.long_namesc                 C   sX   |du rdS | j D ],}||v r| || krtd||| q| j D ]}| ||< qFdS )zf
        Injects the unit, and all of its aliases, in the given
        namespace dictionary.
        Nz?Object with name {!r} already exists in given namespace ({!r}).)r`   r=   r   )rW   r   r   r0   r0   r1   rB    s    

zNamedUnit._inject)NNN)N)rk   rl   rm   rn   rZ   r?  rE  ro   r   r   rY   rG  rH  rB  r0   r0   r0   r1   r     s   '
&




r   c                 C   sB   t  j}|d |v r ||d  S | |}|r:t  |g |S dS )zV
    This is used to reconstruct units when passed around by
    multiprocessing.
    r   N)r   r]   r   )clsr   Z
registeredr]   r/   r0   r0   r1   _recreate_irreducible_unit%  s    rJ  c                   @   s2   e Zd ZdZdd Zedd Ze fddZdS )	r   z
    Irreducible units are the units that all other units are defined
    in terms of.

    Examples are meters, seconds, kilograms, amperes, etc.  There is
    only once instance of such a unit per type.
    c                 C   s*   t  j}t| jt| j| j|v f|  fS r4   )r   r]   rJ  	__class__r#   r   r   r   )rW   r]   r0   r0   r1   
__reduce__B  s
    zIrreducibleUnit.__reduce__c                 C   s   | S )zkThe unit that this named unit represents.

        For an irreducible unit, that is always itself.
        r0   r[   r0   r0   r1   
representsN  s    zIrreducibleUnit.representsc              	   C   sx   t |rt| |vrt|D ]N}z| |}W n ty8   Y q0 t|rJ|  S t||gdgdd  S qtd|  d| S )Nr   Fr   zUnit z/ can not be decomposed into the requested bases)r<   r   r   r   r   r   )rW   r   r   r   r0   r0   r1   r   V  s    
zIrreducibleUnit.decomposeN)	rk   rl   rm   rn   rL  ro   rM  r$   r   r0   r0   r0   r1   r   9  s
   
r   c                   @   s   e Zd ZdZejZdd Zdd Zdd Zdd	d
Z	dd Z
e
 Z Z Z Z Z Z Z Z Z Z ZZdd Zdd ZdddZdddZdd Zdd ZdS )r   z
    A unit that did not parse correctly.  This allows for
    round-tripping it as a string, but no unit operations actually work
    on it.

    Parameters
    ----------
    st : str
        The name of the unit.
    c                 C   s   dt |  dS )NzUnrecognizedUnit(r   r   r[   r0   r0   r1   r   z  s    zUnrecognizedUnit.__repr__c                 C   s   | j ddS )Nasciireplace)r   r   r[   r0   r0   r1   r   }  s    zUnrecognizedUnit.__bytes__c                 C   s   | j S r4   r   r[   r0   r0   r1   r     s    zUnrecognizedUnit.__str__Nc                 C   s   | j S r4   r   rD  r0   r0   r1   r     s    zUnrecognizedUnit.to_stringc                 O   s   t d| jd S )NzPThe unit {!r} is unrecognized, so all arithmetic operations with it are invalid.)r=   r   r   )rW   argskwargsr0   r0   r1   _unrecognized_operator  s
    z'UnrecognizedUnit._unrecognized_operatorc              
   C   sH   zt |dd}W n tttfy,   t Y S 0 t|t| oF| j|jkS )Nr   r   )r   r=   r   r   r   r"   rt   r   r   r0   r0   r1   r     s
    
zUnrecognizedUnit.__eq__c                 C   s
   | |k S r4   r0   r   r0   r0   r1   r     s    zUnrecognizedUnit.__ne__c                 C   s   |  | | |kS r4   )rG   r   r0   r0   r1   r     s    
zUnrecognizedUnit.is_equivalentc                 C   s   |  | td| jd S )NzGThe unit {!r} is unrecognized.  It can not be converted to other units.)rG   r=   r   r   r   r0   r0   r1   r     s    
zUnrecognizedUnit._get_converterc                 C   s   | j S r4   r   rD  r0   r0   r1   rE    s    z UnrecognizedUnit.get_format_namec                 C   s   dS )NFr0   r[   r0   r0   r1   r     s    zUnrecognizedUnit.is_unity)N)N)N)rk   rl   rm   rn   objectrL  r   r   r   r   rR  r   r   r   r7  r8  r   r   r   r   r   r   r   r   r   r   r   rE  r   r0   r0   r0   r1   r   j  s0   


r   c                       s"   e Zd ZdZd fdd	Z  ZS )_UnitMetaClassz
    This metaclass exists because the Unit constructor should
    sometimes return instances that already exist.  This "overrides"
    the constructor before the new instance is actually created, so we
    can return an existing one.
    r   Nraisec              
      sD  t |dr|S ddlm} t||rXt|jr6|j}n"t|j|jj |jj	|jj
dd}t||rt|jrt|j}n"t|j|jj |jj	|jj
dd}t|trt j|||||dS t|tr|S t|ttfrt| dkrtS |d u rtj}t|}t|tr|d}z||W S  ty8    Y n ty }	 z|d	krTnb|tjurl|jd
 }
nd}
d||
t|	}|dkrt|n |dkrt|t ntdt |W  Y d }	~	S d }	~	0 0 njt|t!t"t#j$t#j%frt|g g ddS t|t&rddl'm(} ||S |d u r2t)dnt)| dd S )Nra   r   r   F)r   r   r   )r   r   rC  r   rN  r    r   a  '{}' did not parse as {}unit: {} If this is meant to be a custom unit, define it with 'u.def_unit'. To have it recognized inside a file reader or other code, enable it with 'u.add_enabled_units'. For details, see https://docs.astropy.org/en/latest/units/combining_and_defining.htmlrU  r   z2'parse_strict' must be 'warn', 'raise' or 'silent'r   )StructuredUnitzNone is not a valid Unitz can not be converted to a Unit)*r   r   r   r"   r   ru   r/   r   r   r   r   r   super__call__r   r   r<   stripr   r   r   r   decodeparser   r   r   r   r=   r   r   r   r   intr  r  ZfloatingZintegerr   Z
structuredrW  r   )rW   srM  r   r   rC  r   r   r   eZformat_clausemsgrW  rK  r0   r1   rY    s|    














 

z_UnitMetaClass.__call__)r   NNNNrU  )rk   rl   rm   rn   rY  __classcell__r0   r0   ra  r1   rT    s     rT  c                   @   sP   e Zd ZdZdddZedd Ze fddZd	d
 Z	dd Z
edd ZdS )r   aU	  
    The main unit class.

    There are a number of different ways to construct a Unit, but
    always returns a `UnitBase` instance.  If the arguments refer to
    an already-existing unit, that existing unit instance is returned,
    rather than a new one.

    - From a string::

        Unit(s, format=None, parse_strict='silent')

      Construct from a string representing a (possibly compound) unit.

      The optional `format` keyword argument specifies the format the
      string is in, by default ``"generic"``.  For a description of
      the available formats, see `astropy.units.format`.

      The optional ``parse_strict`` keyword controls what happens when an
      unrecognized unit string is passed in.  It may be one of the following:

         - ``'raise'``: (default) raise a ValueError exception.

         - ``'warn'``: emit a Warning, and return an
           `UnrecognizedUnit` instance.

         - ``'silent'``: return an `UnrecognizedUnit` instance.

    - From a number::

        Unit(number)

      Creates a dimensionless unit.

    - From a `UnitBase` instance::

        Unit(unit)

      Returns the given unit unchanged.

    - From no arguments::

        Unit()

      Returns the dimensionless unit.

    - The last form, which creates a new `Unit` is described in detail
      below.

    See also: https://docs.astropy.org/en/stable/units/

    Parameters
    ----------
    st : str or list of str
        The name of the unit.  If a list, the first element is the
        canonical (short) name, and the rest of the elements are
        aliases.

    represents : UnitBase instance
        The unit that this named unit represents.

    doc : str, optional
        A docstring describing the unit.

    format : dict, optional
        A mapping to format-specific representations of this unit.
        For example, for the ``Ohm`` unit, it might be nice to have it
        displayed as ``\Omega`` by the ``latex`` formatter.  In that
        case, `format` argument should be set to::

            {'latex': r'\Omega'}

    namespace : dict, optional
        When provided, inject the unit (and all of its aliases) into
        the given namespace.

    Raises
    ------
    ValueError
        If any of the given unit names are already in the registry.

    ValueError
        If any of the given unit names are not valid Python tokens.
    Nc                 C   s&   t |}|| _tj| ||||d d S )Nr   rC  r   )r   _representsr   rZ   )rW   rc   rM  rC  r   r   r0   r0   r1   rZ   j  s
    zUnit.__init__c                 C   s   | j S )z)The unit that this named unit represents.)rd  r[   r0   r0   r1   rM  s  s    zUnit.representsc                 C   s   | j j|dS )Nr   )rd  r   r   r0   r0   r1   r   x  s    zUnit.decomposec                 C   s
   | j  S r4   )rd  r   r[   r0   r0   r1   r   {  s    zUnit.is_unityc                 C   s"   | j d u rt| j| jf| _ | j S r4   )r   rd   r   rd  r[   r0   r0   r1   r   ~  s    
zUnit.__hash__c                    sV    fdd|D }dd |D }t |dkrB|d dkrB|d }ntd||dd}|S )Nc                    s   g | ]\}} |qS r0   r0   )rJ   r   _rI  r0   r1   r     r8   z/Unit._from_physical_type_id.<locals>.<listcomp>c                 S   s   g | ]\}}|qS r0   r0   )rJ   re  r	  r0   r0   r1   r     r8   r   r   Fr   )r<   r   )rI  Zphysical_type_idr   r   r/   r0   rf  r1   _from_physical_type_id  s    
zUnit._from_physical_type_id)NNNN)rk   rl   rm   rn   rZ   ro   rM  r$   r   r   r   classmethodrg  r0   r0   r0   r1   r     s   U  
	
r   )	metaclassc                   @   s   e Zd ZdZdS )r   z
    A unit that is simply a SI-prefixed version of another unit.

    For example, ``mm`` is a `PrefixUnit` of ``.001 * m``.

    The constructor is the same as for `Unit`.
    Nr~   r0   r0   r0   r1   r     s   r   c                       s   e Zd ZdZdZde dfddZ fddZed	d
 Z	edd Z
edd Zde fddZdd Ze fddZdd Z  ZS )r   a  
    Create a composite unit using expressions of previously defined
    units.

    Direct use of this class is not recommended. Instead use the
    factory function `Unit` and arithmetic operators to compose
    units.

    Parameters
    ----------
    scale : number
        A scaling factor for the unit.

    bases : sequence of `UnitBase`
        A sequence of units this unit is composed of.

    powers : sequence of numbers
        A sequence of powers (in parallel with ``bases``) for each
        of the base units.
    NFTc           	         s   |r.|D ]}t |tstdqdd |D }|st|dkr|d dkr|d }|d   dkr~||j9 }|j| _|j| _nB dkrg | _g | _n,||j  9 }|j| _ fdd|jD | _t	|| _
n || _
|| _|| _| j||d d S )Nz,bases must be sequence of UnitBase instancesc                 S   s   g | ]}t |qS r0   )r   rJ   r   r0   r0   r1   r     r8   z*CompositeUnit.__init__.<locals>.<listcomp>r   r   c                    s   g | ]}t jt|  qS r0   )r  mulr	   rj  r	  r0   r1   r     s   )r   r   )r"   r   r   r<   r   r   _basesr   _powersr   _scale_expand_and_gather)	rW   r   r   r   r   decompose_basesr   r   r/   r0   rl  r1   rZ     s:    



zCompositeUnit.__init__c                    s4   t | jrt  S | jdkr,d| j dS dS d S )Nr!   z#Unit(dimensionless with a scale of r   zUnit(dimensionless))r<   rm  rX  r   ro  r[   ra  r0   r1   r     s
    


zCompositeUnit.__repr__c                 C   s   | j S )z9
        Return the scale of the composite unit.
        )ro  r[   r0   r0   r1   r     s    zCompositeUnit.scalec                 C   s   | j S )z9
        Return the bases of the composite unit.
        )rm  r[   r0   r0   r1   r     s    zCompositeUnit.basesc                 C   s   | j S )z:
        Return the powers of the composite unit.
        )rn  r[   r0   r0   r1   r     s    zCompositeUnit.powersc           
         s    fdd}i | j }t| j| jD ]|\}}|rF| vrF|j d}t|tr||j | 9 }t|j|jD ]&\}}t||\}	}|||	| |}qlq&||||}q&dd  D j	dd d d	d D | _d
d D | _t
|| _ d S )Nc              	      s|    rH|  vrH D ]6}z||  || 9 }W n ty<   Y q0 |}  qHq| v rpt|  |\}}|| | < n|| < |S r4   )r   r   r	   )r/   r	  r   r   rE   rF   r   Z	new_partsr0   r1   add_unit  s    z2CompositeUnit._expand_and_gather.<locals>.add_unitr   c                 S   s   g | ]}|d  dkr|qS )r   r   r0   r   r0   r0   r1   r   	  r8   z4CompositeUnit._expand_and_gather.<locals>.<listcomp>c                 S   s   | d  t | d ddfS )Nr   r   r   r   )getattrr5   r0   r0   r1   r7    	  r8   z2CompositeUnit._expand_and_gather.<locals>.<lambda>r   c                 S   s   g | ]}|d  qS r9  r0   r   r0   r0   r1   r   "	  r8   c                 S   s   g | ]}|d  qS )r   r0   r   r0   r0   r1   r   #	  r8   )ro  r   rm  rn  r   r"   r   r	   r+   r  r   )
rW   r   r   rs  r   rF   r   Zb_subZp_subrE   r0   rr  r1   rp    s"    
z CompositeUnit._expand_and_gatherc                 C   s"   t | j| jdd | jdd S )z<
        For compatibility with python copy module.
        N)r   ro  rm  rn  r[   r0   r0   r1   __copy__&	  s    zCompositeUnit.__copy__c                 C   s   t |dkr| jd ur| jS | jD ]"}t|tr@t |r"||vr" q\q"t |dkrX| | _| S t| j| j| jd|d}t |dkr|| _|S )Nr   T)r   rq  )r<   _decomposed_cacher   r"   r   r   r   r   )rW   r   r   r6   r0   r0   r1   r   ,	  s$    

zCompositeUnit.decomposec                 C   s    |   }t|jdko|jdkS )Nr   r!   )r   r<   r   r   rf   r0   r0   r1   r   ?	  s    zCompositeUnit.is_unity)rk   rl   rm   rn   rv  r$   rZ   r   ro   r   r   r   rp  ru  r   r   rb  r0   r0   ra  r1   r     s    
,	


)r   YZyottagyCxDZZzettagPKDEZexag NgmCPZpetag  4&kCTZterag   mBGZgigag    eAMZmegag    .ArK   Zkilog     @@hZhectog      Y@ZdaZdekaZdecag      $@dZdecig?cZcentig{Gz?r   ZmilligMbP?r   microgư>r:  Znanog&.>r   Zpicog-q=r   ZfemtogV瞯<rE   ZattogC]r2<zZzeptogO
;yZyoctogW:ZKiZkibig      @ZMiZmebig      0AZGiZgibig      AZTiZtebig      pBZPiZpebig      CZEiZexbig      CFc              	   C   s
  |du rt }n|du rg }|D ]\}}}g }i }|D ]x}	|	|v rBq4| jD ]b}
||	|
  |	dkrd| d |d< d| d |d< | j D ]\}}|||	|  qqHq4|D ](}	|	|v rq| jD ]}
||	|
  qqt|rt	|t
|| gdgdd	||d
 qdS )ad  
    Set up all of the standard metric prefixes for a unit.  This
    function should not be used directly, but instead use the
    `prefixes` kwarg on `def_unit`.

    Parameters
    ----------
    excludes : list of str, optional
        Any prefixes to exclude from creation to avoid namespace
        collisions.

    namespace : dict, optional
        When provided, inject the unit (and all of its aliases) into
        the given namespace dictionary.

    prefixes : list, optional
        When provided, it is a list of prefix definitions of the form:

            (short_names, long_tables, factor)
    TFr   z\mu Zlatex   µZunicoder   r   )r   r   N)si_prefixesrG  r?   rE  r>  r+   rb   rH  r<   r   r   )r   excludesr   prefixesZshortZfullZfactorr   r   prefixrj   r   r   r0   r0   r1   _add_prefixesf	  s8    

r  c                 C   sD   |durt | ||||d}nt| |||d}|r@t||||d |S )a  
    Factory function for defining new units.

    Parameters
    ----------
    s : str or list of str
        The name of the unit.  If a list, the first element is the
        canonical (short) name, and the rest of the elements are
        aliases.

    represents : UnitBase instance, optional
        The unit that this named unit represents.  If not provided,
        a new `IrreducibleUnit` is created.

    doc : str, optional
        A docstring describing the unit.

    format : dict, optional
        A mapping to format-specific representations of this unit.
        For example, for the ``Ohm`` unit, it might be nice to
        have it displayed as ``\Omega`` by the ``latex``
        formatter.  In that case, `format` argument should be set
        to::

            {'latex': r'\Omega'}

    prefixes : bool or list, optional
        When `True`, generate all of the SI prefixed versions of the
        unit as well.  For example, for a given unit ``m``, will
        generate ``mm``, ``cm``, ``km``, etc.  When a list, it is a list of
        prefix definitions of the form:

            (short_names, long_tables, factor)

        Default is `False`.  This function always returns the base
        unit object, even if multiple scaled versions of the unit were
        created.

    exclude_prefixes : list of str, optional
        If any of the SI prefixes need to be excluded, they may be
        listed here.  For example, ``Pa`` can be interpreted either as
        "petaannum" or "Pascal".  Therefore, when defining the
        prefixes for ``a``, ``exclude_prefixes`` should be set to
        ``["P"]``.

    namespace : dict, optional
        When provided, inject the unit (and all of its aliases and
        prefixes), into the given namespace dictionary.

    Returns
    -------
    unit : `~astropy.units.UnitBase`
        The newly-defined unit, or a matching unit that was already
        defined.
    Nrc  )r  r   r  )r   r   r  )r^  rM  rC  r   r  Zexclude_prefixesr   r,   r0   r0   r1   r   	  s    :
r   c                 C   s>   t | tjttttjfr| S t| }|jj	dvr:t
d|S )at  
    Validate value is acceptable for conversion purposes.

    Will convert into an array if not a scalar, and can be converted
    into an array

    Parameters
    ----------
    value : int or float value, or sequence of such values

    Returns
    -------
    Scalar value or numpy array

    Raises
    ------
    ValueError
        If value is not as expected
    )rB   r   r  zMValue not scalar compatible or convertible to an int, float, or complex array)r"   r  Zndarrayr  r]  complexZvoidZarrayZdtypekindr=   )ru   Zavaluer0   r0   r1   r   	  s    
r   c                 C   s   dt |  S )zFunction that just multiplies the value by unity.

    This is a separate function so it can be recognized and
    discarded in unit conversion.
    r!   r   r   r0   r0   r1   r   
  s    r   r   )>rn   r(   r  r@  r   Znumpyr  Zastropy.utils.decoratorsr   Zastropy.utils.exceptionsr   Zastropy.utils.miscr   Zutilsr   r   r   r	   r   r   r   __all__r   r2   rG   rH   rp   rq   r   r   r   r   r   r   r   r   r   r=   r   r   r   r   r   r   r   rJ  r   r   rt   rT  r   r   r   r  Zbinary_prefixesr  r   r   r   r   r    Zfitsr0   r0   r0   r1   <module>   s   
* \58"#&	         '1Ai~
 *
:
G	