ó
šßÈ[c           @` sç  d  Z  d d l m Z m Z m Z m Z d d l m Z d d l m	 Z	 d d l
 Z
 d d l Z d d l m Z d d l m Z d d l Z d d	 l m Z d d
 l m Z d d d d d d d d d d d g Z d e f d „  ƒ  YZ d e f d „  ƒ  YZ g  Z d „  Z d e f d „  ƒ  YZ e j e ƒ d e f d „  ƒ  Yƒ Z d e f d  „  ƒ  YZ  d! e f d" „  ƒ  YZ! d# „  Z" d$ „  Z# d% e f d& „  ƒ  YZ$ d' „  Z% d( „  Z& d) „  Z' d d* e& e' d+ „ Z) d, e f d- „  ƒ  YZ* d S(.   uJ   
This module contains helper functions and classes for handling metadata.
i    (   t   absolute_importt   divisiont   print_functiont   unicode_literalsi   (   t   six(   t   wrapsN(   t   OrderedDict(   t   deepcopy(   t   AstropyWarning(   t   dtype_bytes_or_charsu   MergeConflictErroru   MergeConflictWarningu   MERGE_STRATEGIESu   common_dtypeu	   MergePlusu   MergeNpConcatenateu   MergeStrategyu   MergeStrategyMetau   enable_merge_strategiesu   mergeu   MetaDatat   MergeConflictErrorc           B` s   e  Z RS(    (   t   __name__t
   __module__(    (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyR
      s   t   MergeConflictWarningc           B` s   e  Z RS(    (   R   R   (    (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyR      s   c         ` si  d „  ‰  t  j t  j t  j t  j t  j f ‰ t ‡  ‡ f d †  |  Dƒ ƒ } t | ƒ d k r§ g  |  D] } ˆ  | ƒ j ^ qe } t	 d j
 | ƒ ƒ } | | _ | ‚ n  g  |  D]! } t  j d d ˆ  | ƒ ƒ^ q® }  xa t |  ƒ D]S \ } } | j j d k râ | j j d k rd n d	 t | j ƒ g |  | <qâ qâ Wt  j g  |  D] } | d
 ^ qFƒ } | j j S(   u½  
    Use numpy to find the common dtype for a list of ndarrays.

    Only allow arrays within the following fundamental numpy data types:
    ``np.bool``, ``np.object``, ``np.number``, ``np.character``, ``np.void``

    Parameters
    ----------
    arrs : list of ndarray objects
        Arrays for which to find the common dtype

    Returns
    -------
    dtype_str : str
        String representation of dytpe (dtype ``str`` attribute)
    c         S` s   t  |  d t j d ƒ ƒ S(   Nu   dtypeu   O(   t   getattrt   npt   dtype(   t   arr(    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyR   7   s    c         3` s.   |  ]$ ‰  t  ‡  ‡ f d  †  ˆ Dƒ ƒ Vq d S(   c         3` s'   |  ] } t  ˆ ˆ  ƒ j | ƒ Vq d  S(   N(   t
   issubclasst   type(   t   .0t   np_type(   R   R   (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pys	   <genexpr>;   s    N(   t   tuple(   R   (   R   t   np_types(   R   s5   lib/python2.7/site-packages/astropy/utils/metadata.pys	   <genexpr>;   s   i   u"   Arrays have incompatible types {0}R   u   Su   Uu   0t   0i    (   u   Su   U(   R   t   bool_t   object_t   numbert	   charactert   voidt   sett   lent   nameR
   t   formatt   _incompat_typest   emptyt	   enumerateR   t   kindR	   t   arrayt   str(   t   arrst
   uniq_typesR   t   incompat_typest   tmet   it
   arr_common(    (   R   R   s5   lib/python2.7/site-packages/astropy/utils/metadata.pyt   common_dtype&   s"    	$"			.&t   MergeStrategyMetac           B` s   e  Z d  Z d „  Z RS(   uc   
    Metaclass that registers MergeStrategy subclasses into the
    MERGE_STRATEGIES registry.
    c   	      ` sè   t  t |  ƒ j |  | | | ƒ } d | k rz t | d t ƒ rz | d j ‰  t ˆ  ƒ ‡  f d †  ƒ } t | ƒ | _ n  d | k rä | d } t | t ƒ r« | g } n  x6 t	 | ƒ D]% \ } } t
 j d | | | f ƒ q¸ Wn  | S(   Nu   mergec         ` s:   y ˆ  |  | | ƒ SWn t  k
 r5 } t | ƒ ‚ n Xd  S(   N(   t	   ExceptionR
   (   t   clst   leftt   rightt   err(   t
   orig_merge(    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyt   merge`   s    u   typesi    (   t   superR/   t   __new__t
   isinstancet   classmethodt   __func__R   R6   R   t   reversedt   MERGE_STRATEGIESt   insert(	   t   mclsR    t   basest   membersR1   R6   t   typesR2   R3   (    (   R5   s5   lib/python2.7/site-packages/astropy/utils/metadata.pyR8   X   s    !
 (   R   R   t   __doc__R8   (    (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyR/   R   s   t   MergeStrategyc           B` s   e  Z d  Z e Z RS(   u^	  
    Base class for defining a strategy for merging metadata from two
    sources, left and right, into a single output.

    The primary functionality for the class is the ``merge(cls, left, right)``
    class method.  This takes ``left`` and ``right`` side arguments and
    returns a single merged output.

    The first class attribute is ``types``.  This is defined as a list of
    (left_types, right_types) tuples that indicate for which input types the
    merge strategy applies.  In determining whether to apply this merge
    strategy to a pair of (left, right) objects, a test is done:
    ``isinstance(left, left_types) and isinstance(right, right_types)``.  For
    example::

      types = [(np.ndarray, np.ndarray),  # Two ndarrays
               (np.ndarray, (list, tuple)),  # ndarray and (list or tuple)
               ((list, tuple), np.ndarray)]  # (list or tuple) and ndarray

    As a convenience, ``types`` can be defined as a single two-tuple instead of
    a list of two-tuples, e.g. ``types = (np.ndarray, np.ndarray)``.

    The other class attribute is ``enabled``, which defaults to ``False`` in
    the base class.  By defining a subclass of ``MergeStrategy`` the new merge
    strategy is automatically registered to be available for use in
    merging. However, by default the new merge strategy is *not enabled*.  This
    prevents inadvertently changing the behavior of unrelated code that is
    performing metadata merge operations.

    In most cases (particularly in library code that others might use) it is
    recommended to leave custom strategies disabled and use the
    `~astropy.utils.metadata.enable_merge_strategies` context manager to locally
    enable the desired strategies.  However, if one is confident that the
    new strategy will not produce unexpected behavior, then one can globally
    enable it by setting the ``enabled`` class attribute to ``True``.

    Examples
    --------
    Here we define a custom merge strategy that takes an int or float on
    the left and right sides and returns a list with the two values.

      >>> from astropy.utils.metadata import MergeStrategy
      >>> class MergeNumbersAsList(MergeStrategy):
      ...     types = ((int, float), (int, float))  # (left_types, right_types)
      ...
      ...     @classmethod
      ...     def merge(cls, left, right):
      ...         return [left, right]

    (   R   R   RC   t   Falset   enabled(    (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyRD   t   s   3t	   MergePlusc           B` s;   e  Z d  Z e e f e e f g Z e Z e d „  ƒ Z	 RS(   u€   
    Merge ``left`` and ``right`` objects using the plus operator.  This
    merge strategy is globally enabled by default.
    c         C` s   | | S(   N(    (   R1   R2   R3   (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyR6   ·   s    (
   R   R   RC   t   listR   RB   t   TrueRF   R:   R6   (    (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyRG   ¯   s   t   MergeNpConcatenatec           B` s\   e  Z d  Z e j e j f e j e e f f e e f e j f g Z e Z	 e
 d „  ƒ Z RS(   u×   
    Merge ``left`` and ``right`` objects using np.concatenate.  This
    merge strategy is globally enabled by default.

    This will upcast a list or tuple to np.ndarray and the output is
    always ndarray.
    c         C` sB   t  j | ƒ t  j | ƒ } } t | | g ƒ t  j | | g ƒ S(   N(   R   t
   asanyarrayR.   t   concatenate(   R1   R2   R3   (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyR6   É   s    (   R   R   RC   R   t   ndarrayRH   R   RB   RI   RF   R:   R6   (    (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyRJ   ¼   s   c         C` s   t  |  | ƒ o t  | | ƒ S(   N(   R9   (   R2   R3   R1   (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyt   _both_isinstanceÐ   s    c         C` s-   y t  |  | k ƒ SWn t k
 r( t SXd  S(   N(   t   boolR0   RI   (   R2   R3   (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyt
   _not_equalÔ   s    t   _EnableMergeStrategiesc           B` s#   e  Z d  „  Z d „  Z d „  Z RS(   c         G` s[   | |  _  i  |  _ xB t D]: \ } } } t | | ƒ r | j |  j | <t | _ q q Wd  S(   N(   t   merge_strategiest   orig_enabledR=   R   RF   RI   (   t   selfRR   t	   left_typet
   right_typet   merge_strategy(    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyt   __init__Ü   s    		c         C` s   d  S(   N(    (   RT   (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyt	   __enter__ä   s    c         C` s-   x& |  j  j ƒ  D] \ } } | | _ q Wd  S(   N(   RS   t   itemsRF   (   RT   R   t   valuet   tbRW   RF   (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyt   __exit__ç   s    (   R   R   RX   RY   R]   (    (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyRQ   Û   s   		c          G` s
   t  |  Œ  S(   uE  
    Context manager to temporarily enable one or more custom metadata merge
    strategies.

    Examples
    --------
    Here we define a custom merge strategy that takes an int or float on
    the left and right sides and returns a list with the two values.

      >>> from astropy.utils.metadata import MergeStrategy
      >>> class MergeNumbersAsList(MergeStrategy):
      ...     types = ((int, float),  # left side types
      ...              (int, float))  # right side types
      ...     @classmethod
      ...     def merge(cls, left, right):
      ...         return [left, right]

    By defining this class the merge strategy is automatically registered to be
    available for use in merging. However, by default new merge strategies are
    *not enabled*.  This prevents inadvertently changing the behavior of
    unrelated code that is performing metadata merge operations.

    In order to use the new merge strategy, use this context manager as in the
    following example::

      >>> from astropy.table import Table, vstack
      >>> from astropy.utils.metadata import enable_merge_strategies
      >>> t1 = Table([[1]], names=['a'])
      >>> t2 = Table([[2]], names=['a'])
      >>> t1.meta = {'m': 1}
      >>> t2.meta = {'m': 2}
      >>> with enable_merge_strategies(MergeNumbersAsList):
      ...    t12 = vstack([t1, t2])
      >>> t12.meta['m']
      [1, 2]

    One can supply further merge strategies as additional arguments to the
    context manager.

    As a convenience, the enabling operation is actually done by checking
    whether the registered strategies are subclasses of the context manager
    arguments.  This means one can define a related set of merge strategies and
    then enable them all at once by enabling the base class.  As a trivial
    example, *all* registered merge strategies can be enabled with::

      >>> with enable_merge_strategies(MergeStrategy):
      ...    t12 = vstack([t1, t2])

    Parameters
    ----------
    merge_strategies : one or more `~astropy.utils.metadata.MergeStrategy` args
        Merge strategies that will be enabled.

    (   RQ   (   RR   (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyt   enable_merge_strategiesì   s    8c         C` s(   d j  |  t | ƒ t | ƒ | ƒ } | S(   NuE   Cannot merge meta key {0!r} types {1!r} and {2!r}, choosing {0}={3!r}(   R!   R   (   t   keyR2   R3   t   out(    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyt   _warn_str_func'  s    c         C` s%   d j  |  t | ƒ t | ƒ ƒ } | S(   Nu1   Cannot merge meta key {0!r} types {1!r} and {2!r}(   R!   R   (   R_   R2   R3   R`   (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyt   _error_str_func.  s    u   warnc         C` sb  t  |  | t ƒ s! t d ƒ ‚ n  t |  ƒ } x.t j | ƒ D]\ } } | | k rk t | ƒ | | <q= n  t  |  | | | t ƒ r¬ t |  | | | | d | ƒ| | <q= y¥ | d k r5x’ t D]f \ }	 }
 } | j	 sà qÂ n  t
 |  | |	 ƒ rÂ t
 | | |
 ƒ rÂ | j |  | | | ƒ | | <PqÂ qÂ Wt ‚ n | |  | | | ƒ | | <Wq= t k
 rY|  | d k r‚| | | | <qZ| | d k r£|  | | | <qZt |  | | | ƒ rH| d k rít j | | |  | | | ƒ t ƒ nJ | d k rt | | |  | | | ƒ ƒ ‚ n | d k r7t d ƒ ‚ n  | | | | <qZ| | | | <q= Xq= W| S(   u€   
    Merge the ``left`` and ``right`` metadata objects.

    This is a simplistic and limited implementation at this point.
    u%   Can only merge two dict-based objectst   metadata_conflictsu   warnu   erroru   silentuG   metadata_conflicts argument must be one of "silent", "warn", or "error"N(   RN   t   dictR
   R   R   t	   iteritemsR6   t   NoneR=   RF   R9   RP   t   warningst   warnR   t
   ValueError(   R2   R3   t
   merge_funcRc   t   warn_str_funct   error_str_funcR`   R_   t   valRU   RV   t	   merge_cls(    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyR6   5  sJ    		
#t   MetaDatac           B` s/   e  Z d  Z d e d „ Z d „  Z d „  Z RS(   ué  
    A descriptor for classes that have a ``meta`` property.

    This can be set to any valid `~collections.Mapping`.

    Parameters
    ----------
    doc : `str`, optional
        Documentation for the attribute of the class.
        Default is ``""``.

        .. versionadded:: 1.2

    copy : `bool`, optional
        If ``True`` the the value is deepcopied before setting, otherwise it
        is saved as reference.
        Default is ``True``.

        .. versionadded:: 1.2
    u    c         C` s   | |  _  | |  _ d  S(   N(   RC   t   copy(   RT   t   docRp   (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyRX     s    	c         C` s5   | d  k r |  St | d ƒ s. t ƒ  | _ n  | j S(   Nu   _meta(   Rf   t   hasattrR   t   _meta(   RT   t   instancet   owner(    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyt   __get__“  s
    c         C` sd   | d  k r t ƒ  | _ nE t | t j ƒ rT |  j rH t | ƒ | _ q` | | _ n t d ƒ ‚ d  S(   Nu    meta attribute must be dict-like(	   Rf   R   Rs   R9   t   collectionst   MappingRp   R   t	   TypeError(   RT   Rt   R[   (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyt   __set__š  s    	(   R   R   RC   RI   RX   Rv   Rz   (    (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyRo   y  s   	(+   RC   t
   __future__R    R   R   R   t   externR   t   utilsR   Rg   Rw   R   Rp   R   t   numpyR   t   utils.exceptionsR   t
   utils.miscR	   t   __all__Ry   R
   R   R=   R.   R   R/   t   add_metaclasst   objectRD   RG   RJ   RN   RP   RQ   R^   Ra   Rb   Rf   R6   Ro   (    (    (    s5   lib/python2.7/site-packages/astropy/utils/metadata.pyt   <module>   s@   "		,":			;		B