U
    Tr­`pe  ã                   @   s  d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dl	Z	d dl
Z
d dlZd dlmZ d dlmZ d dlmZ d dlZddlmZ ddlmZ ddlmZ dd	gZdZd
Zd
Zd eee¡ZG dd„ deƒZ G dd„ deƒZ!G dd„ dƒZ"dd„ Z#dS )é    N)ÚStringIO)Úc_inté   )Úutils)ÚControlThread)ÚdownloadÚSmartDLr   é   z{}.{}.{}c                   @   s(   e Zd ZdZdd„ Zdd„ Zdd„ ZdS )	ÚHashFailedExceptionzRaised when hash check fails.c                 C   s   || _ || _|| _d S ©N)ÚfilenameÚcalculated_hashÚneeded_hash)ÚselfÚfnZ	calc_hashr   © r   úJ/mnt/cestravail/FreezeDetection/sentSatProg_v.0.1.3/pySmartDL/pySmartDL.pyÚ__init__   s    zHashFailedException.__init__c                 C   s   d  | j| j| j¡S )Nz,HashFailedException({}, got {}, expected {})©Úformatr   r   r   ©r   r   r   r   Ú__str__   s    zHashFailedException.__str__c                 C   s   d  | j| j| j¡S )Nz-<HashFailedException {}, got {}, expected {}>r   r   r   r   r   Ú__repr__!   s    zHashFailedException.__repr__N©Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   r   r   r   r   r
      s   r
   c                   @   s(   e Zd ZdZdd„ Zdd„ Zdd„ ZdS )	ÚCanceledExceptionz Raised when the job is canceled.c                 C   s   d S r   r   r   r   r   r   r   &   s    zCanceledException.__init__c                 C   s   dS )Nr   r   r   r   r   r   r   (   s    zCanceledException.__str__c                 C   s   dS )Nz<CanceledException>r   r   r   r   r   r   *   s    zCanceledException.__repr__Nr   r   r   r   r   r   $   s   r   c                   @   s   e Zd ZdZdIdd„Zd	d
„ Zdd„ Zdd„ Zdd„ Zdd„ Z	dJdd„Z
dd„ ZdKdd„ZdLdd„ZdMdd„ZdNdd„Zd d!„ ZdOd$d%„Zd&d'„ Zd(d)„ Zd*d+„ Zd,d-„ ZdPd.d/„Zd0d1„ Zd2d3„ Zd4d5„ Zd6d7„ Zd8d9„ Zd:d;„ ZdQd<d=„ZdRd>d?„ZdSd@dA„ZdTdCdD„Z dEdF„ Z!dGdH„ Z"dS )Ur   am  
    The main SmartDL class
    
    :param urls: Download url. It is possible to pass unsafe and unicode characters. You can also pass a list of urls, and those will be used as mirrors.
    :type urls: string or list of strings
    :param dest: Destination path. Default is `%TEMP%/pySmartDL/`.
    :type dest: string
    :param progress_bar: If True, prints a progress bar to the `stdout stream <http://docs.python.org/2/library/sys.html#sys.stdout>`_. Default is `True`.
    :type progress_bar: bool
	:param fix_urls: If true, attempts to fix urls with unsafe characters.
	:type fix_urls: bool
	:param threads: Number of threads to use.
	:type threads: int
    :param timeout: Timeout for network operations, in seconds. Default is 5.
	:type timeout: int
    :param logger: An optional logger.
    :type logger: `logging.Logger` instance
    :param connect_default_logger: If true, connects a default logger to the class.
    :type connect_default_logger: bool
    :param request_args: Arguments to be passed to a new urllib.request.Request instance in dictionary form. See `urllib.request docs <https://docs.python.org/3/library/urllib.request.html#urllib.request.Request>`_ for options. 
    :type request_args: dict
    :rtype: `SmartDL` instance
    
    .. NOTE::
            The provided dest may be a folder or a full path name (including filename). The workflow is:
            
            * If the path exists, and it's an existing folder, the file will be downloaded to there with the original filename.
            * If the past does not exist, it will create the folders, if needed, and refer to the last section of the path as the filename.
            * If you want to download to folder that does not exist at the moment, and want the module to fill in the filename, make sure the path ends with `os.sep`.
            * If no path is provided, `%TEMP%/pySmartDL/` will be used.
    NTé   é   Fc                 C   s  |r|| _ n|rt ¡ | _ n
t ¡ | _ |	rDd|	kr<tƒ |	d< |	| _ndtƒ i| _d| jd krld| jd d< |r€|r€|  ||¡ t|tƒr|gn|| _	|r¬dd„ | j	D ƒ| _	| j	 
d¡| _| j  d | j¡¡ tj tj tj | j¡j¡¡}|ptj t ¡ d|¡| _| jd	 tjkrntj | jd d	… ¡r`tj | jd d	… ¡r`t | jd d	… ¡ |  j|7  _tj | j¡rtj | j|¡| _|| _|| _|| _ d
| _!d| _"d| _#d| _$t% &t'd¡| _(i | _)d| _*d| _+d| _,d| _-d| _.g | _/|| _0|
| _1d | _2d | _3tj tj 4| j¡¡sR| j  d tj 4| j¡¡¡ t 5tj 4| j¡¡ tj6| j| j| j ds|| j  7d¡ d
| _tj | j¡r | j  7d | j¡¡ tj tj 4| j¡¡sè| j  7d tj 4| j¡¡¡ t 5tj 4| j¡¡ | j  d | j¡¡ t 8| j¡| _9d S )NÚheadersz
User-AgentzNMozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0c                 S   s   g | ]}t  |¡‘qS r   )r   Zurl_fix©Ú.0Úxr   r   r   Ú
<listcomp>c   s     z$SmartDL.__init__.<locals>.<listcomp>r   úUsing url "{}"Ú	pySmartDLéÿÿÿÿr   é   i    ÚreadyFTz'Folder "{}" does not exist. Creating...)r!   Útimeoutz=Server does not support HTTPRange. threads_count is set to 1.z?Destination "{}" already exists. Existing file will be removed.z-Directory "{}" does not exist. Creating it...z&Creating a ThreadPool of {} thread(s).):Úloggerr   Zcreate_debugging_loggerZDummyLoggerÚdictÚrequestArgsÚadd_basic_authenticationÚ
isinstanceÚstrÚmirrorsÚpopÚurlÚinfor   ÚurllibÚparseÚunquoteÚosÚpathÚbasenameÚurlparseÚjoinÚtempfileÚ
gettempdirÚdestÚsepÚexistsÚisfileÚunlinkÚisdirÚprogress_barÚthreads_countr+   Úcurrent_attempÚattemps_limitÚminChunkFileÚfilesizeÚmultiprocessingÚValuer   Ú
shared_varÚthread_shared_cmdsÚstatusÚverify_hashÚ_killedÚ_failedÚ_start_func_blockingÚerrorsÚhash_algorithmÚ	hash_codeÚpost_threadpool_threadÚcontrol_threadÚdirnameÚmakedirsZauto_detect_HTTPRange_supportÚwarningZManagedThreadPoolExecutorÚpool)r   Zurlsr@   rF   Zfix_urlsÚthreadsr+   r,   Zconnect_default_loggerZrequest_argsZhash_checksumZ	hash_algoÚusernameÚpasswordr   r   r   r   r   N   sv    

 0zSmartDL.__init__c                 C   s   d  | j| j¡S )NzSmartDL(r"{}", dest=r"{}"))r   r4   r@   r   r   r   r   r   ”   s    zSmartDL.__str__c                 C   s   d  | j¡S )Nz<SmartDL {}>)r   r4   r   r   r   r   r   —   s    zSmartDL.__repr__c                 C   s2   d  ||¡}t | d¡¡}d| | jd d< dS )zØ
        Uses HTTP Basic Access authentication for the connection.
        
        :param username: Username.
        :type username: string
        :param password: Password.
        :type password: string
        z{}:{}zutf-8s   Basic r!   ÚAuthorizationN)r   Úbase64Ústandard_b64encodeÚencoder.   )r   r_   r`   Zauth_stringZbase64stringr   r   r   r/   š   s    	z SmartDL.add_basic_authenticationc                 C   s   d| _ || _|| _dS )aÒ  
        Adds hash verification to the download.
        
        If hash is not correct, will try different mirrors. If all mirrors aren't
        passing hash verification, `HashFailedException` Exception will be raised.
        
        .. NOTE::
            If downloaded file already exist on the destination, and hash matches, pySmartDL will not download it again.
            
        .. WARNING::
            The hashing algorithm must be supported on your system, as documented at `hashlib documentation page <http://docs.python.org/3/library/hashlib.html>`_.
        
        :param algorithm: Hashing algorithm.
        :type algorithm: string
        :param hash: Hash code.
        :type hash: string
        TN)rQ   rV   rW   )r   Ú	algorithmÚhashr   r   r   Úadd_hash_verification§   s    zSmartDL.add_hash_verificationc              	   C   sú   dddg}t j | j¡}t j | j¡}| j d¡ |D ]¾}zœd||f }tjj	|f| j
Ž}tj |¡}| ¡  d¡}| ¡  |D ]R}	| ¡ |	 ¡ kr€| j d| ¡ | d¡}
|	 d	¡d
 }|  |
|¡  W  dS q€W q6 tjjk
rò   Y q6Y q6X q6dS )a4  
        Will attempt to fetch UNIX hash sums files (`SHA256SUMS`, `SHA1SUMS` or `MD5SUMS` files in
        the same url directory).
        
        Calls `self.add_hash_verification` if successful. Returns if a matching hash was found.
        
        :rtype: bool
        
        *New in 1.2.1*
        Z
SHA256SUMSZSHA1SUMSZMD5SUMSzLooking for SUMS files...z%s/%sÚ
zFound a matching hash in %sZSUMSú r   N)r9   r:   rZ   r4   r;   r,   r5   r6   ÚrequestÚRequestr.   ÚurlopenÚreadÚsplitÚcloseÚlowerÚrstriprg   ÚerrorÚ	HTTPError)r   Zdefault_sums_filenamesÚfolderZorig_basenamer   Zsums_urlZsumsRequestÚobjÚdataÚlineZalgorf   r   r   r   Úfetch_hash_sums¾   s(    

zSmartDL.fetch_hash_sumsc           	         sX  ˆ j dkstd ˆ j ¡ƒ‚ˆ j d¡ |dkr6ˆ j}n|ˆ _ˆ jr\ˆ j d tˆ jƒ¡¡ nˆ j d¡ ˆ jdk	rºt	j
 ˆ j¡rºt ˆ jˆ j¡ ¡ ˆ j ¡ krºˆ j dˆ j ¡ dˆ _ dS ˆ j d	 ˆ jˆ j¡¡ tjjˆ jfˆ jŽ}ztjj|ˆ jd
}W n¾ tjjtjjtjfk
rº } zŽˆ j |¡ ˆ jr€ˆ j d t|ƒ¡¡ ˆ j d¡ˆ _ˆ j d ˆ j¡¡ ˆ   |¡ W Y ¢2dS ˆ j !t|ƒ¡ ˆ j |¡ dˆ _"dˆ _ ‚ W 5 d}~X Y nX z2t#|j$d ƒˆ _%ˆ j d ˆ j%t &ˆ j%¡¡¡ W n. t't(t)fk
r   ˆ j !d¡ dˆ _%Y nX t *ˆ j%ˆ j+ˆ j,¡}|d d |d d  d }t|ƒdkr|ˆ j d t|ƒt &|¡¡¡ nˆ j d t &|¡¡¡ dˆ _ t-|ƒD ]J\}}ˆ j. /t0ˆ jˆ jd|  ˆ j|d |d ˆ jdˆ j1ˆ j2ˆ jd¡}q¢t3j4t5ˆ j.‡ fdd„t6t|ƒƒD ƒˆ jgˆ j%ˆ fdˆ _7dˆ j7_8ˆ j7  ¡  t9ˆ ƒˆ _:|rTˆ j;dd dS )a,  
        Starts the download task. Will raise `RuntimeError` if it's the object's already downloading.
        
        .. warning::
            If you're using the non-blocking mode, Exceptions won't be raised. In that case, call
            `isSuccessful()` after the task is finished, to make sure the download succeeded. Call
            `get_errors()` to get the the exceptions.
        
        :param blocking: If true, calling this function will block the thread until the download finished. Default is *True*.
        :type blocking: bool
        r*   z#cannot start (current status is {})z!Starting a new SmartDL operation.Nz"One URL and {} mirrors are loaded.zOne URL is loaded.zKDestination '%s' already exists, and the hash matches. No need to download.ÚfinishedzDownloading '{}' to '{}'...)r+   z{} Trying next mirror...r   r&   TzContent-LengthzContent-Length is {} ({}).z8Server did not send Content-Length. Filesize is unknown.r   z+Launching {} threads (downloads {}/thread).z"Launching 1 thread (downloads {}).Údownloadingú.%.3dFc                    s   g | ]}ˆ j d |  ‘qS )r{   ©r@   )r#   Úir   r   r   r%   8  s     z!SmartDL.start.<locals>.<listcomp>)ÚtargetÚargs)Úraise_exceptions)<rP   ÚRuntimeErrorr   r,   r5   rT   r2   ÚlenrW   r9   r:   rB   r@   r   Úget_file_hashrV   rp   r4   r6   rj   rk   r.   rl   r+   rr   rs   ÚURLErrorÚsocketrU   Úappendr1   r3   Ústartr\   rS   Úintr!   rK   Úsizeof_humanÚ
IndexErrorÚKeyErrorÚ	TypeErrorZcalc_chunk_sizerG   rJ   Ú	enumerater]   Úsubmitr   rN   rO   Ú	threadingÚThreadÚpost_threadpool_actionsÚrangerX   Údaemonr   rY   Úwait)	r   ÚblockingÚreqZurlObjÚer   Zbytes_per_threadr}   Úargr   r   r   r‡   á   sŽ    
"

" ôüþ	

zSmartDL.startc                 C   s$   | j  |d ¡ | j |d ¡ d S )Nr   r   )rU   r†   r,   Ú	exception)r   r–   r—   r   r   r   Ú_exc_callbackE  s    zSmartDL._exc_callbackÚ c              	   C   sx   | j | jk r8|  j d7  _ d| _d| j_i | _|  ¡  n<d}|rN|d |¡7 }| j 	t
j | jd|i tƒ ¡¡ d| _d S )Nr   r*   r   z"The maximum retry attempts reachedz ({})Ú0T)rH   rI   rP   rN   ÚvaluerO   r‡   r   rU   r†   r6   rr   rs   r4   r   rS   )r   ZeStrÚsr   r   r   ÚretryI  s    
 zSmartDL.retryc                 C   sf   | j rP|r| j |¡ d| _d| j_| j  d¡| _| j 	d 
| j¡¡ |  ¡  nd| _| j |¡ d S )Nr*   r   r&   T)r2   rU   r†   rP   rN   r   r3   r4   r,   r5   r   r‡   rS   )r   r—   r   r   r   Útry_next_mirrorX  s    
zSmartDL.try_next_mirrorc                 C   s*   |r t  | j ¡ ¡}|r|S dS | j ¡ S )aŒ  
        Get estimated time of download completion, in seconds. Returns `0` if there is
        no enough data to calculate the estimated time (this will happen on the approx.
        first 5 seconds of each download).
        
        :param human: If true, returns a human-readable formatted string. Else, returns an int type number
        :type human: bool
        :rtype: int/string
        ZTBD)r   Ú
time_humanrY   Úget_eta)r   Úhumanrž   r   r   r   r¢   e  s    
zSmartDL.get_etac                 C   s$   |rd  t | j ¡ ¡¡S | j ¡ S )zê
        Get current transfer speed in bytes per second.
        
        :param human: If true, returns a human-readable formatted string. Else, returns an int type number
        :type human: bool
        :rtype: int/string
        z{}/s)r   r   r‰   rY   Ú	get_speed©r   r£   r   r   r   r¤   t  s    zSmartDL.get_speedc                 C   s2   | j s
dS | j ¡ | j kr.d| j ¡  | j  S dS )z~
        Returns the current progress of the download, as a float between `0` and `1`.
        
        :rtype: float
        r   g      ð?)rK   rY   Úget_dl_sizer   r   r   r   Úget_progress€  s
    zSmartDL.get_progress©ú-ú#é   c                 C   s   t  |  ¡ ||¡S )a[  
        Returns the current progress of the download as a string containing a progress bar.
        
        .. NOTE::
            That's an alias for pySmartDL.utils.progress_bar(obj.get_progress()).
        
        :param length: The length of the progress bar in chars. Default is 20.
        :type length: int
        :rtype: string
        )r   rF   r§   )r   Z	look_feelÚlengthr   r   r   Úget_progress_barŒ  s    zSmartDL.get_progress_barc                 C   s(   | j dkrdS | j dkrdS | j ¡  S )zP
        Returns if the task is finished.
        
        :rtype: bool
        r*   Fry   T)rP   rX   Úis_aliver   r   r   r   Ú
isFinished™  s
    

zSmartDL.isFinishedc                 C   sL   | j r
dS d}| jdkrD|d7 }t d¡ |dkrtd | j¡ƒ‚q| j S )aÙ  
        Returns if the download is successfull. It may fail in the following scenarios:
        
        - Hash check is enabled and fails.
        - All mirrors are down.
        - Any local I/O problems (such as `no disk space available`).
        
        .. NOTE::
            Call `get_errors()` to get the exceptions, if any.
        
        Will raise `RuntimeError` if it's called when the download task is not finished yet.
        
        :rtype: bool
        Fr   ry   r   çš™™™™™¹?é   z]The download task must be finished in order to see if it's successful. (current status is {}))rR   rP   ÚtimeÚsleepr   r   rS   )r   Únr   r   r   ÚisSuccessful¥  s    

zSmartDL.isSuccessfulc                 C   s   | j S )zo
        Get errors happened while downloading.
        
        :rtype: list of `Exception` instances
        )rU   r   r   r   r   Ú
get_errorsÁ  s    zSmartDL.get_errorsc                 C   s   | j S )z­
        Returns the current status of the task. Possible values: *ready*,
        *downloading*, *paused*, *combining*, *finished*.
        
        :rtype: string
        )rP   r   r   r   r   Ú
get_statusÉ  s    zSmartDL.get_statusc                 C   sN   | j dkrdS |  ¡ s"t d¡ q| j ¡  | j ¡  | jrJ|rJ| jd ‚dS )zÉ
        Blocks until the download is finished.
        
        :param raise_exceptions: If true, this function will raise exceptions. Default is *False*.
        :type raise_exceptions: bool
        )r*   ry   Nr°   r(   )	rP   r¯   r²   r³   rX   r=   rY   rS   rU   )r   r€   r   r   r   r”   Ò  s    



zSmartDL.waitc                 C   s   | j dkrd| jd< d| _dS )z%
        Stops the download.
        rz   r›   ÚstopTN)rP   rO   rR   r   r   r   r   r¸   ä  s    

zSmartDL.stopc                 C   s   | j dkrd| _ d| jd< dS )z&
        Pauses the download.
        rz   Úpausedr›   ÚpauseN©rP   rO   r   r   r   r   rº   ì  s    
zSmartDL.pausec                 C   s   |   ¡  dS )z<
        Continues the download. same as unpause().
        N)Úunpauser   r   r   r   Úresumeô  s    zSmartDL.resumec                 C   s&   | j dkr"d| jkr"d| _ | jd= dS )z;
        Continues the download. same as resume().
        r¹   rº   rz   Nr»   r   r   r   r   r¼   ú  s    zSmartDL.unpausec                 C   sT   | j dkr$|dkr|  ¡  n|  ¡  |dkr>|| j | jd< nd| jkrP| jd= dS )zÐ
        Limits the download transfer speed.
        
        :param speed: Speed in bytes per download per second. Negative values will not limit the speed. Default is `-1`.
        :type speed: int
        rz   r   ÚlimitN)rP   rº   r¼   rG   rO   )r   Úspeedr   r   r   Úlimit_speed  s    


zSmartDL.limit_speedc                 C   s   | j S )z¼
        Get the destination path of the downloaded file. Needed when no
        destination is provided to the class, and exists on a temp folder.
        
        :rtype: string
        r|   r   r   r   r   Úget_dest  s    zSmartDL.get_destc                 C   s(   | j s
dS |rt | j  ¡ ¡S | j  ¡ S )a*  
        Returns how much time did the download take, in seconds. Returns
        `-1` if the download task is not finished yet.

        :param human: If true, returns a human-readable formatted string. Else, returns an int type number
        :type human: bool
        :rtype: int/string
        r   )rY   r   r¡   Úget_dl_timer¥   r   r   r   rÂ     s
    	zSmartDL.get_dl_timec                 C   s(   | j s
dS |rt | j  ¡ ¡S | j  ¡ S )zá
        Get downloaded bytes counter in bytes.
        
        :param human: If true, returns a human-readable formatted string. Else, returns an int type number
        :type human: bool
        :rtype: int/string
        r   )rY   r   r‰   r¦   r¥   r   r   r   r¦   +  s
    zSmartDL.get_dl_sizec                 C   s(   | j s
dS |rt | j  ¡ ¡S | j  ¡ S )zÜ
        Get total download size in bytes.
        
        :param human: If true, returns a human-readable formatted string. Else, returns an int type number
        :type human: bool
        :rtype: int/string
        r   )rY   r   r‰   Úget_final_filesizer¥   r   r   r   rÃ   9  s
    zSmartDL.get_final_filesizer(   c              	   C   s\   | j dkrtd| j  ƒ‚|r dnd}t|  ¡ |ƒ }|dkrF| |¡n| ¡ }W 5 Q R X |S )až  
        Returns the downloaded data. Will raise `RuntimeError` if it's
        called when the download task is not finished yet.
        
        :param binary: If true, will read the data as binary. Else, will read it as text.
        :type binary: bool
        :param bytes: Number of bytes to read. Negative values will read until EOF. Default is `-1`.
        :type bytes: int
        :rtype: string
        ry   zTThe download task must be finished in order to read the data. (current status is %s)ÚrbÚrr   )rP   r   ÚopenrÁ   rm   )r   ÚbinaryÚbytesÚflagsÚfrv   r   r   r   Úget_dataH  s    
$zSmartDL.get_datac                 C   s   t  || jdd¡ ¡ S )a¿  
        Returns the downloaded data's hash. Will raise `RuntimeError` if it's
        called when the download task is not finished yet.
        
        :param algorithm: Hashing algorithm.
        :type algorithm: bool
        :rtype: string
        
        .. WARNING::
            The hashing algorithm must be supported on your system, as documented at `hashlib documentation page <http://docs.python.org/3/library/hashlib.html>`_.
        T)rÇ   )ÚhashlibÚnewrË   Ú	hexdigest)r   re   r   r   r   Úget_data_hash[  s    zSmartDL.get_data_hashc                 C   s   |   ¡ }t |¡S )a  
        Returns the JSON in the downloaded data. Will raise `RuntimeError` if it's
        called when the download task is not finished yet. Will raise `json.decoder.JSONDecodeError`
        if the downloaded data is not valid JSON.
        
        :rtype: dict
        )rË   ÚjsonÚloads)r   rv   r   r   r   Úget_jsoni  s    zSmartDL.get_json)NTTr   r    NFNNNNN)N)r›   )N)F)F)r¨   r«   )F)F)F)F)Fr(   )#r   r   r   r   r   r   r   r/   rg   rx   r‡   rš   rŸ   r    r¢   r¤   r§   r­   r¯   rµ   r¶   r·   r”   r¸   rº   r½   r¼   rÀ   rÁ   rÂ   r¦   rÃ   rË   rÏ   rÒ   r   r   r   r   r   -   s@    
F#
d




	




c                 C   sR  |   ¡ st d¡ q |jrdS |  ¡ rR|  ¡ D ]}|j |¡ q.| t	|  ¡ ƒ¡ |j
rh|j d¡ dS |rÒt|d ƒ}tdd„ |d D ƒƒ}t || ¡}|d| krÒd ||||¡}|j |¡ | |¡ dS d	|_|j d
¡ tj|Ž  |jrN|d }	t |j|	¡}
|
|jkr&|j d¡ n(|j d¡ | ttj |	¡t|jƒ¡ dS )z=Run function after thread pool is done. Run this in a thread.r°   NzTask had errors. Exiting...r   c                 S   s   g | ]}t j |¡‘qS r   )r9   r:   Úgetsizer"   r   r   r   r%   ˆ  s     z+post_threadpool_actions.<locals>.<listcomp>i   znDiff between downloaded files and expected filesizes is {}B (filesize: {}, expected_filesize: {}, {} threads).Ú	combiningzCombining downloaded file.r(   zHash verification succeeded.zHash verification failed.)Údoner²   r³   rR   Zget_exceptionZget_exceptionsr,   r™   rŸ   r1   rS   r\   r‚   ÚsumÚmathÚfabsr   rP   r5   r   Zcombine_filesrQ   rƒ   rV   rW   r    r
   r9   r:   r;   rf   )r]   r   Zexpected_filesizeZ
SmartDLObjÚexcr^   Ztotal_filesizeÚdiffZerrMsgZ	dest_pathZhash_r   r   r   r‘   t  s<    

r‘   )$r9   Úurllib.requestr6   Úurllib.errorÚurllib.parser   r²   r×   r>   rb   rÌ   r…   Úior   Zmultiprocessing.dummyÚdummyrL   Úctypesr   rÐ   r›   r   rY   r   r   Ú__all__Z__version_mjaor__Z__version_minor__Z__version_micro__r   Ú__version__Ú	Exceptionr
   r   r   r‘   r   r   r   r   Ú<module>   s8   	    K