Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e715ef3008 | ||
|
|
9384255634 | ||
|
|
72ed585c6f | ||
|
|
41e599f9c3 | ||
|
|
c7530bb143 | ||
|
|
4ceae77401 | ||
|
|
9e185e8f88 | ||
|
|
9c2977acfc | ||
|
|
f8aa20ecdf | ||
|
|
8ff923b0fb | ||
|
|
35c3ee20ed |
@ -42,7 +42,10 @@ before_install:
|
|||||||
install:
|
install:
|
||||||
- if [[ $(echo "$TOXENV" | egrep -c "py32") != 0 ]]; then pip install setuptools==17.1.1; fi;
|
- if [[ $(echo "$TOXENV" | egrep -c "py32") != 0 ]]; then pip install setuptools==17.1.1; fi;
|
||||||
- if [[ $(echo "$TOXENV" | egrep -c "(py2[45]|py3[12])") != 0 ]]; then pip install virtualenv==1.7.2 tox==1.3; fi;
|
- if [[ $(echo "$TOXENV" | egrep -c "(py2[45]|py3[12])") != 0 ]]; then pip install virtualenv==1.7.2 tox==1.3; fi;
|
||||||
- if [[ $(echo "$TOXENV" | egrep -c "(py2[45]|py3[12])") == 0 ]]; then pip install tox; fi;
|
- if [[ $(echo "$TOXENV" | egrep -c "(py26|py33)") != 0 ]]; then pip install virtualenv==15.2.0 tox==2.9.1; fi;
|
||||||
|
- if [[ $(echo "$TOXENV" | egrep -c "(py2[456]|py3[123])") == 0 ]]; then pip install tox; fi;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- tox
|
- tox
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
|
#Usage
|
||||||
|
|
||||||
|
$ curl -s https://git.spectre5.com/adamcruz/speedtest-cli-pub/raw/branch/master/speedtest.py | python -
|
||||||
|
|
||||||
speedtest-cli
|
speedtest-cli
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|||||||
110
speedtest.py
110
speedtest.py
@ -36,7 +36,7 @@ except ImportError:
|
|||||||
gzip = None
|
gzip = None
|
||||||
GZIP_BASE = object
|
GZIP_BASE = object
|
||||||
|
|
||||||
__version__ = '2.0.0'
|
__version__ = '2.0.2'
|
||||||
|
|
||||||
|
|
||||||
class FakeShutdownEvent(object):
|
class FakeShutdownEvent(object):
|
||||||
@ -70,6 +70,7 @@ except ImportError:
|
|||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from xml.dom import minidom as DOM
|
from xml.dom import minidom as DOM
|
||||||
|
from xml.parsers.expat import ExpatError
|
||||||
ET = None
|
ET = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -84,9 +85,9 @@ except ImportError:
|
|||||||
HTTPErrorProcessor, OpenerDirector)
|
HTTPErrorProcessor, OpenerDirector)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from httplib import HTTPConnection
|
from httplib import HTTPConnection, BadStatusLine
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from http.client import HTTPConnection
|
from http.client import HTTPConnection, BadStatusLine
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from httplib import HTTPSConnection
|
from httplib import HTTPSConnection
|
||||||
@ -265,10 +266,13 @@ try:
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
CERT_ERROR = tuple()
|
CERT_ERROR = tuple()
|
||||||
|
|
||||||
HTTP_ERRORS = ((HTTPError, URLError, socket.error, ssl.SSLError) +
|
HTTP_ERRORS = (
|
||||||
CERT_ERROR)
|
(HTTPError, URLError, socket.error, ssl.SSLError, BadStatusLine) +
|
||||||
|
CERT_ERROR
|
||||||
|
)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HTTP_ERRORS = (HTTPError, URLError, socket.error)
|
ssl = None
|
||||||
|
HTTP_ERRORS = (HTTPError, URLError, socket.error, BadStatusLine)
|
||||||
|
|
||||||
|
|
||||||
class SpeedtestException(Exception):
|
class SpeedtestException(Exception):
|
||||||
@ -284,7 +288,11 @@ class SpeedtestHTTPError(SpeedtestException):
|
|||||||
|
|
||||||
|
|
||||||
class SpeedtestConfigError(SpeedtestException):
|
class SpeedtestConfigError(SpeedtestException):
|
||||||
"""Configuration provided is invalid"""
|
"""Configuration XML is invalid"""
|
||||||
|
|
||||||
|
|
||||||
|
class SpeedtestServersError(SpeedtestException):
|
||||||
|
"""Servers XML is invalid"""
|
||||||
|
|
||||||
|
|
||||||
class ConfigRetrievalError(SpeedtestHTTPError):
|
class ConfigRetrievalError(SpeedtestHTTPError):
|
||||||
@ -384,13 +392,11 @@ class SpeedtestHTTPConnection(HTTPConnection):
|
|||||||
"""
|
"""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
source_address = kwargs.pop('source_address', None)
|
source_address = kwargs.pop('source_address', None)
|
||||||
context = kwargs.pop('context', None)
|
|
||||||
timeout = kwargs.pop('timeout', 10)
|
timeout = kwargs.pop('timeout', 10)
|
||||||
|
|
||||||
HTTPConnection.__init__(self, *args, **kwargs)
|
HTTPConnection.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
self.source_address = source_address
|
self.source_address = source_address
|
||||||
self._context = context
|
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
@ -415,16 +421,28 @@ if HTTPSConnection:
|
|||||||
"""Custom HTTPSConnection to support source_address across
|
"""Custom HTTPSConnection to support source_address across
|
||||||
Python 2.4 - Python 3
|
Python 2.4 - Python 3
|
||||||
"""
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
source_address = kwargs.pop('source_address', None)
|
||||||
|
timeout = kwargs.pop('timeout', 10)
|
||||||
|
|
||||||
|
HTTPSConnection.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
self.timeout = timeout
|
||||||
|
self.source_address = source_address
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
"Connect to a host on a given (SSL) port."
|
"Connect to a host on a given (SSL) port."
|
||||||
|
|
||||||
SpeedtestHTTPConnection.connect(self)
|
SpeedtestHTTPConnection.connect(self)
|
||||||
|
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
if hasattr(ssl, 'SSLContext'):
|
if ssl:
|
||||||
kwargs['server_hostname'] = self.host
|
if hasattr(ssl, 'SSLContext'):
|
||||||
|
kwargs['server_hostname'] = self.host
|
||||||
self.sock = self._context.wrap_socket(self.sock, **kwargs)
|
try:
|
||||||
|
self.sock = self._context.wrap_socket(self.sock, **kwargs)
|
||||||
|
except AttributeError:
|
||||||
|
self.sock = ssl.wrap_socket(self.sock, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def _build_connection(connection, source_address, timeout, context=None):
|
def _build_connection(connection, source_address, timeout, context=None):
|
||||||
@ -1042,16 +1060,16 @@ class Speedtest(object):
|
|||||||
uh, e = catch_request(request, opener=self._opener)
|
uh, e = catch_request(request, opener=self._opener)
|
||||||
if e:
|
if e:
|
||||||
raise ConfigRetrievalError(e)
|
raise ConfigRetrievalError(e)
|
||||||
configxml = []
|
configxml_list = []
|
||||||
|
|
||||||
stream = get_response_stream(uh)
|
stream = get_response_stream(uh)
|
||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
try:
|
try:
|
||||||
configxml.append(stream.read(1024))
|
configxml_list.append(stream.read(1024))
|
||||||
except (OSError, EOFError):
|
except (OSError, EOFError):
|
||||||
raise ConfigRetrievalError(get_exception())
|
raise ConfigRetrievalError(get_exception())
|
||||||
if len(configxml[-1]) == 0:
|
if len(configxml_list[-1]) == 0:
|
||||||
break
|
break
|
||||||
stream.close()
|
stream.close()
|
||||||
uh.close()
|
uh.close()
|
||||||
@ -1059,10 +1077,18 @@ class Speedtest(object):
|
|||||||
if int(uh.code) != 200:
|
if int(uh.code) != 200:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
printer('Config XML:\n%s' % ''.encode().join(configxml), debug=True)
|
configxml = ''.encode().join(configxml_list)
|
||||||
|
|
||||||
|
printer('Config XML:\n%s' % configxml, debug=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
root = ET.fromstring(''.encode().join(configxml))
|
try:
|
||||||
|
root = ET.fromstring(configxml)
|
||||||
|
except ET.ParseError:
|
||||||
|
e = get_exception()
|
||||||
|
raise SpeedtestConfigError(
|
||||||
|
'Malformed speedtest.net configuration: %s' % e
|
||||||
|
)
|
||||||
server_config = root.find('server-config').attrib
|
server_config = root.find('server-config').attrib
|
||||||
download = root.find('download').attrib
|
download = root.find('download').attrib
|
||||||
upload = root.find('upload').attrib
|
upload = root.find('upload').attrib
|
||||||
@ -1070,7 +1096,13 @@ class Speedtest(object):
|
|||||||
client = root.find('client').attrib
|
client = root.find('client').attrib
|
||||||
|
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
root = DOM.parseString(''.join(configxml))
|
try:
|
||||||
|
root = DOM.parseString(configxml)
|
||||||
|
except ExpatError:
|
||||||
|
e = get_exception()
|
||||||
|
raise SpeedtestConfigError(
|
||||||
|
'Malformed speedtest.net configuration: %s' % e
|
||||||
|
)
|
||||||
server_config = get_attributes_by_tag_name(root, 'server-config')
|
server_config = get_attributes_by_tag_name(root, 'server-config')
|
||||||
download = get_attributes_by_tag_name(root, 'download')
|
download = get_attributes_by_tag_name(root, 'download')
|
||||||
upload = get_attributes_by_tag_name(root, 'upload')
|
upload = get_attributes_by_tag_name(root, 'upload')
|
||||||
@ -1119,7 +1151,13 @@ class Speedtest(object):
|
|||||||
'upload_max': upload_count * size_count
|
'upload_max': upload_count * size_count
|
||||||
})
|
})
|
||||||
|
|
||||||
self.lat_lon = (float(client['lat']), float(client['lon']))
|
try:
|
||||||
|
self.lat_lon = (float(client['lat']), float(client['lon']))
|
||||||
|
except ValueError:
|
||||||
|
raise SpeedtestConfigError(
|
||||||
|
'Unknown location: lat=%r lon=%r' %
|
||||||
|
(client.get('lat'), client.get('lon'))
|
||||||
|
)
|
||||||
|
|
||||||
printer('Config:\n%r' % self.config, debug=True)
|
printer('Config:\n%r' % self.config, debug=True)
|
||||||
|
|
||||||
@ -1173,13 +1211,13 @@ class Speedtest(object):
|
|||||||
|
|
||||||
stream = get_response_stream(uh)
|
stream = get_response_stream(uh)
|
||||||
|
|
||||||
serversxml = []
|
serversxml_list = []
|
||||||
while 1:
|
while 1:
|
||||||
try:
|
try:
|
||||||
serversxml.append(stream.read(1024))
|
serversxml_list.append(stream.read(1024))
|
||||||
except (OSError, EOFError):
|
except (OSError, EOFError):
|
||||||
raise ServersRetrievalError(get_exception())
|
raise ServersRetrievalError(get_exception())
|
||||||
if len(serversxml[-1]) == 0:
|
if len(serversxml_list[-1]) == 0:
|
||||||
break
|
break
|
||||||
|
|
||||||
stream.close()
|
stream.close()
|
||||||
@ -1188,15 +1226,28 @@ class Speedtest(object):
|
|||||||
if int(uh.code) != 200:
|
if int(uh.code) != 200:
|
||||||
raise ServersRetrievalError()
|
raise ServersRetrievalError()
|
||||||
|
|
||||||
printer('Servers XML:\n%s' % ''.encode().join(serversxml),
|
serversxml = ''.encode().join(serversxml_list)
|
||||||
debug=True)
|
|
||||||
|
printer('Servers XML:\n%s' % serversxml, debug=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
root = ET.fromstring(''.encode().join(serversxml))
|
try:
|
||||||
|
root = ET.fromstring(serversxml)
|
||||||
|
except ET.ParseError:
|
||||||
|
e = get_exception()
|
||||||
|
raise SpeedtestServersError(
|
||||||
|
'Malformed speedtest.net server list: %s' % e
|
||||||
|
)
|
||||||
elements = root.getiterator('server')
|
elements = root.getiterator('server')
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
root = DOM.parseString(''.join(serversxml))
|
try:
|
||||||
|
root = DOM.parseString(serversxml)
|
||||||
|
except ExpatError:
|
||||||
|
e = get_exception()
|
||||||
|
raise SpeedtestServersError(
|
||||||
|
'Malformed speedtest.net server list: %s' % e
|
||||||
|
)
|
||||||
elements = root.getElementsByTagName('server')
|
elements = root.getElementsByTagName('server')
|
||||||
except (SyntaxError, xml.parsers.expat.ExpatError):
|
except (SyntaxError, xml.parsers.expat.ExpatError):
|
||||||
raise ServersRetrievalError()
|
raise ServersRetrievalError()
|
||||||
@ -1809,6 +1860,9 @@ def shell():
|
|||||||
|
|
||||||
printer('Results:\n%r' % results.dict(), debug=True)
|
printer('Results:\n%r' % results.dict(), debug=True)
|
||||||
|
|
||||||
|
if not args.simple and args.share:
|
||||||
|
results.share()
|
||||||
|
|
||||||
if args.simple:
|
if args.simple:
|
||||||
printer('Ping: %s ms\nDownload: %0.2f M%s/s\nUpload: %0.2f M%s/s' %
|
printer('Ping: %s ms\nDownload: %0.2f M%s/s\nUpload: %0.2f M%s/s' %
|
||||||
(results.ping,
|
(results.ping,
|
||||||
@ -1819,8 +1873,6 @@ def shell():
|
|||||||
elif args.csv:
|
elif args.csv:
|
||||||
printer(results.csv(delimiter=args.csv_delimiter))
|
printer(results.csv(delimiter=args.csv_delimiter))
|
||||||
elif args.json:
|
elif args.json:
|
||||||
if args.share:
|
|
||||||
results.share()
|
|
||||||
printer(results.json())
|
printer(results.json())
|
||||||
|
|
||||||
if args.share and not machine_format:
|
if args.share and not machine_format:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user