B
    Afxac1                @  s  d Z ddlmZ ddlZddl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mZ ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZmZ ddlmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z* ddl+m,Z,m-Z- ddl.m/Z/m0Z0 ddl1m2Z2m3Z3m4Z4 ddl5m6Z6m7Z7 ddl8m9Z9m:Z: ddl;m<Z<m=Z=m>Z>m?Z?m@Z@ ddlAmBZBmCZCmDZDmEZE ddlFmGZG ddl-mHZHmIZI ddlJmKZKmLZLmMZMmNZNmOZOmPZPmQZQmRZRmSZSmTZTmUZUmVZV erddl.mWZW ddlXmYZY ddlZm[Z[ ddlZmMZ\ e2rddl]Z]e]j^Z^ndZ^e)dZ_e
`dZaeb dd ZcG dd  d edZeG d!d" d"ZfG d#d$ d$Zge(e*eheef  Zieejgejf ZkG d%d& d&eed'ZlG d(d) d)elZmG d*d+ d+elZnG d,d- d-elZoG d.d/ d/eoenemZpG d0d1 d1ZqG d2d3 d3ZrdS )4a  
pint.registry
~~~~~~~~~~~~~

Defines the Registry, a class to contain units and their relations.

The module actually defines 5 registries with different capabilities:

- BaseRegistry: Basic unit definition and querying.
                Conversion between multiplicative units.

- NonMultiplicativeRegistry: Conversion between non multiplicative (offset) units.
                             (e.g. Temperature)

  * Inherits from BaseRegistry

- ContextRegisty: Conversion between units with different dimensions according
                  to previously established relations (contexts) - e.g. in spectroscopy,
                  conversion between frequency and energy is possible. May also override
                  conversions between units on the same dimension - e.g. different
                  rounding conventions.

  * Inherits from BaseRegistry

- SystemRegistry: Group unit and changing of base units.
                  (e.g. in MKS, meter, kilogram and second are base units.)

  * Inherits from BaseRegistry

- UnitRegistry: Combine all previous capabilities, it is exposed by Pint.

:copyright: 2016 by Pint Authors, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
    )annotationsN)ChainMapdefaultdict)contextmanager)Decimal)Fraction)StringIO)Number)NAMENUMBER)TYPE_CHECKINGAnyCallableContextManagerDict	FrozenSetIterableIteratorListOptionalSetTupleTypeTypeVarUnion   )registry_helperssystems)FQuantityOrUnitLike)	HAS_BABELbabel_parse	tokenizer)ContextContextChain)LogarithmicConverterScaleConverter)AliasDefinition
DefinitionDimensionDefinitionPrefixDefinitionUnitDefinition)DefinitionSyntaxErrorDimensionalityErrorRedefinitionErrorUndefinedUnitError)build_eval_tree)GroupSystem)ParserHelperSourceIteratorUnitsContainer_is_dimfind_connected_nodesfind_shortest_pathgetattr_maybe_raiselogger
pi_theoremsolve_dependenciesstring_preprocessorto_units_container)UnitLike)Quantity)Unit)r5   Tz[ (]c             C  s(   t | dr| j} tdd| } t| S )Nfinditerz{(\w+)}z3(?P<\1>[+-]?[0-9]+(?:.[0-9]+)?(?:[Ee][+-]?[0-9]+)?))hasattrpatternresubcompile)rE    rI   ,lib/python3.7/site-packages/pint/registry.pypattern_to_regex{   s
    

rK   c                  s    e Zd ZdZ fddZ  ZS )RegistryMetazuThis is just to call after_init at the right time
    instead of asking the developer to do it when subclassing.
    c               s   t  j||}|  |S )N)super__call___after_init)selfargskwargsobj)	__class__rI   rJ   rN      s    zRegistryMeta.__call__)__name__
__module____qualname____doc__rN   __classcell__rI   rI   )rT   rJ   rL      s   rL   c               @  s   e Zd ZdZddddZdS )RegistryCachez!Cache to speed up unit registriesNone)returnc             C  s   i | _ i | _i | _i | _d S )N)dimensional_equivalents
root_unitsdimensionality
parse_unit)rP   rI   rI   rJ   __init__   s    zRegistryCache.__init__N)rU   rV   rW   rX   ra   rI   rI   rI   rJ   rZ      s   rZ   c               @  s    e Zd ZdZdddddZdS )ContextCacheOverlayzLayer on top of the base UnitRegistry cache, specific to a combination of
    active contexts which contain unit redefinitions.
    rZ   r[   )registry_cacher\   c             C  s"   |j | _ i | _|j| _|j| _d S )N)r]   r^   r_   r`   )rP   rc   rI   rI   rJ   ra      s    zContextCacheOverlay.__init__N)rU   rV   rW   rX   ra   rI   rI   rI   rJ   rb      s   rb   c            
   @  s  e Zd ZU dZdZded< dZded< dddd	ddded
f	dddddddddddZddddZ	ddddZ
ddddZddddZddddZd d! Zd"d# Zddd$d%Zd&dd'd(Zd)dd*d+Zddd,d-d.Zd/dd0d1Zeddd2d3Zejdd4d5d3Zd6dd7d8d9Zd:d;d7d<d=Zd>d? Zd@dA ZdBdC ZdDdE ZddddFdGdHZdddIdJZdddKddLdMdNZ dddKddLdOdPZ!dddQdRdSZ"d/ddTdUZ#dVd/dWdXdYZ$dZd[ Z%d\d] Z&dd^dd_d`dadbZ'ddcddZ(ddedfZ)dgdh Z*ddiddjdkZ+dldm Z,dndndoddpdqdrZ-ddsdtdtddsdudvdwZ.ddxdyZ/dddKdzd{d|d}Z0dddKd~d{ddZ1e2ddzdddZ3dddKdKddddZ4dddZ5dddZ6ddddKddddddZ7dddKdddddZ8e8Z9dS )BaseRegistrya]  Base class for all registries.

    Capabilities:

    - Register units, prefixes, and dimensions, and their relations.
    - Convert between units.
    - Find dimensionality of a unit.
    - Parse units with prefix and/or suffix.
    - Parse expressions.
    - Parse a definition file.
    - Allow extending the definition file parser by registering @ directives.

    Parameters
    ----------
    filename : str or None
        path of the units definition file to load or line iterable object. Empty to load
        the default definition file. None to leave the UnitRegistry empty.
    force_ndarray : bool
        convert any input, scalar or not to a numpy.ndarray.
    force_ndarray_like : bool
        convert all inputs other than duck arrays to a numpy.ndarray.
    on_redefinition : str
        action to take in case a unit is redefined: 'warn', 'raise', 'ignore'
    auto_reduce_dimensions :
        If True, reduce dimensionality on appropriate operations.
    preprocessors :
        list of callables which are iteratively ran on any input expression or unit
        string
    fmt_locale :
        locale identifier string, used in `format_babel`
    non_int_type : type
        numerical type used for non integer values. (Default: float)
    case_sensitive : bool, optional
        Control default case sensitivity of unit parsing. (Default: True)

    Nz+Dict[str, Callable[[SourceIterator], None]]_parserszOptional[Locale]
fmt_locale FwarnTboolstrz Optional[List[PreprocessorType]]zOptional[str]NON_INT_TYPE)force_ndarrayforce_ndarray_likeon_redefinitionauto_reduce_dimensionspreprocessorsrf   non_int_typecase_sensitivec
       
      C  s   |    |   || _|| _|| _|p(g | _|| _|| _| | || _	|	| _
i | _i | _i | _tt| _dtddddi| _ddd| _t | _d| _d S )Nrg   rI   r   )rg   sF)_register_parsers_init_dynamic_classes	_filenamerl   rm   rp   _on_redefinitionro   set_fmt_localerq   rr   	_defaults_dimensions_unitsr   set_units_caseir*   	_prefixes	_suffixesrZ   _cache_initialized)
rP   filenamerl   rm   rn   ro   rp   rf   rq   rr   rI   rI   rJ   ra      s&    


zBaseRegistry.__init__r[   )r\   c             C  sF   ddl m} || | _ddlm} || | _ddlm} || | _dS )z6Generate subclasses on the fly and attach them to selfr   )build_unit_class)build_quantity_class)build_measurement_classN)	unitr   rA   quantityr   r@   Zmeasurementr   Measurement)rP   r   r   r   rI   rI   rJ   ru     s    

z"BaseRegistry._init_dynamic_classesc             C  s@   | j dkr| dd n| j dk	r.| | j  |   d| _dS )z(This should be called after all __init__rg   zdefault_en.txtTN)rv   load_definitions_build_cacher   )rP   rI   rI   rJ   rO   -  s    

zBaseRegistry._after_initc             C  s   |  d| j d S )Nz	@defaults)_register_parser_parse_defaults)rP   rI   rI   rJ   rt   8  s    zBaseRegistry._register_parsersc             C  sB   t | x4| D ](\}}|d\}}| | j| < qW dS )zLoader for a @default section.=N)next
block_itersplitstripry   )rP   ifilelinenopartkvrI   rI   rJ   r   ;  s    zBaseRegistry._parse_defaultsz'BaseRegistry'c             C  s*   t t| }t| j||_|  |S )N)object__new__typecopydeepcopy__dict__ru   )rP   memonewrI   rI   rJ   __deepcopy__B  s    zBaseRegistry.__deepcopy__c             C  s   t | | | |S )N)r9   rA   )rP   itemrI   rI   rJ   __getattr__H  s    
zBaseRegistry.__getattr__c             C  s   t d | |S )Nz~Calling the getitem method from a UnitRegistry is deprecated. use `parse_expression` method or use the registry as a callable.)r:   warningparse_expression)rP   r   rI   rI   rJ   __getitem__L  s    zBaseRegistry.__getitem__c             C  s(   y|  | dS  tk
r"   dS X dS )z6Support checking prefixed units with the `in` operatorTFN)r   r/   )rP   r   rI   rI   rJ   __contains__S  s
    
zBaseRegistry.__contains__z	List[str]c             C  s   t | j t t|  S )N)listr{   keysr   __dir__)rP   rI   rI   rJ   r   [  s    zBaseRegistry.__dir__zIterator[str]c             C  s   t t| j S )zAllows for listing all units in registry with `list(ureg)`.

        Returns
        -------
        Iterator over names of all units in registry, ordered alphabetically.
        )itersortedr{   r   )rP   rI   rI   rJ   __iter__`  s    zBaseRegistry.__iter__)locr\   c             C  s0   t |tr&|dkrt d }t| || _dS )zChange the locale used by default by `format_babel`.

        Parameters
        ----------
        loc : str or None
            None` (do not translate), 'sys' (detect the system locale) or a locale id string.
        sysr   N)
isinstancerj   localegetdefaultlocaler!   rf   )rP   r   rI   rI   rJ   rx   i  s
    
zBaseRegistry.set_fmt_localeUnitsContainerTc             O  s   t |d| ji|S )Nrq   )r5   rq   )rP   rQ   rR   rI   rI   rJ   r5   z  s    zBaseRegistry.UnitsContainerc             C  s   | j jS )z)Default formatting string for quantities.)r@   default_format)rP   rI   rI   rJ   r   }  s    zBaseRegistry.default_format)valuec             C  s   || j _|| j_|| j_d S )N)rA   r   r@   r   )rP   r   rI   rI   rJ   r     s    zUnion[str, Definition])
definitionr\   c             C  sB   t |tr4x2|dD ]}| t|| j qW n
| | dS )zAdd unit to the registry.

        Parameters
        ----------
        definition : str or Definition
            a dimension, unit or prefix definition.
        
N)r   rj   r   _definer(   from_stringrq   )rP   r   linerI   rI   rJ   define  s    	
zBaseRegistry.definer(   zTuple[Definition, dict, dict]c       
   
   C  s  t |tr| jd }}nt |tr| j| j }}|jrx|j D ]8}|| jkrb|dkrBt	dqB| 
t|ddddd qBW n\t |tr| jd }}nDt |tr| j| j }}| ||| ||j ||fS td|t|jd	d
d
kr|jdrd|jdd  }n
d|j }|jr0d|j }nd}tdd |jD tdd |jD  }| dd |j D }t|||t|jj||j}	n|}	| |	|| |||fS )a  Add unit to the registry.

        This method defines only multiplicative units, converting any other type
        to `delta_` units.

        Parameters
        ----------
        definition : Definition
            a dimension, unit or prefix definition.

        Returns
        -------
        Definition, dict, dict
            Definition instance, case sensitive unit dict, case insensitive unit dict.

        Nz[]z.Only one unit per dimension can be a base unitrg   rI   T)is_basez{} is not a valid definition.offsetr   [z[delta_r   delta_u   Δc             s  s   | ]}d | V  qdS )u   ΔNrI   ).0aliasrI   rI   rJ   	<genexpr>  s    z'BaseRegistry._define.<locals>.<genexpr>c             s  s   | ]}d | V  qdS )r   NrI   )r   r   rI   rI   rJ   r     s    c             S  s   i | ]\}}||qS rI   rI   )r   refr   rI   rI   rJ   
<dictcomp>  s    z(BaseRegistry._define.<locals>.<dictcomp>)r   r)   rz   r+   r{   r}   r   	referencer   r,   r   r*   r~   r'   _define_aliasname	TypeErrorformatgetattr	converter
startswithsymboltuplealiasesr5   itemsr&   scale_define_adder)
rP   r   ddiZ	dimensionZd_nameZd_symbolZ	d_aliasesZd_referenceZd_defrI   rI   rJ   r     sR    







zBaseRegistry._definec             C  sd   |  |j||| |jr*|  |j||| x4|jD ]*}d|krLtd|  |  |||| q2W dS )zHelper function to store a definition in the internal dictionaries.
        It stores the definition under its name, symbol and aliases.
         zAlias cannot contain a space: N)_define_single_adderr   Z
has_symbolr   r   r:   rh   )rP   r   	unit_dictcasei_unit_dictr   rI   rI   rJ   r     s    zBaseRegistry._define_adderc             C  sh   ||krB| j dkr"t|t|n | j dkrBtd|t|f  |||< |dk	rd||  | dS )z~Helper function to store a definition in the internal dictionaries.

        It warns or raise error on redefinition.
        raiserh   zRedefining '%s' (%s)N)rw   r.   r   r:   r   loweradd)rP   keyr   r   r   rI   rI   rJ   r      s    

z!BaseRegistry._define_single_adderc             C  sD   ||j  }|j|j  x(|jD ]}|||< ||  | qW d S )N)r   Zadd_aliasesr   r   r   )rP   r   r   r   r   r   rI   rI   rJ   r     s
    
zBaseRegistry._define_aliasc             C  s8   | j dkri | _ |r,|d dkr,|| j |< ntddS )a8  Register a loader for a given @ directive..

        Parameters
        ----------
        prefix :
            string identifying the section (e.g. @context)
        parserfunc : SourceIterator -> None
            A function that is able to parse a Definition section.

        Returns
        -------

        Nr   @z%Prefix directives must start with '@')re   
ValueError)rP   prefixZ
parserfuncrI   rI   rJ   r     s
    
zBaseRegistry._register_parser)is_resourcer\   c             C  s  t |tryL|r4tjt|}| t|d|S t	|dd}| ||S Q R X W n~ t
tfk
r } z|jdkr|||_|W dd}~X Y nF tk
r } z(t|ddpt|}td||W dd}~X Y nX t|}x|D ]\}}	|	dr|	ds|	d	r|r,|	d
d  }
nTytj|j}
W n tk
r\   t }
Y nX tj|
tj|	d
d  }
| |
| nt|	}| jr| j|d dnd}|dkrtd|	 |dy|| W n: tk
r } z|j dkr||_ |W dd}~X Y nX qy| !t"#|	| j$ W q tk
rl } z|j dkrX||_ |W dd}~X Y q tk
r } zt%&d||	| W dd}~X Y qX qW dS )au  Add units and prefixes defined in a definition text file.

        Parameters
        ----------
        file :
            can be a filename or a line iterable.
        is_resource :
            used to indicate that the file is a resource file
            and therefore should be loaded from the package. (Default value = False)

        Returns
        -------

        zutf-8)encodingNmessagerg   zWhile opening {}
{}r   z@aliasz@import   r   zUnknown directive %s)r   zIn line {}, cannot add '{}' {})'r   rj   	importlibZ	resourcesZread_binary__package__r   r   decodeopenr.   r,   r   	Exceptionr   r   r   r4   r   r   ospathdirnamer   AttributeErrorgetcwdjoinnormpath	_BLOCK_REr   re   getr   r   r(   r   rq   r:   error)rP   filer   Zrbytesfpemsgr   nor   r   partsloaderexrI   rI   rJ   r   ,  s\    

""

zBaseRegistry.load_definitionsc             C  s  t  | _dd | j D }xt|D ]}x|D ]}d|kr>q0| |}|r\|d \}}}n
d| }}yft|| j}| 	|}	| 
|}
|	| jj|< |
| jj|< |s| jj|
t }|| j| j W q0 tk
r } ztd| d| W dd}~X Y q0X q0W q&W dS )	z/Build a cache of dimensionality and base units.c             S  s(   i | ] \}}|j r|j  nt |qS rI   )r   r   r|   )r   r   r   rI   rI   rJ   r   {  s   z-BaseRegistry._build_cache.<locals>.<dictcomp>r   r   rg   zCould not resolve z: N)rZ   r   r{   r   r<   parse_unit_namer3   Z	from_wordrq   _get_root_units_get_dimensionalityr^   r_   r]   
setdefaultr|   r   _namer   r:   r   )rP   ZdepsZ
unit_names	unit_nameZparsed_namesr   	base_name_Zucbur   Z	dimeq_setexcrI   rI   rJ   r   w  s.    





zBaseRegistry._build_cachezOptional[bool])name_or_aliasrr   r\   c       
   	   C  s   |dkrdS y| j | jS  tk
r,   Y nX | ||}|sHt|n<t|dkrd|d \}}}n td|| |d \}}}|r|| }| 	||}| j
| }	t||d|	j| |di| j |< || S |S )z$Return the canonical name of a unit.dimensionlessrg   r   r   z2Parsing {} yield multiple results. Options are: {}rI   )r{   r   KeyErrorr   r/   lenr:   r   r   
get_symbolr~   r+   r   r5   )
rP   r  rr   
candidatesr   r   r   r   r   Z
prefix_defrI   rI   rJ   get_name  s6    


zBaseRegistry.get_namec             C  sn   |  ||}|st|n<t|dkr6|d \}}}n td|| |d \}}}| j| j| j| j S )z&Return the preferred alias for a unit.r   r   z6Parsing {0} yield multiple results. Options are: {1!r})	r   r/   r  r:   r   r   r~   r   r{   )rP   r  rr   r  r   r   r   rI   rI   rJ   r    s    

zBaseRegistry.get_symbol)r   r\   c             C  s   | j | jS )N)r{   r   )rP   r   rI   rI   rJ   _get_symbol  s    zBaseRegistry._get_symbolc             C  s   t |}| |S )zdConvert unit or dict of units or dimensions to a dict of base dimensions
        dimensions
        )r>   r   )rP   input_unitsrI   rI   rJ   get_dimensionality  s    zBaseRegistry.get_dimensionalityzOptional[UnitsContainerT])r  r\   c             C  sz   |s|   S | jj}y|| S  tk
r0   Y nX tt}| |d| d|krV|d= |  dd | D }|||< |S )z,Convert a UnitsContainer to base dimensions.r   z[]c             S  s   i | ]\}}|d kr||qS )r   rI   )r   r   r   rI   rI   rJ   r     s    z4BaseRegistry._get_dimensionality.<locals>.<dictcomp>)r5   r   r_   r  r   int_get_dimensionality_recurser   )rP   r  cacheaccumulatorZdimsrI   rI   rJ   r     s    z BaseRegistry._get_dimensionalityc             C  s   x|D ]}|||  }t |r\| j| }|jr@||  |7  < q|jd k	r| |j|| q| j| | }|jd k	r| |j|| qW d S )N)r6   rz   r   r   r  r{   r	  )rP   r   expr  r   exp2regrI   rI   rJ   r    s    



z(BaseRegistry._get_dimensionality_recursec               s~   ||krdS fdd||fD \} |r> r>|     krBdS  fdd| D }t|tfdd|D rzS dS )a  Get the exponential ratio between two units, i.e. solve unit2 = unit1**x for x.

        Parameters
        ----------
        unit1 : UnitsContainer compatible (str, Unit, UnitsContainer, dict)
            first unit
        unit2 : UnitsContainer compatible (str, Unit, UnitsContainer, dict)
            second unit

        Returns
        -------
        number or None
            exponential proportionality or None if the units cannot be converted

        r   c             3  s   | ]}  |V  qd S )N)r  )r   r   )rP   rI   rJ   r      s    z9BaseRegistry._get_dimensionality_ratio.<locals>.<genexpr>Nc             3  s   | ]\}} | | V  qd S )NrI   )r   r   val)dim2rI   rJ   r   $  s    c             3  s   | ]}| kV  qd S )NrI   )r   r)firstrI   rJ   r   &  s    )r   r   r   all)rP   Zunit1Zunit2Zdim1ZratiosrI   )r  r  rP   rJ   _get_dimensionality_ratio  s    z&BaseRegistry._get_dimensionality_ratior?   zTuple[Number, Unit])r  check_nonmultr\   c             C  s(   t || }| ||\}}|| |fS )a[  Convert unit or dict of units to the root units.

        If any unit is non multiplicative and check_converter is True,
        then None is returned as the multiplicative factor.

        Parameters
        ----------
        input_units : UnitsContainer or str
            units
        check_nonmult : bool
            if True, None will be returned as the
            multiplicative factor if a non-multiplicative
            units is found in the final Units. (Default value = True)

        Returns
        -------
        Number, pint.Unit
            multiplicative factor, base units

        )r>   r   rA   )rP   r  r  funitsrI   rI   rJ   get_root_units*  s    
zBaseRegistry.get_root_unitsc               s   |sd   fS  jj}y|| S  tk
r4   Y nX dttg} |d| |d }  dd |d  D }|rt fdd|D rd}||f||< ||fS )aW  Convert unit or dict of units to the root units.

        If any unit is non multiplicative and check_converter is True,
        then None is returned as the multiplicative factor.

        Parameters
        ----------
        input_units : UnitsContainer or dict
            units
        check_nonmult : bool
            if True, None will be returned as the
            multiplicative factor if a non-multiplicative
            units is found in the final Units. (Default value = True)

        Returns
        -------
        number, Unit
            multiplicative factor, base units

        r   r   c             S  s   i | ]\}}|d kr||qS )r   rI   )r   r   r   rI   rI   rJ   r   j  s    z0BaseRegistry._get_root_units.<locals>.<dictcomp>c             3  s   | ]} j | jj V  qd S )N)r{   r   is_multiplicative)r   r   )rP   rI   rJ   r   o  s    z/BaseRegistry._get_root_units.<locals>.<genexpr>N)	r5   r   r^   r  r   r  _get_root_units_recurser   any)rP   r  r  r  accumulatorsfactorr  rI   )rP   rJ   r   G  s"    zBaseRegistry._get_root_unitsc             C  s   |  ||S )a  Convert unit or dict of units to the base units.

        If any unit is non multiplicative and check_converter is True,
        then None is returned as the multiplicative factor.

        Parameters
        ----------
        input_units : UnitsContainer or str
            units
        check_nonmult : bool
            If True, None will be returned as the multiplicative factor if
            non-multiplicative units are found in the final Units.
            (Default value = True)
        system :
             (Default value = None)

        Returns
        -------
        Number, pint.Unit
            multiplicative factor, base units

        )r  )rP   r  r  systemrI   rI   rJ   get_base_unitsu  s    zBaseRegistry.get_base_unitsc             C  s   xz|D ]r}|||  }|  |}| j| }|jrF|d |  |7  < q|d  |jj| 9  < |jd k	r| |j|| qW d S )Nr   r   )r	  r{   r   Z
_converterr   r   r  )rP   r   r  r!  r   r  r  rI   rI   rJ   r    s    



z$BaseRegistry._get_root_units_recursezFrozenSet['Unit']c               s*   t |} ||}t fdd|D S )r   c             3  s   | ]}  |V  qd S )N)rA   )r   eq)rP   rI   rJ   r     s    z4BaseRegistry.get_compatible_units.<locals>.<genexpr>)r>   _get_compatible_units	frozenset)rP   r  group_or_systemZequivrI   )rP   rJ   get_compatible_units  s    z!BaseRegistry.get_compatible_unitsc             C  s    |s
t  S | |}| jj| S )r   )r'  r   r   r]   )rP   r  r(  src_dimrI   rI   rJ   r&    s    
z"BaseRegistry._get_compatible_unitsr   zUnion[str, Context])obj1obj2contextsr\   c             O  sZ   t || j| jfr$|j|f||S t |trF| |j|f||S t || j| jf S )a  check if the other object is compatible

        Parameters
        ----------
        obj1, obj2
            The objects to check against each other. Treated as
            dimensionless if not a Quantity, Unit or str.
        *contexts : str or pint.Context
            Contexts to use in the transformation.
        **ctx_kwargs :
            Values for the Context/s

        Returns
        -------
        bool
        )r   r@   rA   is_compatible_withrj   r   )rP   r+  r,  r-  Z
ctx_kwargsrI   rI   rJ   r.    s    

zBaseRegistry.is_compatible_withrB   r   )r   srcdstinplacer\   c             C  s0   t || }t || }||kr |S | ||||S )a  Convert value from some source to destination units.

        Parameters
        ----------
        value :
            value
        src : pint.Quantity or str
            source units.
        dst : pint.Quantity or str
            destination units.
        inplace :
             (Default value = False)

        Returns
        -------
        type
            converted value

        )r>   _convert)rP   r   r/  r0  r1  rI   rI   rJ   convert  s
    

zBaseRegistry.convertc       
      C  s   |r.|  |}|  |}||kr.t||||| || \}}	t|trXtt|}nt|trntt|}|r|||9 }n|| }|S )a  Convert value from some source to destination units.

        Parameters
        ----------
        value :
            value
        src : UnitsContainer
            source units.
        dst : UnitsContainer
            destination units.
        inplace :
             (Default value = False)
        check_dimensionality :
             (Default value = True)

        Returns
        -------
        type
            converted value

        )r   r-   r   r   r   rj   r   )
rP   r   r/  r0  r1  Zcheck_dimensionalityr*  dst_dimr"  r   rI   rI   rJ   r2    s    




zBaseRegistry._convertz Tuple[Tuple[str, str, str], ...])r   rr   r\   c             C  s   |  | j||dS )am  Parse a unit to identify prefix, unit name and suffix
        by walking the list of prefix and suffix.
        In case of equivalent combinations (e.g. ('kilo', 'gram', '') and
        ('', 'kilogram', ''), prefer those with prefix.

        Parameters
        ----------
        unit_name :

        case_sensitive : bool or None
            Control if unit lookup is case sensitive. Defaults to None, which uses the
            registry's case_sensitive setting

        Returns
        -------
        tuple of tuples (str, str, str)
            all non-equivalent combinations of (prefix, unit name, suffix)
        )rr   )_dedup_candidates_parse_unit_name)rP   r   rr   rI   rI   rJ   r      s    zBaseRegistry.parse_unit_namezIterator[Tuple[str, str, str]]c       	      c  s   |dkr| j n|}|j}|j}xt| j| jD ]\}}||r0||r0|t|d }|r||dt|  }t|dkr|q0|r|| jkr| j| j	| j| j	| j| fV  q0x<| j
| dD ]&}| j| j	| j| j	| j| fV  qW q0W dS )zHelper of parse_unit_name.Nr   rI   )rr   r   endswith	itertoolsproductr   r~   r  r{   r   r}   r   r   )	rP   r   rr   ZstwZedwsuffixr   r   Z	real_namerI   rI   rJ   r6  9  s&    




zBaseRegistry._parse_unit_namezIterable[Tuple[str, str, str]])r  r\   c             C  sp   t | } x\t| D ]P\}}}t|ts,tt|ts:t|dkrJtd|r| d|| dfd qW t| S )zHelper of parse_unit_name.

        Given an iterable of unit triplets (prefix, name, suffix), remove those with
        different names but equal value, preferring those with a prefix.

        e.g. ('kilo', 'gram', '') and ('', 'kilogram', '')
        rg   znon-empty suffixN)	dictfromkeysr   r   rj   AssertionErrorNotImplementedErrorpopr   )r  ZcpZcucsrI   rI   rJ   r5  X  s    
zBaseRegistry._dedup_candidatesrA   )input_stringas_deltarr   r\   c             C  s0   x| j D ]}||}qW | |||}| |S )a  Parse a units expression and returns a UnitContainer with
        the canonical names.

        The expression can only contain products, ratios and powers of units.

        Parameters
        ----------
        input_string : str
        as_delta : bool or None
            if the expression has multiple units, the parser will
            interpret non multiplicative units as their `delta_` counterparts. (Default value = None)
        case_sensitive : bool or None
            Control if unit parsing is case sensitive. Defaults to None, which uses the
            registry's setting.

        Returns
        -------
            pint.Unit

        )rp   _parse_unitsrA   )rP   rA  rB  rr   pr  rI   rI   rJ   parse_unitsm  s    zBaseRegistry.parse_unitsc             C  s   | j j}|r&||kr&|| jkr&|| S |s2|  S | }t|| j}|jdkrZt	di }t
|dk}x\|D ]T}| j||d}	|| }
|	sqp|r|s|s|
dkr| j|	 }|jsd|	 }	|
||	< qpW | |}|r|||< |S )z_Parse a units expression and returns a UnitContainer with
        the canonical names.
        r   z-Unit expression cannot have a scaling factor.)rr   r   )r   r`   r{   r5   r   r3   r   rq   r   r   r  r	  r  )rP   rA  rB  rr   r  r  retmanyr   Zcnamer   r   rI   rI   rJ   rC    s2    



zBaseRegistry._parse_unitsc          	   K  s   |rt d|d }|d }|tkrn|dkr6d| j S ||krL| || S | d| | j||ddiS n |tkrtj|| j	dS t
dd S )Nz`use_decimal` is deprecated, use `non_int_type` keyword argument when instantiating the registry.
>>> from decimal import Decimal
>>> ureg = UnitRegistry(non_int_type=Decimal)r   r   r  )rr   )rq   zunknown token type)DeprecationWarningr
   r  r@   r5   r	  r   r3   Z
eval_tokenrq   r   )rP   tokenrr   use_decimalvalues
token_typeZ
token_textrI   rI   rJ   _eval_token  s"    
zBaseRegistry._eval_tokenzUnion[List[str], str, None])rA  rE   rr   rJ  rG  r\   c          
   C  s   |s|rg S dS t |}t||}g }x`|D ]X}| }g }	x0| D ]$\}
}|	t|| |
||  qHW ||	 |s.|d S q.W |S )a  Parse a string with a given regex pattern and returns result.

        Parameters
        ----------
        input_string :

        pattern_string:
             The regex parse string
        case_sensitive :
             (Default value = None, which uses registry setting)
        use_decimal :
             (Default value = False)
        many :
             Match many results
             (Default value = False)


        Returns
        -------

        Nr   )rK   rF   rC   	groupdictr   appendfloatr   )rP   rA  rE   rr   rJ  rG  Zmatchedresultsmatchr  r   r   rI   rI   rJ   parse_pattern  s     

zBaseRegistry.parse_patternr@   )rA  rr   rJ  r\   c               s\   |rt d|sdS xjD ]}||}q"W t|}t|}t| fddS )a  Parse a mathematical expression including units and return a quantity object.

        Numerical constants can be specified as keyword arguments and will take precedence
        over the names defined in the registry.

        Parameters
        ----------
        input_string :

        case_sensitive :
             (Default value = None, which uses registry setting)
        use_decimal :
             (Default value = False)
        **values :


        Returns
        -------

        z`use_decimal` is deprecated, use `non_int_type` keyword argument when instantiating the registry.
>>> from decimal import Decimal
>>> ureg = UnitRegistry(non_int_type=Decimal)r   c               s   j | fd iS )Nrr   )rM  )x)rr   rP   rK  rI   rJ   <lambda>=      z/BaseRegistry.parse_expression.<locals>.<lambda>)rH  r@   rp   r=   r"   r0   Zevaluate)rP   rA  rr   rJ  rK  rD  genrI   )rr   rP   rK  rJ   r     s    
zBaseRegistry.parse_expression)F)N)N)T)T)TN)N)F)FT)N)N)NN)TN)NF)NFF)NF):rU   rV   rW   rX   re   __annotations__rf   rP  ra   ru   rO   rt   r   r   r   r   r   r   r   rx   r5   propertyr   setterr   r   r   r   r   r   r   r   r	  r  r
  r  r   r  r  r  r   r$  r  r)  r&  r.  r3  r2  r   r6  staticmethodr5  rE  rC  rM  rS  r   rN   rI   rI   rI   rJ   rd      s~   
$ 7	VK&(
.
	"
4 
*
!  : ,rd   )	metaclassc                  s   e Zd ZdZdddddd fdd	Zddddd fddZdd fddZddddZdd Zdd Z	d fdd	Z
  ZS ) NonMultiplicativeRegistrya  Handle of non multiplicative units (e.g. Temperature).

    Capabilities:
    - Register non-multiplicative units and their relations.
    - Convert between non-multiplicative units.

    Parameters
    ----------
    default_as_delta : bool
        If True, non-multiplicative units are interpreted as
        their *delta* counterparts in multiplications.
    autoconvert_offset_to_baseunit : bool
        If True, non-multiplicative units are
        converted to base units in multiplications.

    TFri   r   r[   )default_as_deltaautoconvert_offset_to_baseunitrR   r\   c               s   t  jf | || _|| _d S )N)rM   ra   r^  r_  )rP   r^  r_  rR   )rT   rI   rJ   ra   U  s    z"NonMultiplicativeRegistry.__init__Nrj   zOptional[bool])rA  rB  rr   c               s   |dkr| j }t |||S )r   N)r^  rM   rC  )rP   rA  rB  rr   )rT   rI   rJ   rC  e  s    z&NonMultiplicativeRegistry._parse_unitszUnion[str, Definition])r   c               s<   t  |\}}}t|jdddkr2| ||| |||fS )a  Add unit to the registry.

        In addition to what is done by the BaseRegistry,
        registers also non-multiplicative units.

        Parameters
        ----------
        definition : str or Definition
            A dimension, unit or prefix definition.

        Returns
        -------
        Definition, dict, dict
            Definition instance, case sensitive unit dict, case insensitive unit dict.

        r   r   )rM   r   r   r   r   )rP   r   r   r   )rT   rI   rJ   r   q  s    z!NonMultiplicativeRegistry._define)r\   c             C  sl   || j kr| j | jS | |}t|dks0t|d \}}}y| j | jS  tk
rf   t|Y nX d S )Nr   r   )r{   r  r   r  r=  r  r/   )rP   unamesr   r   rI   rI   rJ   _is_multiplicative  s    

z,NonMultiplicativeRegistry._is_multiplicativec               sv    fdd|  D }t|dkr,tdnFt|dkrr| \}}|dkrTtdt|dkrn jsntd|S d S )Nc               s"   g | ]\}}  |s||fqS rI   )rb  )r   r`  r   )rP   rI   rJ   
<listcomp>  s    zCNonMultiplicativeRegistry._validate_and_extract.<locals>.<listcomp>r   zmore than one offset unit.zoffset units in higher order.z+offset unit used in multiplicative context.)r   r  r   r?  r_  )rP   r  Znonmult_unitsZnonmult_unitZexponentrI   )rP   rJ   _validate_and_extract  s    
z/NonMultiplicativeRegistry._validate_and_extractc             C  sP   | j | }t|jtrL|j}|t krLdd | D  \}}|||S |S )Nc             S  s   g | ]\}}||fqS rI   rI   )r   r`  r   rI   rI   rJ   rc    s    zBNonMultiplicativeRegistry._add_ref_of_log_unit.<locals>.<listcomp>)	r{   r   r   r%   r   r5   r   r?  r   )rP   Zoffset_unit	all_unitsZ	slct_unitZslct_refr`  r   rI   rI   rJ   _add_ref_of_log_unit  s    

z.NonMultiplicativeRegistry._add_ref_of_log_unitc       
   
     sR  y|  |}W n6 tk
rD } zt||d| dW dd}~X Y nX y|  |}W n6 tk
r } zt||d| dW dd}~X Y nX |s|st ||||S | |}| |}	||	krt||||	|r| j| j||}|	|g}| 
||}|r |	|g}| 
||}t ||||d}|rN| j| j||}|S )a  Convert value from some source to destination units.

        In addition to what is done by the BaseRegistry,
        converts between non-multiplicative units.

        Parameters
        ----------
        value :
            value
        src : UnitsContainer
            source units.
        dst : UnitsContainer
            destination units.
        inplace :
             (Default value = False)

        Returns
        -------
        type
            converted value

        z - In source units, )Z	extra_msgNz - In destination units, F)rd  r   r-   rM   r2  r   r{   r   Zto_referenceremoverf  Zfrom_reference)
rP   r   r/  r0  r1  Zsrc_offset_unitr   Zdst_offset_unitr*  r4  )rT   rI   rJ   r2    s6    &$

z"NonMultiplicativeRegistry._convert)TF)NN)F)rU   rV   rW   rX   ra   rC  r   rb  rd  rf  r2  rY   rI   rI   )rT   rJ   r]  C  s     r]  c                  s   e Zd ZdZddd fddZdd fdd	Zddd
dZdddddZdddddZdd fddZ	ddddZ
dddddZdddddZd0d!dd"d#d$Zed%dd&d'Zd(dd)d*Zd1 fd,d-	Z fd.d/Z  ZS )2ContextRegistryaR  Handle of Contexts.

    Conversion between units with different dimensions according
    to previously established relations (contexts).
    (e.g. in the spectroscopy, conversion between frequency and energy is possible)

    Capabilities:

    - Register contexts.
    - Enable and disable contexts.
    - Parse @context directive.
    r   r[   )rR   r\   c               s8   i | _ t | _i | _i | _t jf | t| j| _d S )N)		_contextsr$   _active_ctx_caches_context_unitsrM   ra   r   r{   )rP   rR   )rT   rI   rJ   ra     s    zContextRegistry.__init__)r\   c               s   t    | d| j d S )Nz@context)rM   rt   r   _parse_context)rP   )rT   rI   rJ   rt   .  s    
z!ContextRegistry._register_parsersc          
   C  sZ   y"|  tj| | j| jd W n2 tk
rT } ztd| dW d d }~X Y nX d S )N)rq   zunknown dimension z in context)add_contextr#   
from_linesr   r  rq   r  r,   )rP   r   r   rI   rI   rJ   rm  2  s    zContextRegistry._parse_contextr#   )contextr\   c             C  sj   |j std|j | jkr(td|j  || j|j < x0|jD ]&}|| jkrXtd|j  || j|< q<W dS )zAdd a context object to the registry.

        The context will be accessible by its name and aliases.

        Notice that this method will NOT enable the context;
        see :meth:`enable_contexts`.
        z%Can't add unnamed context to registryz7The name %s was already registered for another context.z6The name %s was already registered for another contextN)r   r   ri  r:   r   r   )rP   rp  r   rI   rI   rJ   rn  >  s    

zContextRegistry.add_contextrj   )r  r\   c             C  s0   | j | }| j |j= x|jD ]}| j |= qW |S )zRemove a context from the registry and return it.

        Notice that this methods will not disable the context;
        see :meth:`disable_contexts`.
        )ri  r   r   )rP   r  rp  r   rI   rI   rJ   remove_contextU  s
    

zContextRegistry.remove_contextc               s   t    | j| jd< d S )NrI   )rM   r   r   rk  )rP   )rT   rI   rJ   r   c  s    
zContextRegistry._build_cachec             C  s  | j jdd= tdd | jjD }|s8| jd | _dS | j }y&| j| | _| j jd| j	|  W n t
k
r|   Y nX | jd }t| | j|< | _i  | j	|< }| j jd| | j}d| _z4x.t| jjD ]}x|jD ]}| | qW qW W d|| _X dS )aA  If any of the active contexts redefine units, create variant self._cache
        and self._units specific to the combination of active contexts.
        The next time this method is invoked with the same combination of contexts,
        reuse the same variant self._cache and self._units as in the previous time.
        Nc             s  s   | ]}|j V  qd S )N)redefinitions)r   ctxrI   rI   rJ   r   n  s    zBContextRegistry._switch_context_cache_and_units.<locals>.<genexpr>rI   r   ignore)r{   mapsr   rj  r-  rk  r   Zhashableinsertrl  r  rb   rw   reversedrs  	_redefine)rP   Zunits_overlayr   Z
base_cacheZon_redefinition_backuprt  r   rI   rI   rJ   _switch_context_cache_and_unitsg  s,    

z/ContextRegistry._switch_context_cache_and_unitsr+   )r   r\   c       	      C  s   |  |j}|st|jdd |D }|s<td|j t|dksLt|d \}}}y| j| }W n tk
r   t|Y nX |jrtd| 	|j
}| 	|j
}||krtd|j d| d	| d
t|j|j|jd|j
|jd}| | dS )zRedefine a unit from a contextc             S  s   g | ]}|d  s|qS )r   rI   )r   crI   rI   rJ   rc    s    z-ContextRegistry._redefine.<locals>.<listcomp>z%Can't redefine a unit with a prefix: r   r   z+Can't redefine a base unit to a derived onezCan't change dimensionality of z from z to z in a contextF)r   r   r   r   r   r   N)r   r   r/   r   r  r=  r{   r  r   r   r   r+   r   r   r   r   )	rP   r   r  Zcandidates_no_prefixr   r   ZbasedefZdims_oldZdims_newrI   rI   rJ   ry    s6    

zContextRegistry._redefinezUnion[str, Context])names_or_contextsr\   c               s   j jrtj jf  fdd|D }x||D ]t}|jr<q0t|j}xV| D ]J\\}}}|}	|}
||	ks||
krP||| ||	|
| qPW d|_q0W t	 fdd|D }j j
|    dS )a8  Enable contexts provided by name or by object.

        Parameters
        ----------
        *names_or_contexts :
            one or more contexts or context names/aliases
        **kwargs :
            keyword arguments for the context(s)

        Examples
        --------
        See :meth:`context`
        c               s$   g | ]}t |tr j| n|qS rI   )r   rj   ri  )r   r   )rP   rI   rJ   rc    s   z3ContextRegistry.enable_contexts.<locals>.<listcomp>Tc             3  s   | ]}t j|f V  qd S )N)r#   Zfrom_context)r   rt  )rR   rI   rJ   r     s    z2ContextRegistry.enable_contexts.<locals>.<genexpr>N)rj  defaultsr;  checkedZfuncsr   r   Zremove_transformationZadd_transformationr   Zinsert_contextsrz  )rP   r|  rR   Zctxsrt  Z
funcs_copyr/  r0  funcZsrc_Zdst_r-  rI   )rR   rP   rJ   enable_contexts  s$    





zContextRegistry.enable_contextsNr  )nr\   c             C  s   | j | |   dS )zDisable the last n enabled contexts.

        Parameters
        ----------
        n : int
            Number of contexts to disable. Default: disable all contexts.
        N)rj  Zremove_contextsrz  )rP   r  rI   rI   rJ   disable_contexts  s    z ContextRegistry.disable_contextszContextManager[Context]c          
   o  s,   | j || z
| V  W d| t| X dS )aH  Used as a context manager, this function enables to activate a context
        which is removed after usage.

        Parameters
        ----------
        *names :
            name(s) of the context(s).
        **kwargs :
            keyword arguments for the contexts.

        Examples
        --------
        Context can be called by their name:

          >>> import pint
          >>> ureg = pint.UnitRegistry()
          >>> ureg.add_context(pint.Context('one'))
          >>> ureg.add_context(pint.Context('two'))
          >>> with ureg.context('one'):
          ...     pass

        If a context has an argument, you can specify its value as a keyword argument:

          >>> with ureg.context('one', n=1):
          ...     pass

        Multiple contexts can be entered in single call:

          >>> with ureg.context('one', 'two', n=1):
          ...     pass

        Or nested allowing you to give different values to the same keyword argument:

          >>> with ureg.context('one', n=1):
          ...     with ureg.context('two', n=2):
          ...         pass

        A nested context inherits the defaults from the containing context:

          >>> with ureg.context('one', n=1):
          ...     # Here n takes the value of the outer context
          ...     with ureg.context('two'):
          ...         pass
        N)r  r  r  )rP   ra  rR   rI   rI   rJ   rp    s    /
zContextRegistry.contextzCallable[[F], F]c               s    fdd}|S )aV  Decorator to wrap a function call in a Pint context.

        Use it to ensure that a certain context is active when
        calling a function::

        Parameters
        ----------
        name :
            name of the context.
        **kwargs :
            keyword arguments for the context


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

        Example
        -------
          >>> @ureg.with_context('sp')
          ... def my_cool_fun(wavelength):
          ...     print('This wavelength is equivalent to: %s', wavelength.to('terahertz'))
        c               sV   t  fddtjD }t  fddtjD }tj ||d fdd}|S )Nc             3  s   | ]}t  |r|V  qd S )N)rD   )r   attr)r  rI   rJ   r   G  s    zBContextRegistry.with_context.<locals>.decorator.<locals>.<genexpr>c             3  s   | ]}t  |r|V  qd S )N)rD   )r   r  )r  rI   rJ   r   J  s    )assignedupdatedc           	     s$   j f  | |S Q R X d S )N)rp  )rK  Zwrapper_kwargs)r  rR   r   rP   rI   rJ   wrapperM  s    z@ContextRegistry.with_context.<locals>.decorator.<locals>.wrapper)r   	functoolsWRAPPER_ASSIGNMENTSWRAPPER_UPDATESwraps)r  r  r  r  )rR   r   rP   )r  rJ   	decoratorE  s    "z/ContextRegistry.with_context.<locals>.decoratorrI   )rP   r   rR   r  rI   )rR   r   rP   rJ   with_context+  s    zContextRegistry.with_contextFc       
        s   | j r| |}| |}t| j j||}|r| ||}x8t|dd |dd D ]\}}	| j ||	| |}qVW |j|j }}t	 
||||S )a3  Convert value from some source to destination units.

        In addition to what is done by the BaseRegistry,
        converts between units with different dimensions by following
        transformation rules defined in the context.

        Parameters
        ----------
        value :
            value
        src : UnitsContainer
            source units.
        dst : UnitsContainer
            destination units.
        inplace :
             (Default value = False)

        Returns
        -------
        callable
            converted value
        Nrr  r   )rj  r   r8   graphr@   zipZ	transformZ
_magnituder{   rM   r2  )
rP   r   r/  r0  r1  r*  r4  r   ab)rT   rI   rJ   r2  V  s    

$zContextRegistry._convertc               sZ   |  |}t ||}| jrV| }t| jj|}|rVx|D ]}|| jj| O }q>W |S )N)	r   rM   r&  rj  r   r7   r  r   r]   )rP   r  r(  r*  rF  ZnodesZnode)rT   rI   rJ   r&    s    

z%ContextRegistry._get_compatible_units)N)F)rU   rV   rW   rX   ra   rt   rm  rn  rq  r   rz  ry  r  r  r   rp  r  r2  r&  rY   rI   rI   )rT   rJ   rh    s   %*0:+)rh  c                  s  e Zd ZdZd/ fdd	Zdd fddZdd fd	d
Zdd fddZddddZddddZ	d0ddddddZ
edd ZeddddZejdd Zd1ddddddZ fd d!Zd2d"dd#d$d%d&d'Zd3d(dd#d)d*d+Zd,d fd-d.Z  ZS )4SystemRegistrya  Handle of Systems and Groups.

    Conversion between units with different dimensions according
    to previously established relations (contexts).
    (e.g. in the spectroscopy, conversion between frequency and energy is possible)

    Capabilities:

    - Register systems and groups.
    - List systems
    - Get or get the default system.
    - Parse @system and @group directive.
    Nc               s<   t  jf | i | _t | _i | _| d| jd< || _d S )Nroot)rM   ra   _systemsr;  _base_units_cache_groupsr1   _default_system)rP   r#  rR   )rT   rI   rJ   ra     s    zSystemRegistry.__init__r[   )r\   c               s&   t    t| | _t| | _d S )N)rM   ru   r   Zbuild_group_classr1   Zbuild_system_classr2   )rP   )rT   rI   rJ   ru     s    
z$SystemRegistry._init_dynamic_classesc               st   t    d| jkrZ| | jd d}tdd | j D }| ddj}|j||   | j	pl| j
dd| _	dS )	zInvoked at the end of ``__init__``.

        - Create default group and add all orphan units to it
        - Set default system
        groupTc             S  s&   g | ]}|j d kr|jD ]}|qqS )r  )r   members)r   r  memberrI   rI   rJ   rc    s   
z.SystemRegistry._after_init.<locals>.<listcomp>r  Fr#  N)rM   rO   ry   	get_groupr'  r  rK  r  	add_unitsr  r   )rP   ZgrpZgroup_unitsre  )rT   rI   rJ   rO     s    

zSystemRegistry._after_initc               s*   t    | d| j | d| j d S )Nz@groupz@system)rM   rt   r   _parse_group_parse_system)rP   )rT   rI   rJ   rt     s    
z SystemRegistry._register_parsersc             C  s   | j | | j| j d S )N)r1   ro  r   r   rq   )rP   r   rI   rI   rJ   r    s    zSystemRegistry._parse_groupc             C  s   | j | | j| j d S )N)r2   ro  r   r  rq   )rP   r   rI   rI   rJ   r    s    zSystemRegistry._parse_systemTrj   ri   r1   )r   create_if_neededr\   c             C  s.   || j kr| j | S |s$td| | |S )aI  Return a Group.

        Parameters
        ----------
        name : str
            Name of the group to be
        create_if_needed : bool
            If True, create a group if not found. If False, raise an Exception.
            (Default value = True)

        Returns
        -------
        type
            Group
        zUnknown group %s)r  r   r1   )rP   r   r  rI   rI   rJ   r    s
    

zSystemRegistry.get_groupc             C  s   t | jS )N)r   ZListerr  )rP   rI   rI   rJ   r     s    zSystemRegistry.sysr2   c             C  s   | j S )N)r  )rP   rI   rI   rJ   default_system  s    zSystemRegistry.default_systemc             C  s*   |r || j krtd| i | _|| _d S )NzUnknown system %s)r  r   r  r  )rP   r   rI   rI   rJ   r    s
    
c             C  s.   || j kr| j | S |s$td| | |S )aK  Return a Group.

        Parameters
        ----------
        name : str
            Name of the group to be
        create_if_needed : bool
            If True, create a group if not found. If False, raise an Exception.
            (Default value = True)

        Returns
        -------
        type
            System

        zUnknown system %s)r  r   r2   )rP   r   r  rI   rI   rJ   
get_system  s
    

zSystemRegistry.get_systemc               s8   t  |\}}}t|tr.| d|j |||fS )Nr  )rM   r   r   r+   r  r  r   )rP   r   r   r   )rT   rI   rJ   r     s    
zSystemRegistry._definezUnion[UnitLike, Quantity]zUnion[str, System, None]zTuple[Number, Unit])r  r  r#  r\   c             C  s(   t |}| |||\}}|| |fS )a  Convert unit or dict of units to the base units.

        If any unit is non multiplicative and check_converter is True,
        then None is returned as the multiplicative factor.

        Unlike BaseRegistry, in this registry root_units might be different
        from base_units

        Parameters
        ----------
        input_units : UnitsContainer or str
            units
        check_nonmult : bool
            if True, None will be returned as the
            multiplicative factor if a non-multiplicative
            units is found in the final Units. (Default value = True)
        system :
             (Default value = None)

        Returns
        -------
        type
            multiplicative factor, base units

        )r>   _get_base_unitsrA   )rP   r  r  r#  r  r  rI   rI   rJ   r$  *  s     zSystemRegistry.get_base_unitsr   )r  r  r#  c             C  s   |d kr| j }|r0|| j kr0|| jkr0| j| S | ||\}}|sL||fS t|| }|  }| |dj}xN| D ]B\}}	||kr|| }
t|
| }
||
|	 9 }qv|| ||	i9 }qvW | |||}|r||f| j|< ||fS )NF)	r  r  r  r>   r5   r  Z
base_unitsr   r3  )rP   r  r  r#  r"  r  Zdestination_unitsr  r   r   Znew_unitZbase_factorrI   rI   rJ   r  P  s,    




zSystemRegistry._get_base_unitszFrozenSet[Unit]c               sl   |d kr| j }t ||}|rh|| jkr8| j| j}n$|| jkrP| j| j}ntd| t||@ S |S )Nz%Unknown Group o System with name '%s')r  rM   r&  r  r  r  r   r'  )rP   r  r(  rF  r  )rT   rI   rJ   r&  ~  s    


z$SystemRegistry._get_compatible_units)N)T)T)TN)TN)rU   rV   rW   rX   ra   ru   rO   rt   r  r  r  rY  r   r  rZ  r  r   r$  r  r&  rY   rI   rI   )rT   rJ   r    s$   
 % *r  c                  sp   e Zd ZdZddddddddddedfddddddd	 fd
dZdd ZddddddZej	Z	ej
Z
  ZS )UnitRegistryaM  The unit registry stores the definitions and relationships between units.

    Parameters
    ----------
    filename :
        path of the units definition file to load or line-iterable object.
        Empty to load the default definition file.
        None to leave the UnitRegistry empty.
    force_ndarray : bool
        convert any input, scalar or not to a numpy.ndarray.
    force_ndarray_like : bool
        convert all inputs other than duck arrays to a numpy.ndarray.
    default_as_delta :
        In the context of a multiplication of units, interpret
        non-multiplicative units as their *delta* counterparts.
    autoconvert_offset_to_baseunit :
        If True converts offset units in quantities are
        converted to their base units in multiplicative
        context. If False no conversion happens.
    on_redefinition : str
        action to take in case a unit is redefined.
        'warn', 'raise', 'ignore'
    auto_reduce_dimensions :
        If True, reduce dimensionality on appropriate operations.
    preprocessors :
        list of callables which are iteratively ran on any input expression
        or unit string
    fmt_locale :
        locale identifier string, used in `format_babel`. Default to None
    case_sensitive : bool, optional
        Control default case sensitivity of unit parsing. (Default: True)
    rg   FTrh   Nri   rj   )rl   rm   r^  r_  rn   rr   c               s(   t  j|||||||||	|
||d d S )N)r   rl   rm   rn   r^  r_  r#  ro   rp   rf   rq   rr   )rM   ra   )rP   r   rl   rm   r^  r_  rn   r#  ro   rp   rf   rq   rr   )rT   rI   rJ   ra     s    zUnitRegistry.__init__c             C  s
   t || S )u.  Builds dimensionless quantities using the Buckingham π theorem

        Parameters
        ----------
        quantities : dict
            mapping between variable name and units

        Returns
        -------
        list
            a list of dimensionless quantities expressed as dicts

        )r;   )rP   Z
quantitiesrI   rI   rJ   r;     s    zUnitRegistry.pi_theoremr[   )enabler\   c             C  s   ddl m} || | dS )zSet up handlers for matplotlib's unit support.

        Parameters
        ----------
        enable : bool
            whether support should be enabled or disabled (Default value = True)

        r   )setup_matplotlib_handlersN)Z
matplotlibr  )rP   r  r  rI   rI   rJ   setup_matplotlib  s    
zUnitRegistry.setup_matplotlib)T)rU   rV   rW   rX   rP  ra   r;   r  r   r  ZcheckrY   rI   rI   )rT   rJ   r    s"     r  c                  sF   e Zd ZdddZdd Zdd Z fdd	Zd
d Zdd Z  Z	S )LazyRegistryNc             C  s   |pd|pi f| j d< d S )NrI   params)r   )rP   rQ   rR   rI   rI   rJ   ra     s    zLazyRegistry.__init__c             C  s4   | j d \}}d|d< t| _| j|| |   d S )Nr  r   rn   )r   r  rT   ra   rO   )rP   rQ   rR   rI   rI   rJ   Z__init  s
    zLazyRegistry.__initc             C  s   |dkrdS |    t| |S )Nrw   r   )_LazyRegistry__initr   )rP   r   rI   rI   rJ   r   	  s    zLazyRegistry.__getattr__c               s0   |dkrt  || n|   t| || d S )NrT   )rM   __setattr__r  setattr)rP   r   r   )rT   rI   rJ   r  	  s    zLazyRegistry.__setattr__c             C  s   |    | | S )N)r  )rP   r   rI   rI   rJ   r   	  s    zLazyRegistry.__getitem__c             O  s   |    | ||S )N)r  )rP   rQ   rR   rI   rI   rJ   rN   	  s    zLazyRegistry.__call__)NN)
rU   rV   rW   ra   r  r   r  r   rN   rY   rI   rI   )rT   rJ   r    s   
r  c               @  sX   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd ZdS )ApplicationRegistryzGA wrapper class used to distribute changes to the application registry.c             C  s
   || _ d S )N)	_registry)rP   registryrI   rI   rJ   ra   	  s    zApplicationRegistry.__init__c             C  s   | j S )zGet the wrapped registry)r  )rP   rI   rI   rJ   r   	  s    zApplicationRegistry.getc             C  sN   t |t| r| }t |ttfs4tdt| td| j| || _dS )zSet the new registry

        Parameters
        ----------
        new_registry : ApplicationRegistry or LazyRegistry or UnitRegistry
            The new registry.

        See Also
        --------
        set_application_registry
        zExpected UnitRegistry; got %sz$Changing app registry from %r to %r.N)	r   r   r   r  r  r   r:   debugr  )rP   Znew_registryrI   rI   rJ   r|   "	  s    zApplicationRegistry.setc             C  s   t | j|S )N)r   r  )rP   r   rI   rI   rJ   r   8	  s    zApplicationRegistry.__getattr__c             C  s
   t | jS )N)dirr  )rP   rI   rI   rJ   r   ;	  s    zApplicationRegistry.__dir__c             C  s
   | j | S )N)r  )rP   r   rI   rI   rJ   r   >	  s    zApplicationRegistry.__getitem__c             O  s   | j ||S )N)r  )rP   rQ   rR   rI   rI   rJ   rN   A	  s    zApplicationRegistry.__call__c             C  s   | j |S )N)r  r   )rP   r   rI   rI   rJ   r   D	  s    z ApplicationRegistry.__contains__c             C  s
   t | jS )N)r   r  )rP   rI   rI   rJ   r   G	  s    zApplicationRegistry.__iter__N)rU   rV   rW   rX   ra   r   r|   r   r   r   rN   r   r   rI   rI   rI   rJ   r  	  s   r  )srX   Z
__future__r   r   r  Zimportlib.resourcesr   r8  r   r   rF   collectionsr   r   
contextlibr   decimalr   Z	fractionsr   ior   Znumbersr	   tokenizer
   r   typingr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rg   r   r   Z_typingr   r   compatr    r!   r"   rp  r#   r$   Z
convertersr%   r&   Zdefinitionsr'   r(   r)   r*   r+   errorsr,   r-   r.   r/   Z	pint_evalr0   r1   r2   utilr3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r   r@   r   rA   r   ZbabelZLocalerB   rH   r   	lru_cacherK   r   rL   rZ   rb   rP  rk   rj   ZPreprocessorTyperd   r]  rh  r  r  r  r  rI   rI   rI   rJ   <module>"   s   D8
          O      d!