
    Ki>W                       d dl mZ d dlmZ d dlmZ  ed       G d d             Zd+dZd	d
ddddddddd
Zd,dZ	d-d.dZ
 G d d      Z G d de      Z G d de      Z G d de      Z G d d e      Z G d! d"e      Z G d# d$e      Z G d% d&      Zd/d'Zed(k(  r6d dlZ eej.                        d)k(  r e eej.                  d*                yyy)0    )annotations)	Generator)	dataclassT)frozenc                  V    e Zd ZU dZded<   dZded<   dZded<   dZded<   dd	Zdd
Z	y)SequenceN
int | Nonestartstop   intstepnthc                @    | j                   du xr | j                  dk(  S )z2Return True if this sequence describes a wildcard.Nr   )r
   r   selfs    [/home/jay/workspace/scripts/.codegraph-venv/lib/python3.12/site-packages/cronsim/explain.pyis_starzSequence.is_star   s    zzT!4dii1n4    c                T    | j                   duxr | j                   | j                  k(  S )zBReturn True if this sequence describes a a single, specific value.Nr
   r   r   s    r   	is_singlezSequence.is_single   s#    zz%A$**		*AAr   )returnbool)
__name__
__module____qualname__r
   __annotations__r   r   r   r   r    r   r   r   r      s4    E:D*D#MC5Br   r   c                    t        |       dk(  r| d   S t        |       dk(  r| d    d| d    S dj                  | dd       }| d| d    S )	zJoin together strings using commas and 'and' as separators.

    >>> join(["a"])
    'a'
    >>> join(["a", "b"])
    'a and b'
    >>> join(["a", "b", "c"])
    'a, b, and c'
    r   r      z and z, Nz, and )lenjoin)lheads     r   r$   r$      se     1v{t
1v{A$uQqTF##99QsVDV6!B%!!r   lastfirstsecondthirdfourthfifthsixthseventheighthninth)
r"   r   r!                     	   c                4    t         j                  | |  d      S )zhFormat integer as an ordinal number.

    >>> ordinal(1)
    'first'
    >>> ordinal(15)
    '15th'
    th)ORDINALSget)xs    r   ordinalr=   9   s     <<aS8$$r   Nc                2    |	| dd|dS | dd|dd|dS )zFormat time as HH:MM or HH:MM:SS (if seconds are specified).

    >>> format_time(0, 0)
    '00:00'
    >>> format_time(1, 23)
    '01:23'
    >>> format_time(11, 22, 33)
    '11:22:33'
    02d:r   )hmss      r   format_timerD   D   s;     	yC!C!!WAaWAaW%%r   c                      e Zd ZU dZg Zded<   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dZdddZddZddZy)FieldFIXME	list[str]symbolicr   c                b   || _         g | _        | j                  |      D ],  }|| j                  vs| j                  j                  |       . | j                  d   j                  | _        | j                  D ]=  }|j                  | j
                  k7  s|j                  | j
                  k7  s6d | _         n | j
                  dk(  | _        t        d | j                  D              | _	        t        d | j                  D              | _        t        d | j                  D              | _        y )Nr   c              3  <   K   | ]  }|j                           y wN)r   .0seqs     r   	<genexpr>z!Field.__init__.<locals>.<genexpr>m   s     =#=   c              3  <   K   | ]  }|j                           y wrL   r   rM   s     r   rP   z!Field.__init__.<locals>.<genexpr>o        F3s}}FrQ   c              3  <   K   | ]  }|j                           y wrL   rS   rM   s     r   rP   z!Field.__init__.<locals>.<genexpr>q   rT   rQ   )valueparsedparseappendr
   single_valuer   zeroallstaranyany_singlesall_singles)r   rV   rO   s      r   __init__zField.__init__Z   s    
&(::e$ 	(C$++%""3'	( !KKN00;; 	CyyD---T=N=N1N$(!	 %%*	===	F$++FFF$++FFr   c              #  D  K   |j                  d      D ]  }|dk(  rt                t        | t              r6|j	                  d      r%| j                  |dd       }t        ||d       \d|v r?|j                  d      \  }}| j                  |      }t        ||t        |             d|v r|j                  d      \  }}t        |      }|dk(  rt        |	       |d
k(  rt        ddd       |dk(  rt        ddd       d|v r7|j                  d      \  }}| j                  |      | j                  |      }
}	n| j                  |      }	| j                  }
|	| j                  k  r|
| j                  k\  rt        |	       t        |	|
|       d|v r|j                  d      \  }}| j                  |      | j                  |      }
}	|	dz   |
k(  r t        |	|	       t        |
|
       |	| j                  k  r|
| j                  k\  rt                )t        |	|
       :|d
k(  rt        ddd       Q|dk(  rt        ddd       h| j                  |      }t        ||        yw)z@Parse a single field of a cron expression into Sequence objects.,*LNr"   )r
   r   r   #/)r   LW-)r
   r   r   r   r   )	splitr   
isinstanceWeekdayendswith_intr   	max_value	min_value)r   rV   termvr   step_strr   	start_strstop_strr
   r   s              r   rX   zField.parses   sD    KK$ 0	0Ds{j D'*t}}S/AIId3Bi(QQB77 JJsO	cIIdOQQCH==!%Ch8}3;"--T\"""==S["""==d{.2jjo+	8&*ii	&:DIIh<Ot $		$#~~.44>>3I&D11&UDII&*jjo#	8"ii	2DIIh4Gt19$"U;;"D99dnn,1G"*$"T::Rbb99Rbb99IIdOQQ//a0	0s   JJ c                j    || j                   v r| j                   j                  |      S t        |      S )zConvert a value from a cron expression to an integer.

        For month and weekday fields, this takes care of converting JAN, FEB, ...
        and MON, TUE, ...
        )rI   indexr   r   rV   s     r   ro   z
Field._int   s/     DMM!==&&u--5zr   c                    | j                   D cg c])  }t        |j                  t              s|j                  + c}S c c}w )z3Return a list only the single values in this field.)rW   rl   r
   r   )r   rO   s     r   singleszField.singles   s+    %)[[OcJsyy#4N		OOOs
   A A c                    t        |      S )z\Convert an integer value to a string for display.

        >>> label(1)
        '1'
        strr   idxs     r   labelzField.label   s     3xr   c                B    | j                    d| j                  |       S )z\Format a single value for display.

        >>> format_single(1)
        'minute 1'
         )namer   ry   s     r   format_singlezField.format_single   s#     ))Adjj/011r   c                    t         )zhFormat nth-weekday-of-month and L values.

        Implemented in Month and Weekday subclasses.
        )NotImplementedError)r   rV   r   s      r   
format_nthzField.format_nth   s
    
 "!r   c                `    |dk(  rd| j                    S dt        |       d| j                    S )zFormat wildcard and wildcard-with-step values.

        >>> format_every(1)
        'every minute'

        >>> format_every(5)
        'every 5th minute'
        r   every r   )r   r=   )r   r   s     r   format_everyzField.format_every   s7     19DII;''a		{33r   c                    | j                  |      }| j                  |      }|dk(  rd| j                   d| d| S dt        |       d| j                   d| d| S )zFormat a sequence.

        >>> format_seq(1, 10)
        'every minute from 1 through 10'

        >>> format_seq(1, 10, 2)
        'every 2nd minute from 1 through 10'
        r   r    from 	 through r   )r   r   r=   )r   r
   r   r   ru   rv   s         r   
format_seqzField.format_seq   sk     JJu%	::d#19DII;fYKy
KKa		{&9XJWWr   c                X   g }| j                   D ]  }|j                  +|j                  | j                  |j                               ;|j
                  |j                  k7  rO|j
                  J |j                  | j                  |j                  |j
                  |j                               |j                  6|j                  | j                  |j                  |j                               |j                  | j                  |j                                t        |      S )z=Format every component of this field, and join them together.)rW   r
   rY   r   r   r   r   r   r   r   r$   )r   partsrO   s      r   formatzField.format   s    ;; 		<Cyy T..sxx89SYY&xx+++T__SYY#((KL$T__SYY@AT//		:;		< E{r   c                "    | j                         S )zReturn a human-friendly representation of this field.

        Subclasses can override this method to add prepositions ("at", "on", "in").
        )r   r   s    r   __str__zField.__str__   s    
 {{}r   N)rV   r~   )rV   r~   r   zGenerator[Sequence, None, None])rV   r~   r   r   )r   z	list[int]r   r   r   r~   rV   r   r   r~   rV   r   r   r   r   r~   r   )r   r   r   r~   r
   r   r   r   r   r   r   r~   r   r~   )r   r   r   r   rI   r   rq   rp   ra   rX   ro   r{   r   r   r   r   r   r   r   r   r   r   rF   rF   T   sV    DHiIIG220hP2"4X r   rF   c                  8     e Zd ZdZdZdZd fdZd fdZ xZS )Secondr)   r   ;   c                    | j                   rRt        | j                        dkD  r:| j                         D cg c]  }| j	                  |       }}dt        |       S t        |          S c c}w )zFormat the minute field.

        This method adds special handling when all values are single values. Instead
        of "second 1, second 3, and second 5", it produces "seconds 1, 3, and 5".
        r   zseconds r`   r#   rW   r{   r   r$   superr   r   rs   labels	__class__s      r   r   zSecond.format  b     DKK 01 4-1\\^<djjm<F<d6l^,,w~ =   A.c                F    t         |          }| j                  rd|z   S |S )a  Return a human-friendly representation of the second field.

        This method adds the 'at' preposition to the formatted string if the field has
        any single values.

        For example, if the field has a single range (1-5), the result will be
        "every second from 1 through 5". But if the field also has a single field
        (1-5,10), the result will be "at every second from 1 through 5 and second 10".
        at r   r   r_   r   resultr   s     r   r   zSecond.__str__  )     "6>!r   r   	r   r   r   r   rq   rp   r   r   __classcell__r   s   @r   r   r      !    DII	  r   r   c                  8     e Zd ZdZdZdZd fdZd fdZ xZS )Minuteminuter   r   c                    | j                   rRt        | j                        dkD  r:| j                         D cg c]  }| j	                  |       }}dt        |       S t        |          S c c}w )zFormat the minute field.

        This method adds special handling when all values are single values. Instead
        of "minute 1, minute 3, and minute 5", it produces "minutes 1, 3, and 5".
        r   zminutes r   r   s      r   r   zMinute.format&  r   r   c                F    t         |          }| j                  rd|z   S |S )a  Return a human-friendly representation of the minute field.

        This method adds the 'at' preposition to the formatted string if the field has
        any single values.

        For example, if the field has a single range (1-5), the result will be
        "every minute from 1 through 5". But if the field also has a single field
        (1-5,10), the result will be "at every minute from 1 through 5 and minute 10".
        r   r   r   s     r   r   zMinute.__str__1  r   r   r   r   r   s   @r   r   r   !  r   r   r   c                  8     e Zd ZdZdZdZd fdZd fdZ xZS )Hourhourr      c                    | j                   rRt        | j                        dkD  r:| j                         D cg c]  }| j	                  |       }}dt        |       S t        |          S c c}w )zFormat the hour field.

        This method adds special handling when all values are single values. Instead
        of "hour 1, hour 3, and hour 5", it produces "hours 1, 3, and 5".
        r   zhours r   r   s      r   r   zHour.formatG  sb     DKK 01 4-1\\^<djjm<F<DL>**w~ =r   c                &    dt         |          z   S )zReturn a human-friendly representation of the minute field.

        This method adds the 'past' preposition to the formatted string. For example,
        if the hour field has a single value (5), the result will be "past hour 5".
        zpast r   r   r   r   s    r   r   zHour.__str__R  s     ***r   r   r   r   s   @r   r   r   B  s!    DII	 + +r   r   c                  L     e Zd ZdZdZdZddZd	 fdZd
 fdZd
 fdZ	 xZ
S )Dayzday of monthr      c                     dt        |       dS )zuFormat a single day-of-month value for display.

        >>> format_single(2)
        'the 2nd day of month'
        the  day of month)r=   ry   s     r   r   zDay.format_single`  s     gen%]33r   c                P    |dk(  r|dk(  ry|dk(  r|dk(  ryt         |   ||      S )zFormat the L and LW values.

        >>> format_nth(-1)
        'the last day of the month'
        >>> format_nth(-2)
        'the last weekday of the month'
        r"   zthe last day of the monthri   zthe last weekday of the month)r   r   )r   rV   r   r   s      r   r   zDay.format_nthh  s7     "9"."9"2w!%--r   c                    | j                   rUt        | j                        dkD  r=| j                         }d|vr)|D cg c]  }dt	        |        }}t        |       dS t        |          S c c}w )a  Format the day field.

        This method adds special handling for the case when
        all values are single values. For example, instead of
        "the 1st day of month, the 3rd day of month, and the 5th day of month"
        it produces "the 1st, 3rd, and 5th day of month".

        We cannot apply this optimization if the single values contain "-2"
        (the special value for "last weekday of the month").
        r   ri   r   r   )r`   r#   rW   r{   r=   r$   r   r   )r   r{   rs   r   r   s       r   r   z
Day.formatv  ss     DKK 01 4llnG 7>?!D-??v,}55w~ @s   A1c                &    dt         |          z   S )zReturn a human-friendly representation of the day of month field.

        This method unconditionally adds the 'on' preposition.
        on r   r   s    r   r   zDay.__str__      
 uw(((r   r   r   r   )r   r   r   r   rq   rp   r   r   r   r   r   r   s   @r   r   r   [  s+    DII4. $) )r   r   c                  |     e Zd ZdZdZdZdj                         Zdj                         Zd	dZ	d
dZ
d fdZ xZS )Monthmonthr      z1_ JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DECzW_ January February March April May June July August September October November Decemberc                     | j                   |   S )zZConvert an integer value to a month name.

        >>> label(1)
        'January'
        r   r   s     r   r   zMonth.label       {{3r   c                $    | j                  |      S )zbFormat a single month value for display.

        >>> format_single(2)
        'February'
        r   ry   s     r   r   zMonth.format_single       zz%  r   c                &    dt         |          z   S )zReturn a human-friendly representation of the month field.

        This method unconditionally adds the 'in' preposition.
        zin r   r   s    r   r   zMonth.__str__  r   r   r   r   r   )r   r   r   r   rq   rp   rk   rI   r   r   r   r   r   r   s   @r   r   r     sB    DIIBHHJHfllnF !) )r   r   c                       e Zd ZdZdZdZdj                         Zdj                         ZddZ	ddZ
ddZdd fd	Zd fd
Z xZS )rm   zday of weekr   r5   zSUN MON TUE WED THU FRI SAT SUNz?Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sundayc                     | j                   |   S )z_Convert an integer value to a day of week name.

        >>> label(1)
        'Monday'
        r   r   s     r   r   zWeekday.label  r   r   c                $    | j                  |      S )zaFormat a single month value for display.

        >>> format_single(2)
        'Tuesday'
        r   ry   s     r   r   zWeekday.format_single  r   r   c                ^    | j                  |      }|dk(  rd| dS dt        |       d| dS )zFormat the nth-weekday-of-month value.

        >>> format_nth(2, -1)
        'the last Tuesday of the month'
        >>> format_nth(2, 4)
        'the 4th Tuesday of the month'
        r"   z	the last z of the monthr   r   )r   r=   )r   rV   r   r   s       r   r   zWeekday.format_nth  sA     

5!"9ug]33gcl^1UG=99r   c                z    |dk(  r%| j                  |       d| j                  |       S t        | 	  |||      S )zFormat a sequence of weekdays.

        >>> format_seq(1, 3)
        'Monday through Wednesday'
        >>> format_seq(1, 7, 2)
        'evary 2nd day of week from Monday through Sunday'
        r   r   )r   r   r   )r   r
   r   r   r   s       r   r   zWeekday.format_seq  sG     19 jj'(	$**T2B1CDDw!%t44r   c                &    dt         |          z   S )zReturn a human-friendly representation of the month field.

        This method unconditionally adds the 'on' preposition.
        r   r   r   s    r   r   zWeekday.__str__  r   r   r   r   r   r   r   r   )r   r   r   r   rq   rp   rk   rI   r   r   r   r   r   r   r   r   s   @r   rm   rm     sL    DII0668HNTTVF !:5 ) )r   rm   c                  <    e Zd ZddZd	dZd
dZddZddZddZy)
Expressionc                   t        |      dk(  r|j                  dd       t        |d         | _        t	        |d         | _        t        |d         | _        t        |d         | _	        t        |d         | _        t        |d         | _        |d   j                  d      xs |d   j                  d      | _        y )	Nr3   r   0r   r!   r1   r2   rd   )r#   insertr   r)   r   r   r   r   r   dayr   r   rm   dow
startswithday_and)r   r   s     r   ra   zExpression.__init__  s    u:?LLC U1X&U1X&qN	uQx=58_
58$Qx**3/K583F3Fs3Kr   c           
     >   | j                   j                  r| j                  j                  r| j                  j                  r| j                  j	                         }| j                  j	                         }| j                   j	                         }t        |      t        |      z  t        |      z  dk  rxg }t        |      D ]X  }t        |      D ]H  }t        |      D ]8  }| j                  j                  rdn|}|j                  t        |||             : J Z dt        |      z   dfS | j                   j                  rt        | j                  j                        dk(  r| j                  j                  r| j                  j                  d   }	|	j                  y|	j                  m|	j                  dk(  r^t        | j                   j                  |	j                        }
t        | j                   j                  |	j                        }d|
 d| d	fS t        | j                   j                        dk(  rt        | j                  j                        dk(  r| j                  j                  r| j                  j                  d   }|j                  | j                   j                  d   }|j                  ]|j                  Q|j                  dk(  rBt        |j                  d      }
t        |j                  d
      }| j                   d|
 d| d	fS y)a.  Apply formatting optimizations for hours and minutes.

        If both hours and minutes contain only a few single values, format them
        as "at HH:MM, HH:MM, HH:MM, and HH:MM"

        If hours have a single value, and minutes have a single sequence with step 1,
        format them as "every minute from HH:MM through HH:MM".

        If minutes have a single "*/<step>" sequence and hours have a sequence
        with step 1, format them as "every nth minute from HH:00 through HH:59"

        If no special optimizations apply, return None.
        r2   Nr   Tr   r   zevery minute from r   Fr   r   )r   r`   r   r)   r{   r#   sortedr[   rY   rD   r$   rZ   rW   r
   r   r   )r   second_termsminute_terms
hour_termstimesrA   rB   rC   ssrO   hhmm1hhmm2mseqhseqs                 r   optimized_timeszExpression.optimized_times  s     II!!'''';;..0L;;..0L**,J< 3|#44s:F!K
+ @A#L1 @!'!5 @A *.)9)9qB!LLQ2)>?	@@@ tE{*D00 99!!c$++*<*<&=&Bt{{GWGW++$$Q'Cyy$)=#((a-#DII$:$:CIIF#DII$:$:CHHE+E7)E7CUJJ 		  !Q&DKK&&'1,  ;;%%a(Dzz!yy''*::)dii.C		UV'

A6E'		26E"kk]&yH%OOr   c                t   | j                   j                  r!| j                  j                  dk(  rd| j                  j                          S | j                  j                  dk(  rd| j                  j                          S | j                  j                  rJ| j                  j                  r4d| j                  j                          d| j                  j                   S | j                  j                  r?t        | j                  j                        }d| d| j                  j                          S y	)
aV  Apply formatting optimizations for specific dates.

        If day-of-month is L, format it as
        "on the last day of <month description here>".

        If day-of-month is LW, format it as
        "on the last weekday of <month description here>".

        If month and day-of-month each have a single value
        (for example, month 2 and day-of-month 1), format them as
        "February 1st".

        If day-of-month has a single value (for example, 2),
        format it as "on the 2nd day of <month description here>".

        If no special optimizations apply, return None.
        r"   zon the last day of ri   zon the last weekday of r   r   zon the z day of N)r   r]   r   rZ   r   r   r=   )r   date_ords     r   optimized_dateszExpression.optimized_dates5  s    & 88==xx$$*,TZZ->->-@,ABBxx$$*01B1B1D0EFFzz&&488+@+@TZZ..014883H3H2IJJxx$$"488#8#89 
(4::3D3D3F2GHHr   c                   | j                   j                  r| j                  j                  r| j                  j                  ry| j                  j                  r| j                  j                  ry| j                  j                  r| j                   ddfS | j                  j
                  dk(  r| j                  j                  ry| j                  j                  r| j                   ddfS | j                         x}r|S | j                  j                  r| j                   d| j                    dfS | j                   d| j                   d| j                    dfS )	z+Convert the minute and hour fields to text.)zevery secondF)zevery minuteFz of every minuteFr   )zat the start of every hourFz of every hourr   )r   r]   r   r)   r[   rZ   r   )r   r   s     r   translate_timezExpression.translate_timeU  s   99>>{{DKK$4$4,{{DKK$4$4,{{++&67>>{{''1,1A1A:{{++n5u<<((**5*L;;kk]!DII;/66++a}Adii[95@@r   c                   | j                         x}r|S |rQ| j                  j                  r;| j                  j                  r%| j                  j
                  rd| j                   S g }| j                  j                  s|j                  | j                         | j                  j                  s| j                  j                  s| j                  r|j                  d       n3| j                  j                  s| j                  s|j                  d       |j                  | j                         | j                  j                  s|j                  | j                         dj                  d |D              S )z3Convert the day, month, and weekday fields to text.z
every day zif it'sandr   c              3  2   K   | ]  }t        |        y wrL   r}   )rN   parts     r   rP   z,Expression.translate_date.<locals>.<genexpr>  s     4dD	4s   )	r   r   r]   r   r   r`   rY   r   r$   )r   allow_every_daydatesr   s       r   translate_datezExpression.translate_datel  s    ((**5*Lxx}}4::3I3I#DJJ<00#%xx}}LL"xx}}88==T\\Y'XX]]4<<U#LL"zzLL$xx4e444r   c                    | j                         \  }}| j                  |      x}r| d| }n|r| d}n| }|d   j                         |dd z   S )z$Convert the full expression to text.r   z
 every dayr   r   N)r   r   upper)r   timer   dater   s        r   explainzExpression.explain  sm     $ 3 3 5o&&7747vQtf%FvZ(FvFay 6!":--r   N)r   rH   )r   ztuple[str, bool] | None)r   z
str | None)r   ztuple[str, bool])r   r   r   r~   r   )	r   r   r   ra   r   r   r   r   r   r   r   r   r   r     s$    
L:x@A.50
.r   r   c                p    | j                         j                         }t        |      j                         S )zConvert the given cron expression to human-friendly description.

    >>> explain("0 0 15 JAN-FEB *")
    'At 00:00 on the 15th day of January and February'
    )r   rk   r   r   )exprr   s     r   r   r     s,     JJL Ee$$&&r   __main__r!   r   )r%   rH   r   r~   )r<   r   r   r~   rL   )rA   r   rB   r   rC   r	   r   r~   )r   r~   r   r~   )
__future__r   collections.abcr   dataclassesr   r   r$   r:   r=   rD   rF   r   r   r   r   r   rm   r   r   r   sysr#   argvprintr   r   r   <module>r     s   " % ! $B B B"* 	%& i iXU BU B+5 +22)% 2)j)E )>:)e :)zb. b.J' z
388}gchhqk"#  r   