
    Ɔc4                         d Z ddlZddlZddlmZmZ ddlmZ ddlZddl	m
Z
 ddlmZmZmZ  e            Z G d d	e          Z G d
 d          ZdS )zL
Helpers to interact with the ERFA library, in particular for leap seconds.
    N)datetime	timedelta)warn   )ErfaWarning)get_leap_secondsset_leap_secondsdt_eraLEAPSECONDc                   b     e Zd ZdZd fd	Zd fd	Zd Z fdZd Zd	 Z	e
d
             Z xZS )classpropertya  
    Similar to `property`, but allows class-level properties.  That is,
    a property whose getter is like a `classmethod`.

    The wrapped method may explicitly use the `classmethod` decorator (which
    must become before this decorator), or the `classmethod` may be omitted
    (it is implicit through use of this decorator).

    .. note::

        classproperty only works for *read-only* properties.  It does not
        currently allow writeable/deletable properties, due to subtleties of how
        Python descriptors work.  In order to implement such properties on a class
        a metaclass for that class must be implemented.

    Parameters
    ----------
    fget : callable
        The function that computes the value of this property (in particular,
        the function when this is used as a decorator) a la `property`.

    doc : str, optional
        The docstring for the property--by default inherited from the getter
        function.

    lazy : bool, optional
        If True, caches the value returned by the first call to the getter
        function, so that it is only called once (used for lazy evaluation
        of an attribute).  This is analogous to `lazyproperty`.  The ``lazy``
        argument can also be used when `classproperty` is used as a decorator
        (see the third example below).  When used in the decorator syntax this
        *must* be passed in as a keyword argument.

    Examples
    --------

    ::

        >>> class Foo:
        ...     _bar_internal = 1
        ...     @classproperty
        ...     def bar(cls):
        ...         return cls._bar_internal + 1
        ...
        >>> Foo.bar
        2
        >>> foo_instance = Foo()
        >>> foo_instance.bar
        2
        >>> foo_instance._bar_internal = 2
        >>> foo_instance.bar  # Ignores instance attributes
        2

    As previously noted, a `classproperty` is limited to implementing
    read-only attributes::

        >>> class Foo:
        ...     _bar_internal = 1
        ...     @classproperty
        ...     def bar(cls):
        ...         return cls._bar_internal
        ...     @bar.setter
        ...     def bar(cls, value):
        ...         cls._bar_internal = value
        ...
        Traceback (most recent call last):
        ...
        NotImplementedError: classproperty can only be read-only; use a
        metaclass to implement modifiable class-level properties

    When the ``lazy`` option is used, the getter is only called once::

        >>> class Foo:
        ...     @classproperty(lazy=True)
        ...     def bar(cls):
        ...         print("Performing complicated calculation")
        ...         return 1
        ...
        >>> Foo.bar
        Performing complicated calculation
        1
        >>> Foo.bar
        1

    If a subclass inherits a lazy `classproperty` the property is still
    re-evaluated for the subclass::

        >>> class FooSub(Foo):
        ...     pass
        ...
        >>> FooSub.bar
        Performing complicated calculation
        1
        >>> FooSub.bar
        1
    NFc                 ^     | fd}|S t                                                     S )Nc                      |           S )N)lazy )funcclsr   s    ,lib/python3.11/site-packages/erfa/helpers.pywrapperz&classproperty.__new__.<locals>.wrapper}   s    s4d++++    )super__new__)r   fgetdocr   r   	__class__s   `  ` r   r   zclassproperty.__new__y   sH     	, , , , , , Nwws###r   c                     || _         |rt          j                    | _        i | _        |                     |          }t                                          ||           |	|| _        d S d S )N)r   r   )	_lazy	threadingRLock_lock_cache
_wrap_fgetr   __init____doc__)selfr   r   r   r   s       r   r"   zclassproperty.__init__   su    
 	"**DJDKt$$d,,,  	DLLL	 	r   c                 t   | j         r| j                            |t                    }|t          u rl| j        5  | j                            |t                    }|t          u r$| j                            |          }|| j        |<   d d d            n# 1 swxY w Y   n| j                            |          }|S N)r   r    get	_NotFoundr   r   __wrapped__)r$   objobjtypevals       r   __get__zclassproperty.__get__   s    : 	1+//'955Ci 3Z 3 3+//'9==Ci' 3"i33G<</2G,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 )''00C
s   ABBBc                 l    t                                          |                     |                    S r&   )r   getterr!   )r$   r   r   s     r   r/   zclassproperty.getter   s%    ww~~dood33444r   c                      t          d          Nzcclassproperty can only be read-only; use a metaclass to implement modifiable class-level propertiesNotImplementedError)r$   fsets     r   setterzclassproperty.setter       !:; ; 	;r   c                      t          d          r1   r2   )r$   fdels     r   deleterzclassproperty.deleter   r6   r   c                 ~     t           t                    r j         t          j                    fd            }|S )Nc                 $     | j                   S r&   r   )r*   	orig_fgets    r   r   z&classproperty._wrap_fget.<locals>.fget   s    9S]+++r   )
isinstanceclassmethod__func__	functoolswraps)r=   r   s   ` r   r!   zclassproperty._wrap_fget   sT    i-- 	+!*I
 
	#	#	, 	, 	, 	, 
$	#	, r   )NNF)NF)__name__
__module____qualname__r#   r   r"   r-   r/   r5   r9   staticmethodr!   __classcell__r<   s   @r   r   r      s        _ _B	$ 	$ 	$ 	$ 	$ 	$     "  "5 5 5 5 5; ; ;
; ; ;
   \    r   r   c                       e Zd ZdZdZ	 dZ	 d Zed             Zed             Z	edd            Z
ed             Zed	             Zed
             ZdS )leap_secondsaN  Leap second management.

    This singleton class allows access to ERFA's leap second table,
    using the methods 'get', 'set', and 'update'.

    One can also check expiration with 'expires' and 'expired'.

    Note that usage of the class is similar to a ``ScienceState`` class,
    but it cannot be used as a context manager.
    N   c                      t          d          )Nz/This class is a singleton.  Do not instantiate.)RuntimeError)r$   s    r   r"   zleap_seconds.__init__   s    LMMMr   c                     t                      S )z2Get the current leap-second table used internally.)r   r   s    r   r'   zleap_seconds.get   s      !!!r   c                    	 |d         }n# t           $ r d}Y nw xY wt          |dd          }|t          |t                    st          |dd          }	 |/t          j        |                    d          d         d          }nt          j        |d	          }n4# t           $ r'}t          d
| d|t                     d}Y d}~nd}~ww xY wt          |d          r1|	                                t          t          j                           }t          j        |t          dd          }|j        dk    rt!          d          t          j        |dk    |d         dk    z  |d         dk    z  |d         dk     z            st!          d          t          j        |d         dd         dk    t          j        |d                   dk    z            rt!          d          ||fS )a  Validate a leap-second table.

        Parameters
        ----------
        table : array_like
            Must have 'year', 'month', and 'tai_utc' entries.  If a 'day'
            entry is present, it will be checked that it is always 1.
            If ``table`` has an 'expires' attribute, it will be interpreted
            as an expiration date.

        Returns
        -------
        array : `~numpy.ndarray`
            Structures array with 'year', 'month', 'tai_utc'.
        expires: `~datetime.datetime` or None
            Possible expiration date inferred from the table.  `None` if not
            present or if not a `~datetime.datetime` or `~astropy.time.Time`
            instance and not parsable as a 'dd month yyyy' string.

        Raises
        ------
        ValueError
            If the leap seconds in the table are not on the 1st of January or
            July, or if the sorted TAI-UTC do not increase in increments of 1.
        dayr   expiresNisotTr   z%Y-%m-%dz%d %B %Yz!ignoring non-datetime expiration z; parsing it raised 	__array__F)dtypecopyndminz(can only pass in one-dimensional tables.month   yeari  zDleap seconds inferred that are not on 1st of January or 1st of July.i  tai_utcz+jump in TAI-UTC by something else than one.)	Exceptiongetattrr>   r   strptime	partitionr   r   hasattrrT   listr
   namesnparrayndim
ValueErrorallanydiff)r   tablerP   rQ   rR   excs         r   validatezleap_seconds.validate   sb   6	,CC 	 	 	CCC	 %D11 	z'8'D'D 	 7FD11D
 E&/s0C0CA0F0:< <GG '/DDG    2 2 2*-2 23>@ @ @ 5+&& 	DOO%%d+;+A&B&BCE&6U " " " :> 	IGHHHvqg!+-05g!0CEV}t+- . . 	?  > ? ? ? 65="%,75+,,13 4 4 	LJKKKg~s%    AB 
C(C

Cc                 l    |d}n|                      |          \  }}t          |           || _        dS )aH  Set the ERFA leap second table.

        Note that it is generally safer to update the leap-second table than
        to set it directly, since most tables do not have the pre-1970 changes
        in TAI-UTC that are part of the built-in ERFA table.

        Parameters
        ----------
        table : array_like or `None`
            Leap-second table that should at least hold columns of 'year',
            'month', and 'tai_utc'.  Only simple validation is done before it
            is being used, so care need to be taken that entries are correct.
            If `None`, reset the ERFA table to its built-in values.

        Raises
        ------
        ValueError
            If the leap seconds in the table are not on the 1st of January or
            July, or if the sorted TAI-UTC do not increase in increments of 1.
        N)rm   r	   _expires)r   rk   rQ   s      r   setzleap_seconds.set#  sA    ,  	1GG \\%00NE7r   c                     | j         L|                                 d         }t          |d         |d         d          t          | j                  z   S | j         S )zThe expiration date of the current ERFA table.

        This is either a date inferred from the last table used to update or
        set the leap-second array, or a number of days beyond the last leap
        second.
        Nr[   rZ   rX   r   )ro   r'   r   r   _expiration_days)r   lasts     r   rQ   zleap_seconds.expiresA  sX     < 	 7799R=DT&\4=!<<c2334 5 <r   c                 :    | j         t          j                    k     S )z:Whether the leap second table is valid beyond the present.)rQ   r   nowrN   s    r   expiredzleap_seconds.expiredP  s     {X\^^++r   c                 0   |                      |          \  }}	 |                      |                                           \  }}n8# t          $ r+ |                                  |                                 }Y nw xY wt	          j        ||          }|                     |           	 ||| j        k    r|| _        n<# t          $ r/}t          dt          |          z   t                     Y d}~nd}~ww xY wt          |          t          |          z
  S )a]  Add any leap seconds not already present to the ERFA table.

        This method matches leap seconds with those present in the ERFA table,
        and extends the latter as necessary.

        If the ERFA leap seconds file was corrupted, it will be reset.

        If the table is corrupted, the ERFA file will be unchanged.

        Parameters
        ----------
        table : array_like or `~astropy.utils.iers.LeapSeconds`
            Array or table with TAI-UTC from leap seconds.  Should have
            'year', 'month', and 'tai_utc' columns.

        Returns
        -------
        n_update : int
            Number of items updated.

        Raises
        ------
        ValueError
            If the leap seconds in the table are not on the 1st of January or
            July, or if the sorted TAI-UTC do not increase in increments of 1.
        NzStable 'expires' attribute ignored as comparing it with a datetime raised an error:
)rm   r'   r]   rp   rd   union1drQ   ro   r   strr   len)r   rk   rQ   erfa_ls_lsrl   s          r   updatezleap_seconds.updateU  s5   8 e,,w	 cggii00JGQQ 	  	  	 GGIIIggiiGGG	 
 Z''
	 'w'< '& 	 	 	 68;CA       	
 2wwW%%s)   *A 2A:9A:(B= =
C6%C11C6r&   )rC   rD   rE   r#   ro   rr   r"   r?   r'   rm   rp   r   rQ   rv   r~   r   r   r   rI   rI      s        	 	 HCHN N N " " [" F F [FP    [:     ]  , , ], 4& 4& [4& 4& 4&r   rI   )r#   rA   r   r   r   warningsr   numpyrd   corer   ufuncr   r	   r
   objectr(   propertyr   rI   r   r   r   <module>r      s            ( ( ( ( ( ( ( (                 G G G G G G G G G G FHH	h h h h hH h h hVH& H& H& H& H& H& H& H& H& H&r   