Compare commits

..

7 Commits

Author SHA1 Message Date
Matt Martz
5aa515e52c foo 2018-01-02 17:07:28 -06:00
Matt Martz
a75ee8e097 foo 2018-01-02 17:02:34 -06:00
Matt Martz
7e4f319ad4 foo 2018-01-02 16:48:38 -06:00
Matt Martz
18e5a38d32 foo 2018-01-02 16:41:54 -06:00
Matt Martz
5f6267a489 foo 2018-01-02 16:36:20 -06:00
Matt Martz
14e3a390bc foo 2018-01-02 16:30:20 -06:00
Matt Martz
bb9214fd0d testy 2018-01-02 16:25:30 -06:00
8 changed files with 96 additions and 169 deletions

View File

@ -42,12 +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 "(py26|py33)") != 0 ]]; then pip install virtualenv==15.2.0 tox==2.9.1; fi; - if [[ $(echo "$TOXENV" | egrep -c "(py2[45]|py3[12])") == 0 ]]; then pip install tox; fi;
- if [[ $(echo "$TOXENV" | egrep -c "(py2[456]|py3[123])") == 0 ]]; then pip install tox; fi;
script: script:
- ifconfig
- tox - tox
notifications: notifications:

View File

@ -1,7 +1,3 @@
#Usage
$ curl -s https://git.spectre5.com/adamcruz/speedtest-cli-pub/raw/branch/master/speedtest.py | python -
speedtest-cli speedtest-cli
============= =============
@ -11,9 +7,9 @@ speedtest.net
.. image:: https://img.shields.io/pypi/v/speedtest-cli.svg .. image:: https://img.shields.io/pypi/v/speedtest-cli.svg
:target: https://pypi.python.org/pypi/speedtest-cli/ :target: https://pypi.python.org/pypi/speedtest-cli/
:alt: Latest Version :alt: Latest Version
.. image:: https://img.shields.io/travis/sivel/speedtest-cli.svg .. image:: https://img.shields.io/pypi/dm/speedtest-cli.svg
:target: https://pypi.python.org/pypi/speedtest-cli/ :target: https://pypi.python.org/pypi/speedtest-cli/
:alt: Travis :alt: Downloads
.. image:: https://img.shields.io/pypi/l/speedtest-cli.svg .. image:: https://img.shields.io/pypi/l/speedtest-cli.svg
:target: https://pypi.python.org/pypi/speedtest-cli/ :target: https://pypi.python.org/pypi/speedtest-cli/
:alt: License :alt: License
@ -21,7 +17,7 @@ speedtest.net
Versions Versions
-------- --------
speedtest-cli works with Python 2.4-3.7 speedtest-cli works with Python 2.4-3.6
.. image:: https://img.shields.io/pypi/pyversions/speedtest-cli.svg .. image:: https://img.shields.io/pypi/pyversions/speedtest-cli.svg
:target: https://pypi.python.org/pypi/speedtest-cli/ :target: https://pypi.python.org/pypi/speedtest-cli/

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright 2012-2018 Matt Martz # Copyright 2012-2016 Matt Martz
# All Rights Reserved. # All Rights Reserved.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -66,7 +66,7 @@ setup(
author_email='matt@sivel.net', author_email='matt@sivel.net',
url='https://github.com/sivel/speedtest-cli', url='https://github.com/sivel/speedtest-cli',
license='Apache License, Version 2.0', license='Apache License, Version 2.0',
py_modules=['speedtest'], py_modules=['speedtest', 'speedtest_cli'],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [
'speedtest=speedtest:main', 'speedtest=speedtest:main',
@ -91,6 +91,5 @@ setup(
'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
] ]
) )

View File

@ -1,4 +1,4 @@
.TH "speedtest-cli" 1 "2018-01-05" "speedtest-cli" .TH "speedtest-cli" 1 "2014-04-23" "speedtest-cli"
.SH NAME .SH NAME
speedtest\-cli \- Command line interface for testing internet bandwidth using speedtest.net speedtest\-cli \- Command line interface for testing internet bandwidth using speedtest.net
.SH SYNOPSIS .SH SYNOPSIS
@ -23,24 +23,14 @@ Displays usage for the tool.
.B Options .B Options
\fB\-\-no\-download\fR
.RS
Do not perform download test
.RE
\fB\-\-no\-upload\fR
.RS
Do not perform upload test
.RE
\fB\-\-bytes\fR \fB\-\-bytes\fR
.RS .RS
Display values in bytes instead of bits. Does not affect the image generated by \-\-share, nor output from \-\-json or \-\-csv Display values in bytes instead of bits. Does not affect the image generated by \-\-share
.RE .RE
\fB\-\-share\fR \fB\-\-share\fR
.RS .RS
Generate and provide a URL to the speedtest.net share results image, not displayed with \-\-csv Generate and provide a URL to the speedtest.net share results image
.RE .RE
\fB\-\-simple\fR \fB\-\-simple\fR
@ -53,12 +43,12 @@ Suppress verbose output, only show basic information
Suppress verbose output, only show basic information in CSV format. Speeds listed in bit/s and not affected by \-\-bytes Suppress verbose output, only show basic information in CSV format. Speeds listed in bit/s and not affected by \-\-bytes
.RE .RE
\fB\-\-csv\-delimiter CSV_DELIMITER\fR \fB\-\-csv-delimiter CSV_DELIMITER\fR
.RS .RS
Single character delimiter to use in CSV output. Default "," Single character delimiter to use in CSV output. Default ","
.RE .RE
\fB\-\-csv\-header\fR \fB\-\-csv-header\fR
.RS .RS
Print CSV headers Print CSV headers
.RE .RE
@ -75,12 +65,7 @@ Display a list of speedtest.net servers sorted by distance
\fB\-\-server SERVER\fR \fB\-\-server SERVER\fR
.RS .RS
Specify a server ID to test against. Can be supplied multiple times Specify a server ID to test against
.RE
\fB\-\-exclude EXCLUDE\fR
.RS
Exclude a server from selection. Can be supplied multiple times
.RE .RE
\fB\-\-mini MINI\fR \fB\-\-mini MINI\fR
@ -103,11 +88,6 @@ HTTP timeout in seconds. Default 10
Use HTTPS instead of HTTP when communicating with speedtest.net operated servers Use HTTPS instead of HTTP when communicating with speedtest.net operated servers
.RE .RE
\fB\-\-no\-pre\-allocate\fR
.RS
Do 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
.RE
\fB\-\-version\fR \fB\-\-version\fR
.RS .RS
Show the version number and exit Show the version number and exit

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright 2012-2018 Matt Martz # Copyright 2012-2016 Matt Martz
# All Rights Reserved. # All Rights Reserved.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -36,7 +36,7 @@ except ImportError:
gzip = None gzip = None
GZIP_BASE = object GZIP_BASE = object
__version__ = '2.0.2' __version__ = '2.0.0a'
class FakeShutdownEvent(object): class FakeShutdownEvent(object):
@ -70,7 +70,6 @@ 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:
@ -85,9 +84,9 @@ except ImportError:
HTTPErrorProcessor, OpenerDirector) HTTPErrorProcessor, OpenerDirector)
try: try:
from httplib import HTTPConnection, BadStatusLine from httplib import HTTPConnection
except ImportError: except ImportError:
from http.client import HTTPConnection, BadStatusLine from http.client import HTTPConnection
try: try:
from httplib import HTTPSConnection from httplib import HTTPSConnection
@ -166,14 +165,8 @@ except ImportError:
self.flush() self.flush()
_py3_print = getattr(builtins, 'print') _py3_print = getattr(builtins, 'print')
try: _py3_utf8_stdout = _Py3Utf8Output(sys.stdout)
_py3_utf8_stdout = _Py3Utf8Output(sys.stdout) _py3_utf8_stderr = _Py3Utf8Output(sys.stderr)
_py3_utf8_stderr = _Py3Utf8Output(sys.stderr)
except OSError:
# sys.stdout/sys.stderr is not a compatible stdout/stderr object
# just use it and hope things go ok
_py3_utf8_stdout = sys.stdout
_py3_utf8_stderr = sys.stderr
def to_utf8(v): def to_utf8(v):
"""No-op encode to utf-8 for py3""" """No-op encode to utf-8 for py3"""
@ -266,13 +259,10 @@ try:
except AttributeError: except AttributeError:
CERT_ERROR = tuple() CERT_ERROR = tuple()
HTTP_ERRORS = ( HTTP_ERRORS = ((HTTPError, URLError, socket.error, ssl.SSLError) +
(HTTPError, URLError, socket.error, ssl.SSLError, BadStatusLine) + CERT_ERROR)
CERT_ERROR
)
except ImportError: except ImportError:
ssl = None HTTP_ERRORS = (HTTPError, URLError, socket.error)
HTTP_ERRORS = (HTTPError, URLError, socket.error, BadStatusLine)
class SpeedtestException(Exception): class SpeedtestException(Exception):
@ -288,11 +278,7 @@ class SpeedtestHTTPError(SpeedtestException):
class SpeedtestConfigError(SpeedtestException): class SpeedtestConfigError(SpeedtestException):
"""Configuration XML is invalid""" """Configuration provided is invalid"""
class SpeedtestServersError(SpeedtestException):
"""Servers XML is invalid"""
class ConfigRetrievalError(SpeedtestHTTPError): class ConfigRetrievalError(SpeedtestHTTPError):
@ -392,11 +378,13 @@ 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):
@ -421,28 +409,16 @@ 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 ssl: if hasattr(ssl, 'SSLContext'):
if hasattr(ssl, 'SSLContext'): kwargs['server_hostname'] = self.host
kwargs['server_hostname'] = self.host
try: self.sock = self._context.wrap_socket(self.sock, **kwargs)
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):
@ -1060,16 +1036,13 @@ 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_list = [] configxml = []
stream = get_response_stream(uh) stream = get_response_stream(uh)
while 1: while 1:
try: configxml.append(stream.read(1024))
configxml_list.append(stream.read(1024)) if len(configxml[-1]) == 0:
except (OSError, EOFError):
raise ConfigRetrievalError(get_exception())
if len(configxml_list[-1]) == 0:
break break
stream.close() stream.close()
uh.close() uh.close()
@ -1077,18 +1050,10 @@ class Speedtest(object):
if int(uh.code) != 200: if int(uh.code) != 200:
return None return None
configxml = ''.encode().join(configxml_list) printer('Config XML:\n%s' % ''.encode().join(configxml), debug=True)
printer('Config XML:\n%s' % configxml, debug=True)
try: try:
try: root = ET.fromstring(''.encode().join(configxml))
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
@ -1096,13 +1061,7 @@ class Speedtest(object):
client = root.find('client').attrib client = root.find('client').attrib
except AttributeError: except AttributeError:
try: root = DOM.parseString(''.join(configxml))
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')
@ -1151,13 +1110,7 @@ class Speedtest(object):
'upload_max': upload_count * size_count 'upload_max': upload_count * size_count
}) })
try: self.lat_lon = (float(client['lat']), float(client['lon']))
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)
@ -1211,13 +1164,10 @@ class Speedtest(object):
stream = get_response_stream(uh) stream = get_response_stream(uh)
serversxml_list = [] serversxml = []
while 1: while 1:
try: serversxml.append(stream.read(1024))
serversxml_list.append(stream.read(1024)) if len(serversxml[-1]) == 0:
except (OSError, EOFError):
raise ServersRetrievalError(get_exception())
if len(serversxml_list[-1]) == 0:
break break
stream.close() stream.close()
@ -1226,28 +1176,15 @@ class Speedtest(object):
if int(uh.code) != 200: if int(uh.code) != 200:
raise ServersRetrievalError() raise ServersRetrievalError()
serversxml = ''.encode().join(serversxml_list) printer('Servers XML:\n%s' % ''.encode().join(serversxml),
debug=True)
printer('Servers XML:\n%s' % serversxml, debug=True)
try: try:
try: try:
try: root = ET.fromstring(''.encode().join(serversxml))
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:
try: root = DOM.parseString(''.join(serversxml))
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()
@ -1584,7 +1521,7 @@ def ctrl_c(shutdown_event):
""" """
def inner(signum, frame): def inner(signum, frame):
shutdown_event.set() shutdown_event.set()
printer('\nCancelling...', error=True) print_('\nCancelling...')
sys.exit(0) sys.exit(0)
return inner return inner
@ -1592,14 +1529,14 @@ def ctrl_c(shutdown_event):
def version(): def version():
"""Print the version""" """Print the version"""
printer(__version__) print_(__version__)
sys.exit(0) sys.exit(0)
def csv_header(delimiter=','): def csv_header(delimiter=','):
"""Print the CSV Headers""" """Print the CSV Headers"""
printer(SpeedtestResults.csv_header(delimiter=delimiter)) print_(SpeedtestResults.csv_header(delimiter=delimiter))
sys.exit(0) sys.exit(0)
@ -1704,16 +1641,13 @@ def validate_optional_args(args):
def printer(string, quiet=False, debug=False, error=False, **kwargs): def printer(string, quiet=False, debug=False, error=False, **kwargs):
"""Helper function print a string with various features""" """Helper function to print a string only when not quiet"""
if debug and not DEBUG: if debug and not DEBUG:
return return
if debug: if debug:
if sys.stdout.isatty(): out = '\033[1;30mDEBUG: %s\033[0m' % string
out = '\033[1;30mDEBUG: %s\033[0m' % string
else:
out = 'DEBUG: %s' % string
else: else:
out = string out = string
@ -1795,7 +1729,7 @@ def shell():
line = ('%(id)5s) %(sponsor)s (%(name)s, %(country)s) ' line = ('%(id)5s) %(sponsor)s (%(name)s, %(country)s) '
'[%(d)0.2f km]' % server) '[%(d)0.2f km]' % server)
try: try:
printer(line) print_(line)
except IOError: except IOError:
e = get_exception() e = get_exception()
if e.errno != errno.EPIPE: if e.errno != errno.EPIPE:
@ -1860,20 +1794,19 @@ 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' % print_('Ping: %s ms\nDownload: %0.2f M%s/s\nUpload: %0.2f M%s/s' %
(results.ping, (results.ping,
(results.download / 1000.0 / 1000.0) / args.units[1], (results.download / 1000.0 / 1000.0) / args.units[1],
args.units[0], args.units[0],
(results.upload / 1000.0 / 1000.0) / args.units[1], (results.upload / 1000.0 / 1000.0) / args.units[1],
args.units[0])) args.units[0]))
elif args.csv: elif args.csv:
printer(results.csv(delimiter=args.csv_delimiter)) print_(results.csv(delimiter=args.csv_delimiter))
elif args.json: elif args.json:
printer(results.json()) if args.share:
results.share()
print_(results.json())
if args.share and not machine_format: if args.share and not machine_format:
printer('Share results: %s' % results.share()) printer('Share results: %s' % results.share())
@ -1883,7 +1816,7 @@ def main():
try: try:
shell() shell()
except KeyboardInterrupt: except KeyboardInterrupt:
printer('\nCancelling...', error=True) print_('\nCancelling...')
except (SpeedtestException, SystemExit): except (SpeedtestException, SystemExit):
e = get_exception() e = get_exception()
# Ignore a successful exit, or argparse exit # Ignore a successful exit, or argparse exit

34
speedtest_cli.py Normal file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright 2012-2016 Matt Martz
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import warnings
DEPRECATED_MSG = ('The file speedtest_cli.py has been deprecated in favor of '
'speedtest.py\nand is available for download at:\n\n'
'https://raw.githubusercontent.com/sivel/speedtest-cli/'
'master/speedtest.py')
if __name__ == '__main__':
raise SystemExit(DEPRECATED_MSG)
else:
try:
from speedtest import *
except ImportError:
raise SystemExit(DEPRECATED_MSG)
else:
warnings.warn(DEPRECATED_MSG, UserWarning)

View File

@ -1,19 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright 2018 Matt Martz
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sys import sys
import subprocess import subprocess

View File

@ -2,6 +2,7 @@
skipsdist=true skipsdist=true
[testenv] [testenv]
whitelist_externals = bash
commands = commands =
{envpython} -V {envpython} -V
{envpython} -m compileall speedtest.py {envpython} -m compileall speedtest.py
@ -17,6 +18,7 @@ commands =
flake8 speedtest.py flake8 speedtest.py
[testenv:pypy] [testenv:pypy]
whitelist_externals = bash
commands = commands =
pypy -V pypy -V
pypy -m compileall speedtest.py pypy -m compileall speedtest.py