U
    P;cc                     @   st  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Zd dlZzd dlZejZW n ek
r   dZeZY nX dZG dd deZdae Zejdd dkZejdd dkZejdd d	kZzd dlZW n> ek
r6   zd dlZW n ek
r0   dZY nX Y nX z>d dlm  mZ  zd d
lm!Z" W n ek
rr   Y nX W n2 ek
r   d dl#m$Z% d dlm&Z& dZ Y nX z4d dl'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1 W nF ek
r$   d dl2m(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1 Y nX zd dl3m4Z4m5Z5 W n& ek
r`   d dl6m4Z4m5Z5 Y nX zd dl3m7Z7 W nB ek
r   zd dl6m7Z7 W n ek
r   dZ7Y nX Y nX zd dl3m8Z8 W n ek
r   dZ8Y nX zd dl9m9Z9 W n" ek
r   d dl:m9Z9 Y nX zd dl;m;Z; W n" ek
rH   d dl<m;Z; Y nX zd dl;m=Z= W nJ ek
r   zd dl<m=Z= W n" ek
r   d dl>m=Z= Y nX Y nX zd dl?m@Z@ W n" ek
r   d dl@m@Z@ Y nX z(d dlAmBZC d dlAmDZE eFZGeHZIeJZKW n: ek
r<   d dlLmMZC d dlLmNZE dZGdZIdZKY nX zd dlOmPZP dZQW nR ek
r   zd dlPmPZP dZQW n& ek
r   d dlRmPZPmQZQ Y nX Y nX zd dlSZSW n ek
rF   d dlTZTd dlRmUZUmVZV G dd  d eUZWeXeTd!ZYzeWejZZ[eWej\Z]W n" e^k
r0   ejZZ[ej\Z]Y nX d"d# Z_d$d% Z`Y nX [Sd&d# Z_d'd% Z`erje jajbZcnerve"jdZcerejejfZgnejejhZgzLd dliZizeijjfZkW n elk
r   em ZkY nX e*e+ejneijoe5fek ZpW n( ek
r   dZie*e+ejne5fZpY nX G d(d) d)eqZrG d*d+ d+erZsG d,d- d-erZtG d.d/ d/erZuG d0d1 d1erZvG d2d3 d3etZwG d4d5 d5etZxG d6d7 d7erZyG d8d9 d9erZzG d:d; d;erZ{G d<d= d=erZ|G d>d? d?erZ}G d@dA dAerZ~G dBdC dCerZG dDdE dEerZG dFdG dGerZedfdHdIZG dJdK dKe4Ze7r8G dLdM dMe7ZddNdOZG dPdQ dQe,ZG dRdS dSe,ZddUdVZG dWdX dXeZdYdZ Zd[d\ Zd]d^ Zdd`daZddbdcZddde Zdfdg Zdhdi Zdjdk ZG dldm dmejeZG dndo doeZG dpdq dqejeZG drds dseZG dtdu dueZdvdw Zdxdy Zdd{d|Zd}d~ Zdd ZdddZdd Zdd Zedkrpe  dS )    Nz2.1.3c                   @   s   e Zd ZdZedd ZdS )FakeShutdownEventzClass to fake a threading.Event.isSet so that users of this module
    are not required to register their own threading.Event()
    c                   C   s   dS )z#Dummy method to always return falseF r   r   r   -/tmp/pip-unpacked-wheel-bun4rs_y/speedtest.pyisSet/   s    zFakeShutdownEvent.isSetN)__name__
__module____qualname____doc__staticmethodr   r   r   r   r   r   *   s   r   F   )r      )r      )   r   )_Element)minidom)
ExpatError)
urlopenRequest	HTTPErrorURLErrorAbstractHTTPHandlerProxyHandlerHTTPDefaultErrorHandlerHTTPRedirectHandlerHTTPErrorProcessorOpenerDirector)HTTPConnectionBadStatusLine)HTTPSConnection)
FakeSocket)Queue)urlparse)parse_qs)md5)ArgumentParser)SUPPRESS)OptionParser)SUPPRESS_HELPintstringfloat)StringIO)r+   BytesIO)TextIOWrapperFileIOc                       s,   e Zd ZdZ fddZ fddZ  ZS )_Py3Utf8OutputzVUTF-8 encoded wrapper around stdout for py3, to override
        ASCII stdout
        c                    s(   t | d}tt| j|ddd d S )Nwutf8strict)encodingerrors)r.   filenosuperr/   __init__)selffkwargsbuf	__class__r   r   r7      s    
z_Py3Utf8Output.__init__c                    s   t t| | |   d S N)r6   r/   writeflush)r8   sr<   r   r   r?      s    z_Py3Utf8Output.write)r   r   r   r	   r7   r?   __classcell__r   r   r<   r   r/      s   r/   printc                 C   s   | S )zNo-op encode to utf-8 for py3r   vr   r   r   to_utf8   s    rF   c                  O   s8   | dtjkrt|d< n| dt|d< t| | dS )z>Wrapper function for py3 to print, with a utf-8 encoded stdoutfileN)getsysstderr_py3_utf8_stderr_py3_utf8_stdout
_py3_printargsr:   r   r   r   print_   s    
rP   c                 C   s,   z|  ddW S  tk
r&   |  Y S X dS )z)Encode value to utf-8 if possible for py2r1   r2   N)encodeAttributeErrorrD   r   r   r   rF      s    c            
         s.  | dtj  dkrdS  fdd}d}| dd}|dk	r`t|trNd}nt|ts`td| d	d}|dk	rt|trd}nt|tstd
|rtd|s| D ]}t|trd} qq|rtd}td}nd}d}|dkr|}|dkr|}t| D ] \}	}|	r|| || q || dS )zThe new-style print function for Python 2.4 and 2.5.

        Taken from https://pypi.python.org/pypi/six/

        Modified to set encoding to UTF-8 always, and to flush after write
        rG   Nc                    sl   t | tst| } d}t  trVt | trV|d k	rVt dd }|d krJd}| ||}  |     d S )Nr1   r4   r2   )	
isinstance
basestringstrrG   unicodegetattrrQ   r?   r@   )datar3   r4   fpr   r   r?      s    


zprint_.<locals>.writeFsepTzsep must be None or a stringendzend must be None or a stringz$invalid keyword arguments to print()
 )poprI   stdoutrS   rV   rU   	TypeError	enumerate)
rO   r:   r?   Zwant_unicoder[   r\   argnewlinespaceir   rY   r   rP      sL    





c                   @   s   e Zd ZdZdS )SpeedtestExceptionzBase exception for this moduleNr   r   r   r	   r   r   r   r   rg   )  s   rg   c                   @   s   e Zd ZdZdS )SpeedtestCLIErrorz9Generic exception for raising errors during CLI operationNrh   r   r   r   r   ri   -  s   ri   c                   @   s   e Zd ZdZdS )SpeedtestHTTPErrorz#Base HTTP exception for this moduleNrh   r   r   r   r   rj   1  s   rj   c                   @   s   e Zd ZdZdS )SpeedtestConfigErrorzConfiguration XML is invalidNrh   r   r   r   r   rk   5  s   rk   c                   @   s   e Zd ZdZdS )SpeedtestServersErrorzServers XML is invalidNrh   r   r   r   r   rl   9  s   rl   c                   @   s   e Zd ZdZdS )ConfigRetrievalErrorzCould not retrieve config.phpNrh   r   r   r   r   rm   =  s   rm   c                   @   s   e Zd ZdZdS )ServersRetrievalErrorz(Could not retrieve speedtest-servers.phpNrh   r   r   r   r   rn   A  s   rn   c                   @   s   e Zd ZdZdS )InvalidServerIDTypez/Server ID used for filtering was not an integerNrh   r   r   r   r   ro   E  s   ro   c                   @   s   e Zd ZdZdS )NoMatchedServersz!No servers matched when filteringNrh   r   r   r   r   rp   I  s   rp   c                   @   s   e Zd ZdZdS )SpeedtestMiniConnectFailurez7Could not connect to the provided speedtest mini serverNrh   r   r   r   r   rq   M  s   rq   c                   @   s   e Zd ZdZdS )InvalidSpeedtestMiniServerzjServer provided as a speedtest mini server does not actually appear
    to be a speedtest mini server
    Nrh   r   r   r   r   rr   Q  s   rr   c                   @   s   e Zd ZdZdS )ShareResultsConnectFailurez6Could not connect to speedtest.net API to POST resultsNrh   r   r   r   r   rs   W  s   rs   c                   @   s   e Zd ZdZdS )ShareResultsSubmitFailurezRUnable to successfully POST results to speedtest.net API after
    connection
    Nrh   r   r   r   r   rt   [  s   rt   c                   @   s   e Zd ZdZdS )SpeedtestUploadTimeoutz~testlength configuration reached during upload
    Used to ensure the upload halts when no additional data should be sent
    Nrh   r   r   r   r   ru   a  s   ru   c                   @   s   e Zd ZdZdS )SpeedtestBestServerFailurezUnable to determine best serverNrh   r   r   r   r   rv   g  s   rv   c                   @   s   e Zd ZdZdS )SpeedtestMissingBestServerz?get_best_server not called or not able to determine best serverNrh   r   r   r   r   rw   k  s   rw   c              	   C   s   | \}}d}t ||dt jD ]}|\}}}	}
}d}zFt  |||	}|tk	rZ|t| |rh|| || |W   S  t jk
r   t	 }|dk	r|
  Y qX q|dk	r|n
t ddS )a  Connect to *address* and return the socket object.

    Convenience function.  Connect to *address* (a 2-tuple ``(host,
    port)``) and return the socket object.  Passing the optional
    *timeout* parameter will set the timeout on the socket instance
    before attempting to connect.  If no *timeout* is supplied, the
    global default timeout setting returned by :func:`getdefaulttimeout`
    is used.  If *source_address* is set it must be a tuple of (host, port)
    for the socket to bind as a source address before making the connection.
    An host of '' or port 0 tells the OS to use the default.

    Largely vendored from Python 2.7, modified to work with Python 2.4
    Nr   z!getaddrinfo returns an empty list)socketgetaddrinfoSOCK_STREAM_GLOBAL_DEFAULT_TIMEOUT
settimeoutr*   bindconnecterrorget_exceptionclose)addresstimeoutsource_addresshostporterrresafsocktypeproto	canonnamesasockr   r   r   create_connectiono  s(    


r   c                   @   s    e Zd ZdZdd Zdd ZdS )SpeedtestHTTPConnectionzUCustom HTTPConnection to support source_address across
    Python 2.4 - Python 3
    c                 O   s@   | dd }| dd}d | _tj| f|| || _|| _d S Nr   r   
   )r_   _tunnel_hostr   r7   r   r   r8   rO   r:   r   r   r   r   r   r7     s    z SpeedtestHTTPConnection.__init__c              	   C   sf   z t | j| jf| j| j| _W n2 ttfk
rR   t| j| jf| j| j| _Y nX | j	rb| 
  dS )z3Connect to the host and port specified in __init__.N)rx   r   r   r   r   r   r   rR   ra   r   _tunnelr8   r   r   r   r~     s    


zSpeedtestHTTPConnection.connectN)r   r   r   r	   r7   r~   r   r   r   r   r     s   r   c                   @   s$   e Zd ZdZdZdd Zdd ZdS )SpeedtestHTTPSConnectionz^Custom HTTPSConnection to support source_address across
        Python 2.4 - Python 3
        i  c                 O   s@   | dd }| dd}d | _tj| f|| || _|| _d S r   )r_   r   r   r7   r   r   r   r   r   r   r7     s    z!SpeedtestHTTPSConnection.__init__c                 C   s@  z t | j| jf| j| j| _W n2 ttfk
rR   t| j| jf| j| j| _Y nX | j	rb| 
  trzBi }ttdr| j	r| j	|d< n
| j|d< | jj| jf|| _W nF tk
r   t| j| _z| j| j_W n tk
r   Y nX Y nX nJtr4zt| jt | j| _W n tk
r0   tdY nX ntddS )z(Connect to a host on a given (SSL) port.
SSLContextserver_hostnamez?This version of Python does not support HTTPS/SSL functionalityN)rx   r   r   r   r   r   r   rR   ra   r   r   sslhasattr_contextwrap_socketr   r   rg   )r8   r:   r   r   r   r~     sL    




z SpeedtestHTTPSConnection.connectN)r   r   r   r	   default_portr7   r~   r   r   r   r   r     s   r   c                    s    fdd}|S )zCross Python 2.4 - Python 3 callable to build an ``HTTPConnection`` or
    ``HTTPSConnection`` with the args we need

    Called from ``http(s)_open`` methods of ``SpeedtestHTTPHandler`` or
    ``SpeedtestHTTPSHandler``
    c                    s(   | d r|d<  | f|S )Nr   r   context)update)r   r:   
connectionr   r   r   r   r   inner  s    z _build_connection.<locals>.innerr   )r   r   r   r   r   r   r   r   _build_connection  s    r   c                   @   s(   e Zd ZdZd	ddZdd ZejZdS )
SpeedtestHTTPHandlerzCustom ``HTTPHandler`` that can build a ``HTTPConnection`` with the
    args we need for ``source_address`` and ``timeout``
    r   Nr   c                 C   s   t | | || _|| _d S r>   )r   r7   r   r   )r8   
debuglevelr   r   r   r   r   r7     s    zSpeedtestHTTPHandler.__init__c                 C   s   |  tt| j| j|S r>   )do_openr   r   r   r   r8   reqr   r   r   	http_open  s    zSpeedtestHTTPHandler.http_open)r   Nr   )	r   r   r   r	   r7   r   r   do_request_http_requestr   r   r   r   r     s   

r   c                   @   s(   e Zd ZdZd	ddZdd ZejZdS )
SpeedtestHTTPSHandlerzCustom ``HTTPSHandler`` that can build a ``HTTPSConnection`` with the
    args we need for ``source_address`` and ``timeout``
    r   Nr   c                 C   s"   t | | || _|| _|| _d S r>   )r   r7   r   r   r   )r8   r   r   r   r   r   r   r   r7   )  s    zSpeedtestHTTPSHandler.__init__c                 C   s   |  tt| j| j| jd|S )N)r   )r   r   r   r   r   r   r   r   r   r   
https_open0  s    z SpeedtestHTTPSHandler.https_open)r   NNr   )	r   r   r   r	   r7   r   r   r   https_requestr   r   r   r   r   %  s     
r   r   c                 C   s   t d| dd | r0| df}t d|f dd nd}t t||dt||dt t t g}t }dt fg|_	|D ]}|
| qt|S )	zFunction similar to ``urllib2.build_opener`` that will build
    an ``OpenerDirector`` with the explicit handlers we want,
    ``source_address`` for binding, ``timeout`` and our custom
    `User-Agent`
    zTimeout set to %dTdebugr   zBinding to source address: %rNr   z
User-agent)printerr   r   r   r   r   r   r   build_user_agent
addheadersadd_handler)r   r   source_address_tuplehandlersopenerhandlerr   r   r   build_opener>  s.    
r   c                   @   s    e Zd ZdZdd Zdd ZdS )GzipDecodedResponsezA file-like object to decode a response encoded with the gzip
    method, as described in RFC 1952.

    Largely copied from ``xmlrpclib``/``xmlrpc.client`` and modified
    to work for py2.4-py3
    c                 C   sf   t stdtpt}| | _|d}t|dkr4qB| j| q| jd t j	j
| d| jd d S )NzEHTTP response body is gzip encoded, but gzip support is not available   r   rb)modefileobj)gziprj   r,   r+   ioreadlenr?   seekGzipFiler7   )r8   responseIOchunkr   r   r   r7   i  s    
zGzipDecodedResponse.__init__c                 C   s"   ztj|  W 5 | j   X d S r>   )r   r   r   r   r   r   r   r   r   y  s    zGzipDecodedResponse.closeN)r   r   r   r	   r7   r   r   r   r   r   r   b  s   r   c                   C   s   t  d S )zgHelper function to work with py2.4-py3 for getting the current
    exception in a try/except block
       )rI   exc_infor   r   r   r   r     s    r   c                 C   s   | \}}|\}}d}t || }t || }t |d t |d  t t |t t | t |d  t |d   }	dt t |	t d|	  }
||
 }|S )z4Determine distance between 2 sets of [lat,lon] in kmi  r   r   )mathradianssincosatan2sqrt)originZdestinationZlat1Zlon1Zlat2Zlon2ZradiusZdlatZdlonacdr   r   r   distance  s"     r   c                  C   sL   ddt   t  d f dt   ddt f} d| }td| d	d
 |S )z0Build a Mozilla/5.0 compatible User-Agent stringzMozilla/5.0z(%s; U; %s; en-us)r   z	Python/%sz(KHTML, like Gecko)zspeedtest-cli/%sr^   zUser-Agent: %sTr   )platformarchitecturepython_version__version__joinr   )Zua_tuple
user_agentr   r   r   r     s    


r   0c           	      C   s   |si }| d dkr.dt | }d|| f }n| }d| kr@d}nd}d||ttj d |f }|d	d
i tddt | |f dd t|||dS )znBuild a urllib2 request object

    This function automatically adds a User-Agent header to all requests

    r   :)httphttpsz%s%s?&z%s%sx=%s.%s  zCache-Controlzno-cache%s %s)GETPOSTTr   )rX   headers)boolr(   timeittimer   r   r   )	urlrX   r   bumpsecureschemeZschemed_urldelimZ	final_urlr   r   r   build_request  s*     r   c                 C   sn   |r|j }nt}z6|| }|  | kr>td|  dd |dfW S  tk
rh   t }d|f Y S X dS )zyHelper function to catch common exceptions encountered when
    establishing a connection with a HTTP/HTTPS request

    zRedirected to %sTr   FN)openr   get_full_urlgeturlr   HTTP_ERRORSr   )requestr   _openuher   r   r   catch_request  s    
r   c                 C   s@   z| j j}W n tk
r&   | j}Y nX |ddkr<t| S | S )zzHelper function to return either a Gzip reader if
    ``Content-Encoding`` is ``gzip`` otherwise the response itself

    zcontent-encodingr   )r   	getheaderrR   r   )r   r   r   r   r   get_response_stream  s    r   c                 C   s    |  |d }tt|j S )zRetrieve an attribute from an XML document and return it in a
    consistent format

    Only used with xml.dom.minidom, which is likely only to be used
    with python versions older than 2.5
    r   )getElementsByTagNamedictlist
attributesitems)domZtag_nameelemr   r   r   get_attributes_by_tag_name  s    r  c                    s   d fdd	}|S )zNBuilt in callback function used by Thread classes for printing
    status
    Fc                    sF      rd S tjd | d |kr8|dkr8tjd tj  d S )N.r   Tr]   )r   rI   r`   r?   r@   )currenttotalstartr\   shutdown_eventr   r   r     s    zprint_dots.<locals>.inner)FFr   r	  r   r   r  r   
print_dots  s    r  c                  O   s   d S r>   r   rN   r   r   r   
do_nothing  s    r  c                   @   s"   e Zd ZdZdddZdd ZdS )HTTPDownloaderz!Thread class for retrieving a URLNc                 C   sX   t j|  || _dg| _|| _|| _|| _|r:|j| _	nt
| _	|rL|| _nt | _d S Nr   )	threadingThreadr7   r   result	starttimer   rf   r   _openerr   _shutdown_eventr   )r8   rf   r   r  r   r   r	  r   r   r   r7     s    
zHTTPDownloader.__init__c                 C   s   zrt  | j | jkrp| | j}| j sht  | j | jkrh| j	t
|d | jd dkr"qhq"|  W n& tk
r   Y n tk
r   Y nX d S )N (  r   )r   default_timerr  r   r  r   r  r   r  appendr   r   r   IOErrorr   )r8   r9   r   r   r   run'  s     
zHTTPDownloader.run)NNr   r   r   r	   r7   r  r   r   r   r   r    s
     
r  c                   @   s@   e Zd ZdZdddZdd Zedd Zdd
dZdd Z	dS )HTTPUploaderDataz]File like object to improve cutting off the upload once the timeout
    has been reached
    Nc                 C   s8   || _ || _|| _|r|| _nt | _d | _dg| _d S r  )lengthr  r   r  r   _datar  )r8   r  r  r   r	  r   r   r   r7   =  s    zHTTPUploaderData.__init__c                 C   sp   d}t tt | jd }tp t}z,|d|| dt | jd    | _W n tk
rj   tdY nX d S )NZ$0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZg      B@zcontent1=%sr   	   zMInsufficient memory to pre-allocate upload data. Please use --no-pre-allocate)	r(   roundr  r,   r+   rQ   r  MemoryErrorri   )r8   charsZ
multiplierr   r   r   r   pre_allocateK  s    
zHTTPUploaderData.pre_allocatec                 C   s   | j s|   | j S r>   )r  r#  r   r   r   r   rX   [  s    zHTTPUploaderData.datar  c                 C   sH   t  | j | jkr>| j s>| j|}| j	t
| |S t d S r>   )r   r  r  r   r  r   rX   r   r  r  r   ru   )r8   nr   r   r   r   r   a  s    zHTTPUploaderData.readc                 C   s   | j S r>   )r  r   r   r   r   __len__j  s    zHTTPUploaderData.__len__)N)r  )
r   r   r   r	   r7   r#  propertyrX   r   r%  r   r   r   r   r  8  s   


	r  c                   @   s"   e Zd ZdZdddZdd ZdS )HTTPUploaderzThread class for putting a URLNc                 C   sf   t j|  || _| | jj_| _|| _d| _|| _	|| _
|rH|j| _nt| _|rZ|| _nt | _d S r  )r  r  r7   r   rX   r  r  sizer  r   rf   r   r  r   r  r   )r8   rf   r   r  r(  r   r   r	  r   r   r   r7   q  s    
zHTTPUploader.__init__c              	   C   s   | j }zt | j | jkr| j sz| |}W n: tk
rn   t	| j 
 |j| jd}| |}Y nX |d |  t| j jj| _nd| _W n@ ttfk
r   t| j jj| _Y n tk
r   d| _Y nX d S )N)rX      r   )r   r   r  r  r   r  r   r  ra   r   r   rX   r   r(  r   sumr  r  r  ru   r   )r8   r   r9   r   r   r   r    s(    


zHTTPUploader.run)NNr  r   r   r   r   r'  n  s
     
r'  c                   @   sT   e Zd ZdZdddZdd Zd	d
 Zdd ZedddZ	dddZ
dddZdS )SpeedtestResultsat  Class for holding the results of a speedtest, including:

    Download speed
    Upload speed
    Ping/Latency to test server
    Data about server that the test was run against

    Additionally this class can return a result data as a dictionary or CSV,
    as well as submit a POST of the result data to the speedtest.net API
    to get a share results image link.
    r   NFc                 C   sv   || _ || _|| _|d kr"i | _n|| _|p.i | _d | _dtj   | _	d| _
d| _|rd|| _nt | _|| _d S )Nz%sZr   )downloaduploadpingserverclient_sharedatetimeutcnow	isoformat	timestampbytes_received
bytes_sentr  r   _secure)r8   r,  r-  r.  r/  r0  r   r   r   r   r   r7     s    
zSpeedtestResults.__init__c                 C   s   t |  S r>   )reprr   r   r   r   r   __repr__  s    zSpeedtestResults.__repr__c                 C   sb  | j r| j S tt| jd d}tt| jd}tt| jd d}d| jd  d| ddd| d	d
| ddtd|||df  	  dddd| j
 d| j d| jd  g}ddi}tdd| || jd}t|| jd\}}|rt|| }	|j}
|  t|
dkrtdt|	 }|d}|rFt|dkrNtdd|d  | _ | j S ) zRPOST data to the speedtest.net API to obtain a share results
        link
             @@r   zrecommendedserverid=%sidzping=%szscreenresolution=zpromo=zdownload=%sz
screendpi=z	upload=%sztestmethod=httpzhash=%sz%s-%s-%s-%sZ297aae72ztouchscreen=nonezstartmode=pingselectz
accuracy=1zbytesreceived=%szbytessent=%szserverid=%sZRefererz*http://c.speedtest.net/flash/speedtest.swfz ://www.speedtest.net/api/api.phpr   )rX   r   r   r      z)Could not submit results to speedtest.netresultidr   z&http://www.speedtest.net/result/%s.png)r1  r(   r   r,  r.  r-  r/  r#   rQ   	hexdigestr6  r7  r   r   r8  r   r  rs   r   coder   rt   r"   decoderH   r   )r8   r,  r.  r-  Zapi_datar   r   r9   r   r   rA  Zqsargsr?  r   r   r   share  sV    
 
zSpeedtestResults.sharec              
   C   s*   | j | j| j| j| j| j| j| j| jd	S )z Return dictionary of result data)	r,  r-  r.  r/  r5  r7  r6  rC  r0  )	r,  r-  r.  r/  r5  r7  r6  r1  r0  r   r   r   r   r     s    zSpeedtestResults.dict,c              
   C   sJ   ddddddddd	d
g
}t  }tj|| dd}|dd |D  | S )zReturn CSV Headersz	Server IDZSponsorzServer NameZ	TimestampZDistanceZPingDownloadZUploadZSharez
IP Address 	delimiterlineterminatorc                 S   s   g | ]}t |qS r   rF   .0rE   r   r   r   
<listcomp>  s     z/SpeedtestResults.csv_header.<locals>.<listcomp>)r+   csvwriterwriterowgetvalue)rH  rowoutrO  r   r   r   
csv_header  s    
    zSpeedtestResults.csv_headerc                 C   s   |   }t }tj||dd}|d d |d d |d d |d |d d |d	 |d
 |d | jpfd| jd g
}|dd |D  | S )zReturn data in CSV formatrF  rG  r/  r<  sponsornamer5  r   r.  r,  r-  ipc                 S   s   g | ]}t |qS r   rJ  rK  r   r   r   rM  &  s     z(SpeedtestResults.csv.<locals>.<listcomp>)r   r+   rN  rO  r1  r0  rP  rQ  )r8   rH  rX   rS  rO  rR  r   r   r   rN    s    
 
    zSpeedtestResults.csvc                 C   s*   i }|r| ddd tj|  f|S )zReturn data in JSON format   T)indent	sort_keys)r   jsondumpsr   )r8   prettyr:   r   r   r   r[  )  s    zSpeedtestResults.json)r   r   r   NNNF)rD  )rD  )F)r   r   r   r	   r7   r:  rC  r   r
   rT  rN  r[  r   r   r   r   r+    s       
=

r+  c                   @   sr   e Zd ZdZdddZedd Zd	d
 ZdddZdd Z	dddZ
dddZedfddZeddfddZdS )	Speedtestz>Class for performing standard speedtest.net testing operationsNr   Fc                 C   s   i | _ || _|| _t||| _|| _|r0|| _nt | _|   |d k	rT| j 	| i | _
g | _i | _t| j d | j|d| _d S )Nr0  )r0  r   r   )config_source_address_timeoutr   r  r8  r  r   
get_configr   serversclosest_bestr+  results)r8   r_  r   r   r   r	  r   r   r   r7   8  s&    zSpeedtest.__init__c                 C   s   | j s|   | j S r>   )re  get_best_serverr   r   r   r   bestU  s    zSpeedtest.bestc                 C   s  i }t rd|d< td|| jd}t|| jd\}}|r>t|g }t|}z||d W n" t	t
fk
r   tt Y nX t|d dkrJqqJ|  |  t|jd	krd
S d |}td| dd znzt|}W n* tjk
r   t }td| Y nX |dj}	|dj}
|dj}|dj}W nv tk
r   zt|}W n( tk
r   t }td| Y nX t|d}	t|d}
t|d}t|d}Y nX dd |	d dD }t|d }t|d }ddddddd g}||d! d
 d"d#d$d%d&d'd(d)d*d+g
d,}t|d }tt || }|t|
d- d,}t|d. t|	d/ d0 d,}t|d1 t|
d1 d,}| j!"|||||||| d2 zt#|d3 t#|d4 f| _$W n2 t%k
r    td5|&d3|&d4f Y nX td6| j! dd | j!S )7zgDownload the speedtest.net configuration and return only the data
        we are interested in
        r   Accept-Encodingz)://www.speedtest.net/speedtest-config.phpr   r   r=  r   r  r   r>  NrF  zConfig XML:
%sTr   z)Malformed speedtest.net configuration: %szserver-configr,  r-  r0  c                 S   s   g | ]}|rt |qS r   )r(   )rL  rf   r   r   r   rM    s     z(Speedtest.get_config.<locals>.<listcomp>Z	ignoreidsrD  ratioZmaxchunkcounti   i   i   i   i   i   i  p r   i^  i  i  r   i  i  i	  i  i  i  )r-  r,  ZthreadsperurlthreadsZthreadcountr   Z
testlength)r0  ignore_serverssizescountsrl  r  
upload_maxlatlonzUnknown location: lat=%r lon=%rz
Config:
%r)'r   r   r8  r   r  rm   r   r  r   OSErrorEOFErrorr   r   r   r(   rA  rQ   r   r   ET
fromstring
ParseErrorrk   findattribrR   DOMparseStringr   r  splitr   ceilr_  r   r*   lat_lon
ValueErrorrH   )r8   r   r   r   r   Zconfigxml_liststreamZ	configxmlrootZserver_configr,  r-  r0  rm  rk  rp  Zup_sizesrn  Z
size_countZupload_countro  rl  r  r   r   r   rb  [  s     




  





zSpeedtest.get_configc                 C   s  |dkrg }|dkrg }| j   ||fD ]H}t|D ]:\}}zt|||< W q6 tk
rn   td| Y q6X q6q*ddddg}i }trd|d< g }|D ] }	ztd	|	| jd
 d f || j	d}
t
|
| jd\}}|r|d|  t t|}g }z||d W n$ ttfk
r2   tt Y nX t|d dkrqJq|  |  t|jdkrpt d |}td| dd zzHzt|}W n* tjk
r   t }td| Y nX t|d}W nX tk
r0   zt |}W n( t!k
r    t }td| Y nX |"d}Y nX W n& t#t$j%j&j!fk
rZ   t Y nX |D ]}z
|j'}W n( tk
r   t(t)|j*+ }Y nX |rt|,d|krq`t|,d| jd ks`t|,d|krq`z(t-| j.t/|,dt/|,df}W n t0k
r.   Y q`Y nX ||d< z| j | | W n" t1k
rn   |g| j |< Y nX q`W  qW q tk
r   Y qY qX q|s|r| j st2 | j S )zRetrieve a the list of speedtest.net servers, optionally filtered
        to servers matching those specified in the ``servers`` argument
        Nz)%s is an invalid server type, must be intz1://www.speedtest.net/speedtest-servers-static.phpz3http://c.speedtest.net/speedtest-servers-static.phpz*://www.speedtest.net/speedtest-servers.phpz,http://c.speedtest.net/speedtest-servers.phpr   ri  z%s?threads=%srl  r,  rj  r=  %sr   r  r   r>  rF  zServers XML:
%sTr   z'Malformed speedtest.net server list: %sr/  r<  rm  rq  rr  r   )3rc  clearrb   r(   r  ro   r   r   r_  r8  r   r  r  rn   r   r   rs  rt  r   r   r   rA  rQ   r   r   ru  rv  rw  rl   
etree_iterrR   rz  r{  r   r   SyntaxErrorxmlparsersexpatry  r   r   r   r   rH   r   r~  r*   	ExceptionKeyErrorrp   )r8   rc  excludeZserver_listrf   rA   urlsr   r4   r   r   r   r   r  Zserversxml_listZ
serversxmlr  elementsr/  ry  r   r   r   r   get_servers  s    





zSpeedtest.get_serversc              	   C   sD  t |}tj|d \}}|r.tj|}n|}t|}t|| jd\}}|r^td| n|	 }	|
  td|	 }
|
sdD ]r}z| jd||f }W n tk
r   Y qX |	   }|jdkrt| dkrtd	|r|g}
 qq|r|
std
| d|d dd|d|
d f dddg| _| jS )zaInstead of querying for a list of servers, set a link to a
        speedtest mini server
        r   r=  zFailed to connect to %szupload_?[Ee]xtension: "([^"]+)")ZphpZaspZaspxZjspz%s/speedtest/upload.%sr>  r   z
size=[0-9]z!Invalid Speedtest Mini Server: %szSpeedtest Minir   /)rU  rV  r   r   latencyr<  )r!   ospathsplitextdirnamer   r   r  rq   r   r   refindallrB  r   r  striprA  r   
splitlinesmatchrr   rstriprc  )r8   r/  urlpartsrV  extr   r   r   r   text	extensionr9   rX   r   r   r   set_mini_serverM  sX    



	zSpeedtest.set_mini_serverr   c                 C   sn   | j s|   t| j  D ]8}| j | D ]"}| j| t| j|kr* qPq*q qVqtd| j dd | jS )z`Limit servers to the closest speedtest.net servers based on
        geographic distance
        zClosest Servers:
%rTr   )rc  r  sortedkeysrd  r  r   r   )r8   limitr   rA   r   r   r   get_closest_servers  s    zSpeedtest.get_closest_serversc              
   C   s>  |s| j s|  }| j }| jr*| jdf}nd}t }i }|D ]}g }tj|d }ttj		 d }d||f }	t
ddD ](}
d|	|
f }tdd	|f d
d t|	}zz|d dkrt|d |d}nt|d |d}d|i}d|d |d f }t }|jd	||d | }t | }W n: tk
r`   t }td| d
d |d Y q~Y nX |d}t|jdkr|d kr|| n
|d |  q~tt|d d d}|||< q<zt| d }W n tk
r   tdY nX || }||d< || j_ || j_!| j"#| td| d
d |S )znPerform a speedtest.net "ping" to determine which speedtest.net
        server has the lowest latency
        r   Nr   r   z%s/latency.txt?x=%sr   z%s.%sr   r   Tr   r   r   )r   z
User-Agentz%s?%sr   rX  )r   z	ERROR: %ri  r  r>  z	test=testr   r;  z-Unable to connect to servers to test latency.r  zBest Server:
%r)$rd  r  r`  r   r  r  r  r(   r   r   ranger   r!   r   r   r  r   getresponser   r   r  r   statusrQ   r   r   r*  r  r  
IndexErrorrv   rf  r.  r/  re  r   )r8   rc  r   r   rf  r/  Zcumr   ZstampZlatency_urlrf   Zthis_latency_urlr  hr   r  r  rr  r   r  avgZfastestrh  r   r   r   rg    sv    






zSpeedtest.get_best_serverc              	      s  g }j d d D ]@}tdj d d D ]&}|dtjjd ||f  q*qt|}g }t|D ]\}}	|t	|	|j
d qh|pj d d ddi fd	d
}
g  fdd}t}tj|
|||fd}tj|||fd}t |  |  t}||r.|jdd q||rH|jdd q.t }tj_jj|  d j_jjdkrdj d d< jjS )zTest download speed against speedtest.net

        A ``threads`` value of ``None`` will fall back to those dictated
        by the speedtest.net configuration
        rn  r,  r   ro  z%s/random%sx%s.jpgr   )r   r   rl  c              	      s   t |D ]v\}}t||jd d jjd}d krLtjd q2|  | 	|d d  d7  <  ||dd qd S )	Nr  r,  r   r	  rl  MbP?Tr   r  )
rb   r  r_  r  r  r   r   sleepr  putqrequestsrequest_countrf   r   threadcallback	in_flightmax_threadsr8   r  r   r   producer  s    z$Speedtest.download.<locals>.producerc                    sf   t }t|k rb| d}||r0|jdd qd  d8  < t|j  |j|dd qd S NTr  r   rl  r   r\   )thread_is_aliver   rH   r   r  r*  r  rf   r  r  	_is_aliver  r  finishedr  r   r   consumer  s    
z$Speedtest.download.<locals>.consumertargetrO   r  r         @i    r-  )r_  r  r  r  r  r  rh  r   rb   r   r8  r    r  r  r   r  r  r  r   r*  rf  r6  r,  )r8   r  rl  r  r(  _r  r  rf   r   r  r  r  prod_threadcons_threadr  stopr   r  r  r  r  r8   r  r   r,    sN    



zSpeedtest.downloadTc              	      s  g }j d d D ](}tdj d d D ]}|| q*qj d }g }t|D ]Z\}	}t|dj d d jd}
|r|
  d|i}|tjd	 |
j	|d
|f qR|pj d d ddi fdd}g  fdd}t
|pj d d }tj||||fd}tj|||fd}t |  |  t}||rd|jdd qJ||r~|jdd qdt }tj_jj|  d j_jjS )zTest upload speed against speedtest.net

        A ``threads`` value of ``None`` will fall back to those dictated
        by the speedtest.net configuration
        rn  r-  r   ro  rp  r  r  zContent-lengthr   )r   r   rl  c              
      s   t |d | D ]\}}t||d |d jd d jjd}d kr^tjd qD|  | 	|d d  d7  <  ||dd	 qd S )
Nr   r   r  r-  r  rl  r  Tr  )
rb   r'  r_  r  r  r   r   r  r  r  r  r  r   r   r  W  s     	z"Speedtest.upload.<locals>.producerc                    sb   t }t|k r^| d}||r0|jdd qd  d8  < |j  |j|dd qd S r  )r  r   rH   r   r  r  rf   r  r  r   r   r  k  s    
z"Speedtest.upload.<locals>.consumerr  g?r  r  )r_  r  r  rb   r  r  r#  r   rh  r8  r    r  r  r   r  r  r  r   r*  rf  r7  r-  )r8   r  r#  rl  rn  r(  r  r  r  rf   rX   r   r  r  r  r  r  r  r  r   r  r   r-  .  s`    



zSpeedtest.upload)NNr   FN)NN)r   )N)r   r   r   r	   r7   r&  rh  rb  r  r  r  rg  r  r,  r-  r   r   r   r   r^  5  s       

t
~6

LKr^  c                    s    fdd}|S )zWCatch Ctrl-C key sequence and set a SHUTDOWN_EVENT for our threaded
    operations
    c                    s"       tddd td d S )N
Cancelling...Tr   r   )setr   rI   exit)signumframer  r   r   r     s    zctrl_c.<locals>.innerr   r
  r   r  r   ctrl_c  s    r  c                   C   s0   t dt  t dtjdd  td dS )zPrint the versionzspeedtest-cli %sz	Python %sr]   rF  r   N)r   r   rI   versionreplacer  r   r   r   r   r    s    r  rD  c                 C   s   t tj| d td dS )zPrint the CSV HeadersrH  r   N)r   r+  rT  rI   r  r  r   r   r   rT    s    rT  c                  C   s  d} t | d}z|j|_W n tk
r.   Y nX |jddddddd	 |jd
dddddd	 |jddddd |jddddddd |jdddd |jddddd |jddddd |jdd td!d" |jd#ddd$d |jd%ddd&d |jd'dd(d |jd)td*d+d, |jd-td*d.d, |jd/d0d1 |jd2d3d1 |jd4d5td6d" |jd7dd8d |jd9d:dddd;d< |jd=dd>d |jd?dttd@ | }t	|t
r|dA }n|}|S )BzAFunction to handle building and parsing of command line argumentszCommand line interface for testing internet bandwidth using speedtest.net.
--------------------------------------------------------------------------
https://github.com/sivel/speedtest-cli)descriptionz--no-downloadr,  Tstore_constFzDo not perform download test)destdefaultactionconsthelpz--no-uploadr-  zDo not perform upload testz--single
store_truezYOnly use a single connection instead of multiple. This simulates a typical file transfer.)r  r  r  z--bytesunits)byter  )bitr   zxDisplay values in bytes instead of bits. Does not affect the image generated by --share, nor output from --json or --csv)r  r  r  r  r  z--sharez]Generate and provide a URL to the speedtest.net share results image, not displayed with --csv)r  r  z--simplez4Suppress verbose output, only show basic information)r  r  r  z--csvzvSuppress verbose output, only show basic information in CSV format. Speeds listed in bit/s and not affected by --bytesz--csv-delimiterrD  z<Single character delimiter to use in CSV output. Default ",")r  typer  z--csv-headerzPrint CSV headersz--jsonzwSuppress verbose output, only show basic information in JSON format. Speeds listed in bit/s and not affected by --bytesz--listz:Display a list of speedtest.net servers sorted by distancez--serverr  zCSpecify a server ID to test against. Can be supplied multiple times)r  r  r  z	--excludez?Exclude a server from selection. Can be supplied multiple timesz--miniz URL of the Speedtest Mini server)r  z--sourcezSource IP address to bind toz	--timeoutr   z#HTTP timeout in seconds. Default 10z--securezPUse HTTPS instead of HTTP when communicating with speedtest.net operated serversz--no-pre-allocater#  zDo not pre allocate upload data. Pre allocation is enabled by default to improve upload performance. To support systems with insufficient memory, use this option to avoid a MemoryError)r  r  r  r  r  z	--versionz Show the version number and exitz--debug)r  r  r  r   )	ArgParser
add_optionadd_argumentrR   PARSER_TYPE_STRPARSER_TYPE_INTPARSER_TYPE_FLOATARG_SUPPRESS
parse_argsrS   tuple)r  parseroptionsrO   r   r   r   r    s    

 
 

 







   
r  c                 C   sT   dt fdtfd}| D ]4\}}t| |dr|d dkrtd|d |f qdS )	zCheck if an argument was provided that depends on a module that may
    not be part of the Python standard library.

    If such an argument is supplied, and the module does not exist, exit
    with an error stating which module is missing.
    zjson/simplejson python modulezSSL support)r[  r   Fr   Nz(%s is not installed. --%s is unavailabler   )r[  r   r   rW   
SystemExit)rO   Zoptional_argsrc   infor   r   r   validate_optional_args  s    
r  c                 K   sT   |rt sdS |r.tj r$d|  }q2d|  }n| }|r@tj|d< |sPt|f| dS )z4Helper function print a string with various featuresNz[1;30mDEBUG: %s[0mz	DEBUG: %srG   )DEBUGrI   r`   isattyrJ   rP   )r)   quietr   r   r:   rS  r   r   r   r     s    



r   c               
   C   s  t  } ttjt|  t }|jr,t  |js@|js@t	dt
|jdkrVt	d|jrft|j t| t|dd}|dkrd}|rda|js|js|jrd}nd}|js|jrd}nd}|s|rt}nt| }td| zt|j|j|jd	}W n2 tft k
r*   td
dd t	t Y nX |jrz|  W n2 tft k
rr   tddd t	t Y nX t |j!" D ]X\}}|D ]H}	d|	 }
zt|
 W n, t#k
r   t }|j$t$j%kr΂ Y nX qqt&'d td|j(d  | |j)std| z|j|j*|j+d W n t,k
rV   t	dd-dd |j*D  Y nd tft k
r   tddd t	t Y n4 t.k
r   t	dd-dd |j*D  Y nX |j*rt
|j*dkrtd| n
td| |/  n|j)r|/|0|j) |j1}td|j* | |jrtd|dt2| d |j|d|j3 d  td!|jd" d" |j4d  |j4d f | n
td#| |jrtd$|dt2| d |j||j5d|j3 d% td&|jd" d" |j4d  |j4d f | n
td'| td(|6  dd) |js&|j7r&|7  |jr|td*|j8|jd" d" |j4d  |j4d |jd" d" |j4d  |j4d f  n0|jrt|j|jd+ n|jrt|  |j7r|std,|7   d-S ).zRun the full speedtest.net testz0Cannot supply both --no-download and --no-uploadr   z*--csv-delimiter must be a single characterr   FSUPPRESSHELPTz)Retrieving speedtest.net configuration...)r   r   r   z'Cannot retrieve speedtest configurationr  z%Cannot retrieve speedtest server listz:%(id)5s) %(sponsor)s (%(name)s, %(country)s) [%(d)0.2f km]r   z Testing from %(isp)s (%(ip)s)...r0  z'Retrieving speedtest.net server list...)rc  r  zNo matched servers: %sz, c                 s   s   | ]}d | V  qdS r  Nr   rL  rA   r   r   r   	<genexpr>z  s     zshell.<locals>.<genexpr>z,%s is an invalid server type, must be an intc                 s   s   | ]}d | V  qdS r  r   r  r   r   r   r    s     z1Retrieving information for the selected server...z&Selecting best server based on ping...z>Hosted by %(sponsor)s (%(name)s) [%(d)0.2f km]: %(latency)s mszTesting download speed)rF  r]   r  )Nr   )r  rl  zDownload: %0.2f M%s/sr;  zSkipping download testzTesting upload speed)r  r#  rl  zUpload: %0.2f M%s/szSkipping upload testzResults:
%rr   z5Ping: %s ms
Download: %0.2f M%s/s
Upload: %0.2f M%s/sr  zShare results: %sN)9r  EventsignalSIGINTr  r  r  r,  r-  ri   r   Zcsv_delimiterrT  r  rW   r  simplerN  r[  r  r  r   r^  sourcer   r   rm   r   r   r   r  rn   r  rc  r   r  errnoEPIPErI   r  r_  Zminir/  r  rp   r   ro   rg  r  rf  r   Zsingler  r#  r   rC  r.  )r	  rO   r   r  Zmachine_formatr  Z	speedtestr  rc  r/  liner   rf  r   r   r   shell"  s   











r  c               	   C   s|   z
t   W nl tk
r*   tddd Y nN ttfk
rv   t } t| dddkrrd|  }|sfd|  }td	| Y nX d S )
Nr  Tr  rA  r   )r   r   r  z%rz	ERROR: %s)r  KeyboardInterruptr   rg   r  r   rW   )r   msgr   r   r   main  s    
r  __main__)N)Nr   )NNr   F)N)rD  )FFF)r  r  rN  rI   r   r  r  rx   r   r2  r   r  xml.parsers.expatr  r   r   Z	GZIP_BASEImportErrorobjectr   r   r  r{   version_infoZPY25PLUSZPY26PLUSZPY32PLUSr[  Z
simplejsonxml.etree.ElementTreeetreeElementTreeru  r   Z
ET_Elementxml.domr   rz  r   urllib2r   r   r   r   r   r   r   r   r   r   urllib.requesthttplibr   r   http.clientr   r   r    queuer!   urllib.parser"   cgihashlibr#   argparser$   r  r%   r  r(   r  rU   r  r*   r  optparser&   r'   	cStringIOr+   r,   r   __builtin__builtinsr-   r.   r/   rW   rM   r`   rL   rJ   rK   rs  rF   rP   Elementiterr  getiteratorr  is_aliver  isAliver   CertificateErrorZ
CERT_ERRORrR   r  r   SSLErrorr   r  rg   ri   rj   rk   rl   rm   rn   ro   rp   rq   rr   rs   rt   ru   rv   rw   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r'  r+  r^  r  r  rT  r  r  r   r  r  r   r   r   r   r   <module>   s  



46



=


)"B

$
$
&60     Z
V
 #
