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r¦dnd	ƒ |||k7 }qH|rÌt|› 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r–dksœn t‚dt	|j
|j ƒ  kr¼dksÂn t‚t|ƒt|ƒksÖt‚| ¡  ¡ | ¡  ¡ ksòt‚|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s’t
‚|d d
ks¢t
‚|d jtdd�ksºt
‚|d jtdd�ksÒt
‚|d jtdd�ksêt
‚|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rìt
 d¡ | ¡ | ¡   k�r|k�sn t|ƒ‚| ¡ | ¡ k�s0t|ƒ‚| ¡ | ¡ k�sJt|ƒ‚dS )zŽWe 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 )zƒdateutil 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 )zÄdateutil 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 )z¨When 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

ø
	
üþ	

	
	