o
    .jy@                     @   s4  d Z ddlZddlmZ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mZ ddlmZmZ ejdg d	Zd
edefddZedd Zedd Zedd Zdd Zdd Zdd Zedd Zejdg dedddd fded!d"d#d fded!d"d#d$d%d fded!d"d#d$d&d fded!d"d#d$d'd'd fded(ddd)fded(ddddd)fded(dddd&d)fded(ddddd)fded(ddddd)fd*edddd+fd*ed,d-d#ddd+fd*ed,d-d#ddd+fd*ed,d-d#d.dd+fd*ed,d-d#d.d'd'd+fd*ed,d-d#d-dd/fd*ed,d-d#d-ddd/fd*ed,d-d#d0dd/fd*ed,d%d1ddd/fd*ed,d%d1ddd/fd*ed,d%d1d.dd/fd*ed,d%d1d.d2d/fd*ed,d%d1d.d'd'd/fd*ed,d%d1d-dd+fd*ed,d%d1d-ddd+fd*ed,d%d1d0dd+fd3edddd4fd3ed,d5d-ddd6fd3ed,d5d-ddd6fd3ed,d5d-dd'd'd6fd3ed,d5d-d.ddd4fd3ed,d5d-d-dd4fd3ed7d-d8ddd4fd3ed7d-d8dd'd'd4fd3ed7d-d8d.dd4fd3ed7d-d8d-dd6fd3ed7d-d8d-ddd6fd3ed7d-d8d0dd6fd9d: Zejd;g d<d=d> Zd?ed@edAefdBdCZ g dDZ!ejd?e!dEdF Z"dGdH Z#dIdJ Z$dKdL Z%dMdN Z&dOdP Z'dQdR Z(dSdT Z)ejdUd3dVgdWdX Z*dYdZ Z+ejd[g d\d]d^ Z,d_d` Z-dadb Z.dcdd Z/dedf Z0ejde1 dgdhh didj Z2dS )kaR  Generate VTIMEZONE components from actual timezone information.

When we generate VTIMEZONE from actual tzinfo instances of
- dateutil
- zoneinfo
- pytz

Then, we cannot assume that the future information stays the same but
we should be able to create tests that work for the past.

See https://github.com/collective/icalendar/issues/722
    N)datedatetime	timedelta)findall)gettz)Calendar	ComponentEventTimezone)tzid_from_tzinfotzids_from_tzinfotzid)Europe/BerlinAsia/SingaporeAmerica/New_Yorkc1c2c           	   	      s   d |     }|    }t fdd|D }d}t||ddD ]8\}}t|dkp5t|dk}t|d | d|t|  |d	 | d|t|  ||krUd
nd |||k7 }q&|rhJ | ddS )z!Print the diff of two components.    c                 3   s$    | ]}t | krt |V  qd S N)len).0lML f/home/thesage/.local/lib/python3.10/site-packages/icalendar/tests/test_issue_722_generate_vtimezone.py	<genexpr>'   s   " z*assert_components_equal.<locals>.<genexpr>r   F)strictz   z
->z	diff! z lines differN)to_icaldecode
splitlinesmaxzipr   print)	r   r   ll1ll2paddiffl1l2ar   r   r   assert_components_equal"   s    

r-   c                 C   s&  |   r	td | |}|dusJ t|}d|d< | }t|d}| }t|d}t|| t|| dt|j	|j
   krLdksOJ  J dt|j	|j
   kr`dkscJ  J t|t|ksmJ |  |  ks{J |j
|j
ksJ |j	|j	ksJ ||ksJ dS )zqtzinfo -> VTIMEZONE -> tzinfo -> VTIMEZONE

    We can assume that both generated VTIMEZONEs are equivalent.
    zGpytz will not converge on the first run. This is problematic. PYTZ-TODONztest-generatedTZID      )	uses_pytzpytestskiptimezoner
   from_tzinfoto_tzr-   r   standarddaylightdictr    r!   )tzpr   tzinfo1
generated1tzinfo2
generated2tzinfo3
generated3r   r   r   test_conversion_converges6   s,   



((rA   c                 C   sR   t j| |tdddd}|  t j| |tdddd}t|| ||ks'J dS )a  We want to make sure that we get the same info for all timezone implementations.

    We assume that
    - the timezone implementations have the same info within the days we test
    - the timezone transitions times do not change because they are before last_date
         )	last_dateN)r
   	from_tzidr   use_zoneinfor-   )r   r:   tz1tz2r   r   r    both_tzps_generate_the_same_infoW   s
   	
rI   c                 C   s$   t || }|d | ksJ dS )zCheck the TZID.r.   N)r
   r5   r4   )r   r:   tzr   r   r   test_tzid_matchesg   s   rK   c                 C   st   t d}|jg ksJ t|jdksJ |jd }|d jtdks%J |d jtdks0J |d dks8J dS )z1We do not need to convert UTC but it should work.UTCrC   r   TZOFFSETFROM
TZOFFSETTOTZNAMEN)r
   rE   r8   r   r7   tdr   )r:   utcr7   r   r   r   test_do_not_convert_utcn   s   

rR   c                 C   s  t d}|jD ]}t|j|d |d j|d j t|   qt|j	dks,J t|jdv s7J d|j	d }|jd }|d d	ksIJ |d d
ksQJ |d jt
ddks]J |d jt
ddksiJ |d jt
ddksuJ |d jt
ddksJ dS )z+Test the Europe/Berlin timezone conversion.r   rO   rM   rN   rC   )rC   r/   zWe start in winterCESTCET)hoursr/   N)r
   rE   r7   r%   namerP   r    r!   r   r8   r   )r:   rJ   xdststar   r   r   test_berlin_timey   s   

 

r[   c                     sp   t ddd t ddd fdd} tjd d}|j|j D ]}| |j |dg D ]}| | q.q!d S )	Ni  rC   rB   c                    s     |   krksJ  J d S r   r   )dt
first_daterD   r   r   check   s    z(test_range_is_not_crossed.<locals>.checkr   )rD   r^   RDATE)r   r
   rE   r7   r8   DTSTARTget)r_   rJ   subrdater   r]   r   test_range_is_not_crossed   s   

re   c                 C   sL   | | }|dusJ t|}| }t|t|ksJ ||ks$J dS )zVWhen we get the timezone again, usually, we should use the
    one of the library/tzp.N)r4   r
   r5   r6   type)r   r:   r;   r<   r=   r   r   r   test_use_the_original_timezone   s   

rg   )r   r\   tznamer   i  rC   z+0730i           
   "   ;   i  z+08r   rU   rB   r0   r/   rT            r   EST   EDTi  	   c           	      C   sL  | d| d| d}|  ||}t| |}|j| dd}|j|d}t| |  rv||}|t	ddd	d
dt	dddd
ddt	dddd
dt	dddddt	ddd	dddt	ddd	ddt	ddd	ddt	ddd	d
dfv rvt
d | |   kr|ksJ | J || | ksJ || | ksJ |dS )zWe should make sure than the datetimes with the generated timezones
    work as expected: They have the right UTC offset, dst and tzname.
    z: z (expected in )F)lookup_tzidtzinforB   rl   rp   rC   r   rs   r0   rn   r/   rq   z(We do not know how to do this. PYTZ-TODON)localizer
   r5   r4   r6   replacer%   r1   	normalizer   r2   r3   rh   rY   	utcoffset)	r:   r   r\   rh   messageexpected_dt	componentgenerated_tzinfogenerated_dtr   r   r   ,test_check_datetimes_around_transition_times   s,   4


,r   uid)r   rC   r/   r0   c                 C   s>   | j }|j| }t|d }|j }||ksJ |d dS )a  When going from Daylight Saving Time to Standard Time, times can be ambiguous.
    For example, at 3:00 AM, the time falls back to 2:00 AM, repeating a full hour of times from 2:00 AM to 3:00 AM on the same date.

    By the RFC 5545, we cannot accommodate this case. All datetimes should
    be BEFORE the transition if ambiguous. However, dateutil can
    create a timezone that allows the event to be after this ambiguous time span, of course.

    Each event has its timezone saved in it.
    zX-TZNAMESUMMARYN)'issue_722_timezone_transition_ambiguityeventsstrstartrh   )	calendarsr:   r   caleventexpected_tznameactual_tznamer   r   r   3test_dateutil_timezone_when_time_is_going_backwards   s
   

r   queryr   returnc              
   C   s<   zt | d|i}W t|S  ty } zt| |d}~ww )zThe tzid from the query.r   N)eval	Exception
ValueErrorr   )r   r   ry   er   r   r   
query_tzid  s   
r   )zcal.events[0].start.tzinfozcal.events[0].end.tzinfozcal.todos[0].end.tzinfoz.cal.events[0].get('RDATE').dts[0].dt[0].tzinfoz,cal.events[1].get('RECURRENCE-ID').dt.tzinfoz.cal.events[2].get('RDATE')[0].dts[0].dt.tzinfoz.cal.events[2].get('RDATE')[1].dts[0].dt.tzinfoc                 C   s(   | j }t||}| }||v sJ dS )z*Add the missing timezones to the calendar.N)issue_722_missing_timezonesr   get_missing_tzids)r   r   r   r   tzsr   r   r   %test_add_missing_timezones_to_example  s   
r   c                 C   sN   | j }t }tD ]}t||}t|d| || qt|ttks%J dS )zGWe make sure each query tests a unique place to find for the algorithm.z->N)r   setqueriesr   r%   addr   )r   r   tzidsr   r   r   r   r   test_queries_yield_unique_tzids%  s   
r   c                 C   sN   | j }|j }ttd|}| |ksJ dt|ttks%J ddS )z)Make sure all tzids are actually queried.zTZID=([a-zA-Z_/+-]+)z&We find all tzids and they are unique.zWe query all the tzids.N)r   raw_icsr!   r   r   get_used_tzidsr   r   )r   r   rawidsr   r   r   "test_we_do_not_miss_to_add_a_query0  s
   
r   c                 C   s*   | j }d| v sJ d| v sJ dS )z6If we have an unknown tzid with no timezone component.CUSTOM_tzidN)"issue_722_missing_VTIMEZONE_customr   r   r   r   r   r   r   test_unknown_tzid9     r   c                 C   s*   | j }d| v sJ d| vsJ dS )z3Check the custom timezone component is not missing.custom_America/New_YorkN)america_new_yorkr   r   r   r   r   r   &test_custom_timezone_is_found_and_used@  r   r   c                  C   s   t  } |  t ksJ dS )z"Check that no timezone is missing.N)r   r   r   )r   r   r   r   test_not_missing_anythingG  s   r   c                 C   s*   | j }d| vsJ d| vsJ dS )z UTC should not be found missing.rL   N)r   r   r   r   r   r   r   test_utc_is_not_missingM  r   r   c                 C   sJ   | j }|j|jd  | dhksJ dt|jd jjj	v s#J dS )zdateutil is an example of a timezone that has no tzid.

    In this test we make sure that the timezone is said to be missing.
    r   r   dateutilN)
r   subcomponentsremove	timezonesr   reprr   r   ry   	__class__)r   no_pytzr   r   r   r   /test_dateutil_timezone_is_not_found_with_tznameT  s    r   rh   zArctic/Longyearbyenc                 C   sl   t  }t }tdddt| d|_tt|jj || |	 | hks'J |
  |	 t ks4J dS )zdateutil is an example of a timezone that has no tzid.

    In this test we make sure that the timezone is matched by its
    tzname() in the timezone in the STANDARD and DAYLIGHT components.
    rB   rs   ri   rx   N)r   r	   r   r   r   r%   dirry   add_componentr   add_missing_timezonesr   )rh   r   r   r   r   r   -test_dateutil_timezone_is_matched_with_tzname_  s   
r   c                 C   s   dS )zpWe find and add a dateutil timezone.

    This is important as we use those in the zoneinfo implementation.
    Nr   )r   r   r   r   $test_dateutil_timezone_is_also_addedq  s    r   calendar)exampler   timezone_same_startperiod_with_timezonec                 C   sT   | | }|j dd }t | ksJ |  t | ks!J |j |ks(J dS )z4Check that these calendars have no timezone missing.N)r   r   r   r   )r   r   r   r   r   r   r   test_timezone_is_not_missingx  s   r   c                 C   sR   | j }t|jdksJ |  t|jttksJ dt| dks'J dS )zAdd all timezones specified.r   zall timezones are knownN)r   r   r   r   r   r   r   r   r   r    test_add_missing_known_timezones  s
   r   c                 C   sZ   | j }t|jdksJ | dhksJ |  |jg ks"J d| dhks+J dS )z(I cannot add a timezone that is unknown.r   r   zwe cannot add this timezoneN)r   r   r   r   r   r   r   r   r    test_cannot_add_unknown_timezone  s   r   c                   C   s:   t t td W d    d S 1 sw   Y  d S )Nzinvalid/tzid)r2   raisesr   r
   rE   r   r   r   r   2test_cannot_create_a_timezone_from_an_invalid_tzid  s   "r   c                   C   s   t d dS )zWhen we add the timezones, we should check the calendar to see
    if all dates really occur in the span we use.

    We should also consider a huge default range.
    todoN)r2   r3   r   r   r   r   *test_dates_before_and_after_are_considered  s   r   Factory	localtimec                 C   s(   t | }|du s| t|v sJ dS dS )zxdateutil and others were badly supported.

    But if we know their shortcodes, we should be able to identify them.
    N)r   r   )r   rJ   r   r   r   'test_we_can_identify_dateutil_timezones  s    r   )3__doc__zoneinfor   r   r   rer   r2   dateutil.tzr   	icalendarr   r   r	   r
   icalendar.timezoner   r   markparametrizer   r-   rA   rI   rK   rR   r[   re   rg   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   available_timezonesr   r   r   r   r   <module>   s   

 


	
 #$%&')*+
0

	

	
	
	