U
    j@                  /   @   s  d Z ddlmZmZmZ ddlmZ ddlZddlmZ zddl	m
Z
 W n  ek
rh   ddlm
Z
 Y nX ddlmZmZmZmZ ddlmZmZ ejd	d
ddgZeed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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dedd d d3fded,d4d-ddd5fded,d4d-d dd5fded,d4d-d d(d(d5fded,d4d-d.dd d3fded,d4d-d-dd3fded6d-d7d dd3fded6d-d7d d(d(d3fded6d-d7d.dd3fded6d-d7d-dd5fded6d-d7d-d d d5fded6d-d7d0dd5fg&d8d9 Z ejd:dd d.d-gd;d< Z!e"ee"d=d>d?Z#d@dAdBdCdDdEdFgZ$ejdGe$dHdI Z%dJdK Z&dLdM Z'dNdO Z(dPdQ Z)dRdS Z*dTdU Z+dVdW Z,ejdXddYgdZd[ Z-d\d] Z.ejd^d_d`dadbgdcdd Z/dedf Z0dgdh Z1didj Z2dkdl Z3ejd	e
 dmdnh dodp Z4dS )qa  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.
    )datedatetime	timedelta)findallN)gettz)available_timezones)Calendar	ComponentEventTimezone)tzid_from_tzinfotzids_from_tzinfotzidEurope/BerlinzAsia/SingaporezAmerica/New_York)c1c2c           	   	      s   d |     }|    }t fdd|D }d}t||D ]p\}}t|dkpft|dk}t|d | d|t|  |d | d|t|  ||krdnd	 |||k7 }qH|rt| 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ZML U/tmp/pip-unpacked-wheel-g40nyxg1/icalendar/tests/test_issue_722_generate_vtimezone.py	<genexpr>)   s      z*assert_components_equal.<locals>.<genexpr>r   z   z
->z	diff! z lines differN)to_icaldecode
splitlinesmaxzipr   printAssertionError)	r   r   Zll1Zll2padZdiffl1l2ar   r   r   assert_components_equal$   s     

r(   c                 C   s(  |   rtd | |}|dk	s(tt|}d|d< | }t|d}| }t|d}t|| t|| dt	|j
|j   krdksn tdt	|j
|j   krdksn tt|t|kst|  |  kst|j|jkst|j
|j
kst||ks$t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#   r   from_tzinfoto_tzr(   r   standarddaylightdictr   r   )tzpr   tzinfo1
generated1tzinfo2Z
generated2Ztzinfo3Z
generated3r   r   r   test_conversion_converges8   s,    



&&r9   c                 C   sR   t j| |tdddd}|  t j| |tdddd}t|| ||ksNt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   Zuse_zoneinfor(   r#   )r   r5   Ztz1Ztz2r   r   r    both_tzps_generate_the_same_infoY   s
    	
r>   c                 C   s$   t || }|d | ks tdS )zCheck the TZID.r)   N)r   r0   r/   r#   )r   r5   tzr   r   r   test_tzid_matchesi   s    r@   c                 C   st   t d}|jg kstt|jdks*t|jd }|d jtdksJt|d jtdks`t|d dksptdS )z1We do not need to convert UTC but it should work.UTCr;   r   TZOFFSETFROM
TZOFFSETTOTZNAMEN)r   r=   r3   r#   r   r2   tdr   )r5   utcr2   r   r   r   test_do_not_convert_utcp   s    

rG   c                 C   s  t d}|jD ]4}t|j|d |d j|d j t|   qt|j	dksXt
t|jdksnt
d|j	d }|jd }|d d	kst
|d d
kst
|d jtddkst
|d jtddkst
|d jtddkst
|d jtddkst
dS )z+Test the Europe/Berlin timezone conversion.r   rD   rB   rC   r;   )r;   r*   zWe start in winterCESTCET)hoursr*   N)r   r=   r2   r"   namerE   r   r   r   r3   r#   r   )r5   r?   xdstZstar   r   r   test_berlin_time{   s    

 

rO   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\qBd S )	Ni  r;   r:   c                    s    |   krksn t d S r   )r#   )dt
first_dater<   r   r   check   s    z(test_range_is_not_crossed.<locals>.checkr   )r<   rR   ZRDATE)r   r   r=   r2   r3   ZDTSTARTget)rS   r?   subZrdater   rQ   r   test_range_is_not_crossed   s    
rV   c                 C   sL   | | }|dk	stt|}| }t|t|ks<t||ksHtdS )zVWhen we get the timezone again, usually, we should use the
    one of the library/tzp.N)r/   r#   r   r0   r1   type)r   r5   r6   r7   r8   r   r   r   test_use_the_original_timezone   s    

rX   )r   rP   tznamei  r;   z+0730i           
   "   ;   i  z+08rJ   r:   r+   r*   rI            EST   EDTi  	   c           	      C   sN  | d| d| d}|  ||}t| |}|j| dd}|j|d}t| |  r||}|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krt
d | |   kr|ksn t|| | ks0t|| | ksJt|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)Zlookup_tzidtzinfor:   r]   ra   r;   r   rd   r+   r_   r*   rb   z(We do not know how to do this. PYTZ-TODON)Zlocalizer   r0   r/   r1   replacer"   r,   	normalizer   r-   r.   rY   r#   rN   	utcoffset)	r5   r   rP   rY   messageZexpected_dt	componentZgenerated_tzinfoZgenerated_dtr   r   r   ,test_check_datetimes_around_transition_times   s,    4


*ro   uidc                 C   s>   | j }|j| }t|d }|j }||ks:t|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-TZNAMEZSUMMARYN)Z'issue_722_timezone_transition_ambiguityeventsstrstartrY   r#   )	calendarsr5   rp   caleventZexpected_tznameZactual_tznamer   r   r   3test_dateutil_timezone_when_time_is_going_backwards   s
    

rw   )queryru   returnc              
   C   sH   zt | d|i}W n, tk
r> } zt| |W 5 d}~X Y nX t|S )zThe tzid from the query.ru   N)eval	Exception
ValueErrorr   )rx   ru   ri   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.tzinforx   c                 C   s(   | j }t||}| }||ks$tdS )z*Add the missing timezones to the calendar.N)issue_722_missing_timezonesr~   get_missing_tzidsr#   )rt   rx   ru   r   Z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sJtdS )zGWe make sure each query tests a unique place to find for the algorithm.z->N)r   setqueriesr~   r"   addr   r#   )rt   ru   tzidsrx   r   r   r   r   test_queries_yield_unique_tzids'  s    
r   c                 C   sN   | j }|j }ttd|}| |ks2tdt|ttksJt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   Zraw_icsr   r   r   get_used_tzidsr#   r   r   )rt   ru   rawidsr   r   r   "test_we_do_not_miss_to_add_a_query2  s
    
r   c                 C   s*   | j }d| kstd| ks&tdS )z6If we have an unknown tzid with no timezone component.CUSTOM_tzidN)"issue_722_missing_VTIMEZONE_customr   r#   r   rt   ru   r   r   r   test_unknown_tzid;  s    r   c                 C   s*   | j }d| kstd| ks&tdS )z3Check the custom timezone component is not missing.custom_America/New_YorkN)america_new_yorkr   r#   r   r   r   r   r   &test_custom_timezone_is_found_and_usedB  s    r   c                  C   s   t  } |  t kstdS )z"Check that no timezone is missing.N)r   r   r   r#   )ru   r   r   r   test_not_missing_anythingI  s    r   c                 C   s*   | j }d| kstd| ks&tdS )z UTC should not be found missing.rA   N)r   r   r#   r   r   r   r   r   test_utc_is_not_missingO  s    r   c                 C   sJ   | j }|j|jd  | dhks*tdt|jd jj	j
ksFt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   ZdateutilN)r   Zsubcomponentsremove	timezonesr   r#   reprrq   rs   ri   	__class__)rt   Zno_pytzru   r   r   r   /test_dateutil_timezone_is_not_found_with_tznameV  s    r   rY   zArctic/Longyearbyenc                 C   sl   t  }t }tdddt| d|_tt|jj || |	 | hksNt
|  |	 t ksht
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.
    r:   rd   rZ   rh   N)r   r
   r   r   rs   r"   dirri   Zadd_componentr   r#   add_missing_timezonesr   )rY   ru   rv   r   r   r   -test_dateutil_timezone_is_matched_with_tznamea  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   )rt   r   r   r   $test_dateutil_timezone_is_also_addeds  s    r   calendarZexampler   Ztimezone_same_startZperiod_with_timezonec                 C   sT   | | }|j dd }t | ks(t|  t | ksBt|j |ksPtdS )z4Check that these calendars have no timezone missing.N)r   r   r   r#   r   )rt   r   ru   r   r   r   r   test_timezone_is_not_missingz  s    r   c                 C   sR   | j }t|jdkst|  t|jttks:tdt| dksNtdS )zAdd all timezones specified.r   zall timezones are knownN)r   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t| dhks*t|  |jg ksDtd| dhksVt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   r    test_cannot_add_unknown_timezone  s    r   c                	   C   s$   t t td W 5 Q R X d S )Nzinvalid/tzid)r-   Zraisesr|   r   r=   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)r-   r.   r   r   r   r   *test_dates_before_and_after_are_considered  s    r   ZFactory	localtimec                 C   s$   t | }|dks | t|ks t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#   )r   r?   r   r   r   'test_we_can_identify_dateutil_timezones  s    r   )5__doc__r   r   r   rer   r-   Zdateutil.tzr   Zzoneinfor   ImportErrorZbackports.zoneinfoZ	icalendarr   r	   r
   r   Zicalendar.timezoner   r   markZparametrizer   r(   r9   r>   r@   rG   rO   rV   rX   ro   rw   rr   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   s   

 


0


	
	

	
	