speedtest-cli-ng 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- speedtest_cli_ng-0.3.0/.gitignore +220 -0
- {speedtest_cli_ng-0.2.0/speedtest_cli_ng.egg-info → speedtest_cli_ng-0.3.0}/PKG-INFO +17 -13
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0}/README.md +6 -4
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0}/pyproject.toml +46 -35
- speedtest_cli_ng-0.3.0/src/speedtest/__init__.py +3 -0
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0/src}/speedtest/__main__.py +8 -11
- speedtest_cli_ng-0.3.0/src/speedtest/__version__.py +5 -0
- speedtest_cli_ng-0.3.0/src/speedtest/cli/__init__.py +7 -0
- speedtest_cli_ng-0.3.0/src/speedtest/cli/display.py +69 -0
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0/src}/speedtest/cli/parser.py +2 -8
- speedtest_cli_ng-0.3.0/src/speedtest/cli/runner.py +107 -0
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0/src}/speedtest/client.py +14 -18
- speedtest_cli_ng-0.3.0/src/speedtest/engine/__init__.py +30 -0
- speedtest_cli_ng-0.3.0/src/speedtest/engine/config.py +72 -0
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0/src}/speedtest/engine/network.py +30 -34
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0/src}/speedtest/engine/servers.py +10 -14
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0/src}/speedtest/engine/transfer.py +41 -27
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0/src}/speedtest/exceptions.py +10 -10
- speedtest_cli_ng-0.3.0/src/speedtest/models/__init__.py +17 -0
- speedtest_cli_ng-0.2.0/speedtest/models/config.py → speedtest_cli_ng-0.3.0/src/speedtest/models/api_config.py +3 -2
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0/src}/speedtest/models/context.py +17 -5
- speedtest_cli_ng-0.3.0/src/speedtest/models/location.py +25 -0
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0/src}/speedtest/models/result.py +2 -2
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0/src}/speedtest/models/server.py +3 -26
- speedtest_cli_ng-0.3.0/src/speedtest/utils/__init__.py +9 -0
- speedtest_cli_ng-0.3.0/src/speedtest/utils/constants.py +7 -0
- speedtest_cli_ng-0.3.0/src/speedtest/utils/logger.py +41 -0
- speedtest_cli_ng-0.3.0/tests/cli/test_display.py +93 -0
- speedtest_cli_ng-0.3.0/tests/cli/test_parser.py +84 -0
- speedtest_cli_ng-0.3.0/tests/cli/test_runner.py +167 -0
- speedtest_cli_ng-0.3.0/tests/conftest.py +88 -0
- speedtest_cli_ng-0.3.0/tests/engine/test_config.py +114 -0
- speedtest_cli_ng-0.3.0/tests/models/test_api_config.py +66 -0
- speedtest_cli_ng-0.3.0/tests/models/test_context.py +107 -0
- speedtest_cli_ng-0.3.0/tests/models/test_location.py +53 -0
- speedtest_cli_ng-0.3.0/tests/models/test_result.py +90 -0
- speedtest_cli_ng-0.3.0/tests/models/test_server.py +80 -0
- speedtest_cli_ng-0.3.0/tests/test_main.py +81 -0
- speedtest_cli_ng-0.3.0/tests/utils/test_logger.py +88 -0
- speedtest_cli_ng-0.3.0/uv.lock +303 -0
- speedtest_cli_ng-0.2.0/PKG-INFO +0 -162
- speedtest_cli_ng-0.2.0/extras/man/speedtest-cli.1 +0 -103
- speedtest_cli_ng-0.2.0/setup.cfg +0 -4
- speedtest_cli_ng-0.2.0/speedtest/__init__.py +0 -15
- speedtest_cli_ng-0.2.0/speedtest/cli/commands.py +0 -26
- speedtest_cli_ng-0.2.0/speedtest/cli/main.py +0 -103
- speedtest_cli_ng-0.2.0/speedtest/cli/output.py +0 -62
- speedtest_cli_ng-0.2.0/speedtest/engine/__init__.py +0 -0
- speedtest_cli_ng-0.2.0/speedtest/engine/config.py +0 -50
- speedtest_cli_ng-0.2.0/speedtest/models/__init__.py +0 -12
- speedtest_cli_ng-0.2.0/speedtest/utils/__init__.py +0 -0
- speedtest_cli_ng-0.2.0/speedtest/utils/logger.py +0 -91
- speedtest_cli_ng-0.2.0/speedtest_cli_ng.egg-info/SOURCES.txt +0 -32
- speedtest_cli_ng-0.2.0/speedtest_cli_ng.egg-info/dependency_links.txt +0 -1
- speedtest_cli_ng-0.2.0/speedtest_cli_ng.egg-info/entry_points.txt +0 -3
- speedtest_cli_ng-0.2.0/speedtest_cli_ng.egg-info/top_level.txt +0 -1
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0}/LICENSE +0 -0
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0}/NOTICE +0 -0
- {speedtest_cli_ng-0.2.0 → speedtest_cli_ng-0.3.0/src}/speedtest/utils/status.py +0 -0
- {speedtest_cli_ng-0.2.0/speedtest/cli → speedtest_cli_ng-0.3.0/tests}/__init__.py +0 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by an python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
*.lcov
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
cover/
|
|
54
|
+
|
|
55
|
+
# Translations
|
|
56
|
+
*.mo
|
|
57
|
+
*.pot
|
|
58
|
+
|
|
59
|
+
# Django stuff:
|
|
60
|
+
*.log
|
|
61
|
+
local_settings.py
|
|
62
|
+
db.sqlite3
|
|
63
|
+
db.sqlite3-journal
|
|
64
|
+
|
|
65
|
+
# Flask stuff:
|
|
66
|
+
instance/
|
|
67
|
+
.webassets-cache
|
|
68
|
+
|
|
69
|
+
# Scrapy stuff:
|
|
70
|
+
.scrapy
|
|
71
|
+
|
|
72
|
+
# Sphinx documentation
|
|
73
|
+
docs/_build/
|
|
74
|
+
|
|
75
|
+
# PyBuilder
|
|
76
|
+
.pybuilder/
|
|
77
|
+
target/
|
|
78
|
+
|
|
79
|
+
# Jupyter Notebook
|
|
80
|
+
.ipynb_checkpoints
|
|
81
|
+
|
|
82
|
+
# IPython
|
|
83
|
+
profile_default/
|
|
84
|
+
ipython_config.py
|
|
85
|
+
|
|
86
|
+
# pyenv
|
|
87
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
88
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
89
|
+
# .python-version
|
|
90
|
+
|
|
91
|
+
# pipenv
|
|
92
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
93
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
94
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
95
|
+
# install all needed dependencies.
|
|
96
|
+
# Pipfile.lock
|
|
97
|
+
|
|
98
|
+
# UV
|
|
99
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
100
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
101
|
+
# commonly ignored for libraries.
|
|
102
|
+
# uv.lock
|
|
103
|
+
|
|
104
|
+
# poetry
|
|
105
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
106
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
107
|
+
# commonly ignored for libraries.
|
|
108
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
109
|
+
# poetry.lock
|
|
110
|
+
# poetry.toml
|
|
111
|
+
|
|
112
|
+
# pdm
|
|
113
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
114
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
115
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
116
|
+
# pdm.lock
|
|
117
|
+
# pdm.toml
|
|
118
|
+
.pdm-python
|
|
119
|
+
.pdm-build/
|
|
120
|
+
|
|
121
|
+
# pixi
|
|
122
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
123
|
+
# pixi.lock
|
|
124
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
125
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
126
|
+
.pixi/*
|
|
127
|
+
!.pixi/config.toml
|
|
128
|
+
|
|
129
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
130
|
+
__pypackages__/
|
|
131
|
+
|
|
132
|
+
# Celery stuff
|
|
133
|
+
celerybeat-schedule*
|
|
134
|
+
celerybeat.pid
|
|
135
|
+
|
|
136
|
+
# Redis
|
|
137
|
+
*.rdb
|
|
138
|
+
*.aof
|
|
139
|
+
*.pid
|
|
140
|
+
|
|
141
|
+
# RabbitMQ
|
|
142
|
+
mnesia/
|
|
143
|
+
rabbitmq/
|
|
144
|
+
rabbitmq-data/
|
|
145
|
+
|
|
146
|
+
# ActiveMQ
|
|
147
|
+
activemq-data/
|
|
148
|
+
|
|
149
|
+
# SageMath parsed files
|
|
150
|
+
*.sage.py
|
|
151
|
+
|
|
152
|
+
# Environments
|
|
153
|
+
.env
|
|
154
|
+
.envrc
|
|
155
|
+
.venv
|
|
156
|
+
env/
|
|
157
|
+
venv/
|
|
158
|
+
ENV/
|
|
159
|
+
env.bak/
|
|
160
|
+
venv.bak/
|
|
161
|
+
|
|
162
|
+
# Spyder project settings
|
|
163
|
+
.spyderproject
|
|
164
|
+
.spyproject
|
|
165
|
+
|
|
166
|
+
# Rope project settings
|
|
167
|
+
.ropeproject
|
|
168
|
+
|
|
169
|
+
# mkdocs documentation
|
|
170
|
+
/site
|
|
171
|
+
|
|
172
|
+
# mypy
|
|
173
|
+
.mypy_cache/
|
|
174
|
+
.dmypy.json
|
|
175
|
+
dmypy.json
|
|
176
|
+
|
|
177
|
+
# Pyre type checker
|
|
178
|
+
.pyre/
|
|
179
|
+
|
|
180
|
+
# pytype static type analyzer
|
|
181
|
+
.pytype/
|
|
182
|
+
|
|
183
|
+
# Cython debug symbols
|
|
184
|
+
cython_debug/
|
|
185
|
+
|
|
186
|
+
# PyCharm
|
|
187
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
188
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
189
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
190
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
191
|
+
# .idea/
|
|
192
|
+
|
|
193
|
+
# Abstra
|
|
194
|
+
# Abstra is an AI-powered process automation framework.
|
|
195
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
196
|
+
# Learn more at https://abstra.io/docs
|
|
197
|
+
.abstra/
|
|
198
|
+
|
|
199
|
+
# Visual Studio Code
|
|
200
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
201
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
202
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
203
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
204
|
+
# .vscode/
|
|
205
|
+
# Temporary file for partial code execution
|
|
206
|
+
tempCodeRunnerFile.py
|
|
207
|
+
|
|
208
|
+
# Ruff stuff:
|
|
209
|
+
.ruff_cache/
|
|
210
|
+
|
|
211
|
+
# PyPI configuration file
|
|
212
|
+
.pypirc
|
|
213
|
+
|
|
214
|
+
# Marimo
|
|
215
|
+
marimo/_static/
|
|
216
|
+
marimo/_lsp/
|
|
217
|
+
__marimo__/
|
|
218
|
+
|
|
219
|
+
# Streamlit
|
|
220
|
+
.streamlit/secrets.toml
|
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: speedtest-cli-ng
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Next generation CLI for testing internet bandwidth using speedtest.net
|
|
5
|
-
Author-email: Michał Korczak <git@omikor.in>
|
|
6
|
-
License-Expression: Apache-2.0
|
|
7
5
|
Project-URL: Homepage, https://github.com/Omikorin/speedtest-cli
|
|
8
6
|
Project-URL: Source, https://github.com/Omikorin/speedtest-cli
|
|
9
7
|
Project-URL: Issues, https://github.com/Omikorin/speedtest-cli/issues
|
|
10
|
-
|
|
8
|
+
Author-email: Michał Korczak <git@omikor.in>
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
License-File: NOTICE
|
|
12
|
+
Keywords: bandwidth,cli,internet,speedtest,speedtest.net
|
|
11
13
|
Classifier: Development Status :: 4 - Beta
|
|
12
14
|
Classifier: Environment :: Console
|
|
13
15
|
Classifier: Intended Audience :: Developers
|
|
14
16
|
Classifier: Intended Audience :: System Administrators
|
|
15
17
|
Classifier: Operating System :: OS Independent
|
|
16
|
-
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
17
20
|
Classifier: Topic :: Internet :: WWW/HTTP
|
|
18
21
|
Classifier: Topic :: System :: Networking
|
|
19
22
|
Classifier: Topic :: Terminals
|
|
20
23
|
Classifier: Topic :: Utilities
|
|
21
|
-
Requires-Python: >=3.
|
|
24
|
+
Requires-Python: >=3.14
|
|
25
|
+
Requires-Dist: httpx2<3,>=2.5.0
|
|
26
|
+
Requires-Dist: rich<16,>=15.0.0
|
|
22
27
|
Description-Content-Type: text/markdown
|
|
23
|
-
License-File: LICENSE
|
|
24
|
-
License-File: NOTICE
|
|
25
|
-
Dynamic: license-file
|
|
26
28
|
|
|
27
29
|
# speedtest-cli
|
|
28
30
|
|
|
@@ -32,9 +34,11 @@ Dynamic: license-file
|
|
|
32
34
|
[](https://github.com/Omikorin/speedtest-cli/actions/workflows/ci.yml)
|
|
33
35
|
[](https://sonarcloud.io/summary/new_code?id=Omikorin_speedtest-cli)
|
|
34
36
|
|
|
37
|
+
---
|
|
38
|
+
|
|
35
39
|
Next generation CLI for testing internet bandwidth using speedtest.net
|
|
36
40
|
|
|
37
|
-
Rebuilt for modern Python 3.
|
|
41
|
+
Rebuilt for modern Python 3.14+
|
|
38
42
|
|
|
39
43
|
## Getting started
|
|
40
44
|
|
|
@@ -110,7 +114,7 @@ Miscellaneous Options:
|
|
|
110
114
|
|
|
111
115
|
### Requirements
|
|
112
116
|
|
|
113
|
-
- Python 3.
|
|
117
|
+
- Python 3.14+
|
|
114
118
|
- uv 0.11+
|
|
115
119
|
|
|
116
120
|
### Setup project
|
|
@@ -131,7 +135,7 @@ uv run ruff format --check .
|
|
|
131
135
|
uv run ruff check .
|
|
132
136
|
|
|
133
137
|
# Run typecheck
|
|
134
|
-
uv run
|
|
138
|
+
uv run ty check
|
|
135
139
|
|
|
136
140
|
# Run tests
|
|
137
141
|
uv run pytest
|
|
@@ -153,7 +157,7 @@ This project is a heavily refactored and modernized fork of the original [speedt
|
|
|
153
157
|
|
|
154
158
|
## License
|
|
155
159
|
|
|
156
|
-
This project is licensed
|
|
160
|
+
This project is licensed under the terms of the [Apache License 2.0](https://github.com/Omikorin/speedtest-cli/blob/main/LICENSE).
|
|
157
161
|
|
|
158
162
|
---
|
|
159
163
|
|
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
[](https://github.com/Omikorin/speedtest-cli/actions/workflows/ci.yml)
|
|
7
7
|
[](https://sonarcloud.io/summary/new_code?id=Omikorin_speedtest-cli)
|
|
8
8
|
|
|
9
|
+
---
|
|
10
|
+
|
|
9
11
|
Next generation CLI for testing internet bandwidth using speedtest.net
|
|
10
12
|
|
|
11
|
-
Rebuilt for modern Python 3.
|
|
13
|
+
Rebuilt for modern Python 3.14+
|
|
12
14
|
|
|
13
15
|
## Getting started
|
|
14
16
|
|
|
@@ -84,7 +86,7 @@ Miscellaneous Options:
|
|
|
84
86
|
|
|
85
87
|
### Requirements
|
|
86
88
|
|
|
87
|
-
- Python 3.
|
|
89
|
+
- Python 3.14+
|
|
88
90
|
- uv 0.11+
|
|
89
91
|
|
|
90
92
|
### Setup project
|
|
@@ -105,7 +107,7 @@ uv run ruff format --check .
|
|
|
105
107
|
uv run ruff check .
|
|
106
108
|
|
|
107
109
|
# Run typecheck
|
|
108
|
-
uv run
|
|
110
|
+
uv run ty check
|
|
109
111
|
|
|
110
112
|
# Run tests
|
|
111
113
|
uv run pytest
|
|
@@ -127,7 +129,7 @@ This project is a heavily refactored and modernized fork of the original [speedt
|
|
|
127
129
|
|
|
128
130
|
## License
|
|
129
131
|
|
|
130
|
-
This project is licensed
|
|
132
|
+
This project is licensed under the terms of the [Apache License 2.0](https://github.com/Omikorin/speedtest-cli/blob/main/LICENSE).
|
|
131
133
|
|
|
132
134
|
---
|
|
133
135
|
|
|
@@ -1,33 +1,44 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["
|
|
3
|
-
build-backend = "
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "speedtest-cli-ng"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
{name = "Michał Korczak", email = "git@omikor.in"}
|
|
10
|
-
# TODO: I'm not sure whether I should put the old author because of possible spam for him unknowingly etc
|
|
11
|
-
# {name = "Matt Martz", email = "matt@sivel.net"}
|
|
12
|
-
]
|
|
7
|
+
description = "Next generation CLI for testing internet bandwidth using speedtest.net"
|
|
8
|
+
keywords = ["speedtest", "speedtest.net", "bandwidth", "internet", "cli"]
|
|
13
9
|
license = "Apache-2.0"
|
|
10
|
+
version = "0.3.0"
|
|
11
|
+
requires-python = ">=3.14"
|
|
12
|
+
authors = [{ name = "Michał Korczak", email = "git@omikor.in" }]
|
|
14
13
|
license-files = ["LICENSE", "NOTICE"]
|
|
15
|
-
description = "Next generation CLI for testing internet bandwidth using speedtest.net"
|
|
16
14
|
readme = "README.md"
|
|
17
|
-
requires-python = ">=3.12"
|
|
18
|
-
keywords = ["speedtest", "speedtest.net", "bandwidth", "internet", "cli"]
|
|
19
15
|
classifiers = [
|
|
20
16
|
"Development Status :: 4 - Beta",
|
|
21
17
|
"Environment :: Console",
|
|
22
18
|
"Intended Audience :: Developers",
|
|
23
19
|
"Intended Audience :: System Administrators",
|
|
24
20
|
"Operating System :: OS Independent",
|
|
25
|
-
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.14",
|
|
22
|
+
"Programming Language :: Python :: 3.15",
|
|
26
23
|
"Topic :: Internet :: WWW/HTTP",
|
|
27
24
|
"Topic :: System :: Networking",
|
|
28
25
|
"Topic :: Terminals",
|
|
29
26
|
"Topic :: Utilities",
|
|
30
27
|
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"httpx2>=2.5.0,<3",
|
|
30
|
+
"rich>=15.0.0,<16",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[dependency-groups]
|
|
34
|
+
dev = [
|
|
35
|
+
# Tests
|
|
36
|
+
"pytest>=9.0.0,<10",
|
|
37
|
+
"pytest-cov>=7.0.0,<8",
|
|
38
|
+
# Linting
|
|
39
|
+
"ruff>=0.15.0,<1",
|
|
40
|
+
"ty>=0.0.55,<1",
|
|
41
|
+
]
|
|
31
42
|
|
|
32
43
|
[project.urls]
|
|
33
44
|
Homepage = "https://github.com/Omikorin/speedtest-cli"
|
|
@@ -37,16 +48,21 @@ Issues = "https://github.com/Omikorin/speedtest-cli/issues"
|
|
|
37
48
|
[project.scripts]
|
|
38
49
|
speedtest = "speedtest.__main__:main"
|
|
39
50
|
speedtest-cli = "speedtest.__main__:main"
|
|
51
|
+
speedtest-cli-ng = "speedtest.__main__:main"
|
|
40
52
|
|
|
41
|
-
|
|
42
|
-
[
|
|
43
|
-
|
|
53
|
+
[tool.hatch.build.targets.sdist]
|
|
54
|
+
exclude = [
|
|
55
|
+
".github",
|
|
56
|
+
".python-version",
|
|
57
|
+
"renovate.json5",
|
|
58
|
+
]
|
|
44
59
|
|
|
45
|
-
[tool.
|
|
46
|
-
|
|
60
|
+
[tool.hatch.build.targets.wheel]
|
|
61
|
+
packages = ["src/speedtest"]
|
|
47
62
|
|
|
48
63
|
[tool.uv]
|
|
49
64
|
required-version = ">=0.11.0"
|
|
65
|
+
exclude-newer = "7 days"
|
|
50
66
|
|
|
51
67
|
[[tool.uv.index]]
|
|
52
68
|
name = "testpypi"
|
|
@@ -55,42 +71,37 @@ publish-url = "https://test.pypi.org/legacy/"
|
|
|
55
71
|
explicit = true
|
|
56
72
|
|
|
57
73
|
[tool.ruff]
|
|
58
|
-
|
|
59
|
-
line-length = 100
|
|
74
|
+
line-length = 120
|
|
60
75
|
src = ["speedtest", "tests"]
|
|
61
76
|
|
|
62
77
|
[tool.ruff.lint]
|
|
63
78
|
select = [
|
|
79
|
+
"ANN", # flake8 annotations
|
|
80
|
+
"B", # flake8 bugbear
|
|
81
|
+
"PYI", # flake8 pyi
|
|
64
82
|
"E", # pycodestyle errors
|
|
65
83
|
"W", # pycodestyle warnings
|
|
66
84
|
"F", # pyflakes
|
|
67
|
-
"I", # isort
|
|
68
|
-
"
|
|
85
|
+
"I", # isort
|
|
86
|
+
"N", # pep8 naming
|
|
87
|
+
"UP", # pyupgrade
|
|
69
88
|
"RUF", # ruff-specific rules
|
|
70
89
|
]
|
|
90
|
+
preview = true
|
|
71
91
|
ignore = []
|
|
92
|
+
unfixable = ["B"]
|
|
72
93
|
|
|
73
94
|
[tool.ruff.format]
|
|
74
95
|
quote-style = "double"
|
|
75
96
|
indent-style = "space"
|
|
76
97
|
|
|
77
|
-
[tool.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
typeCheckingMode = "standard" # Can be bumped to "strict" once codebase is fully annotated
|
|
81
|
-
useLibraryCodeForTypes = true
|
|
82
|
-
reportMissingImports = true
|
|
98
|
+
[tool.ty.rules]
|
|
99
|
+
missing-type-argument = "error"
|
|
100
|
+
possibly-unresolved-reference = "warn"
|
|
83
101
|
|
|
84
102
|
[tool.pytest]
|
|
85
103
|
minversion = "9.0"
|
|
86
104
|
# Automatically show extra test info, fail if coverage drops, and output a terminal coverage report
|
|
87
|
-
addopts = "-v --cov=speedtest --cov-report=term-missing"
|
|
105
|
+
addopts = ["-v", "--cov=speedtest", "--cov-report=term-missing"]
|
|
88
106
|
testpaths = ["tests"]
|
|
89
107
|
|
|
90
|
-
[dependency-groups]
|
|
91
|
-
dev = [
|
|
92
|
-
"pyright>=1.1.400",
|
|
93
|
-
"pytest>=9.0.0",
|
|
94
|
-
"pytest-cov>=7.0.0",
|
|
95
|
-
"ruff>=0.15.0",
|
|
96
|
-
]
|
|
@@ -4,25 +4,22 @@ The main entry point. Invoke as `speedtest-cli` or `python -m speedtest`.
|
|
|
4
4
|
|
|
5
5
|
import sys
|
|
6
6
|
|
|
7
|
-
from speedtest.cli
|
|
8
|
-
from speedtest.exceptions import
|
|
9
|
-
from speedtest.utils
|
|
10
|
-
from speedtest.utils.status import ExitStatus
|
|
7
|
+
from speedtest.cli import shell
|
|
8
|
+
from speedtest.exceptions import SpeedtestError
|
|
9
|
+
from speedtest.utils import ExitStatus, logger
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
def main() -> int:
|
|
14
13
|
"""Execute the CLI and return an integer exit status."""
|
|
15
14
|
|
|
16
15
|
try:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return int(exit_status)
|
|
16
|
+
return shell()
|
|
20
17
|
|
|
21
18
|
except KeyboardInterrupt:
|
|
22
19
|
logger.error("Stopped by user")
|
|
23
20
|
return ExitStatus.ERROR_CTRL_C.value
|
|
24
21
|
|
|
25
|
-
except
|
|
22
|
+
except SpeedtestError as e:
|
|
26
23
|
code = getattr(e, "code", ExitStatus.ERROR.value)
|
|
27
24
|
|
|
28
25
|
if code not in (ExitStatus.SUCCESS.value, ExitStatus.ERROR_CTRL_C.value):
|
|
@@ -31,10 +28,10 @@ def main() -> int:
|
|
|
31
28
|
|
|
32
29
|
return int(code)
|
|
33
30
|
|
|
34
|
-
except Exception
|
|
35
|
-
logger.exception("An unexpected error occurred."
|
|
31
|
+
except Exception:
|
|
32
|
+
logger.exception("An unexpected error occurred.")
|
|
36
33
|
return ExitStatus.ERROR.value
|
|
37
34
|
|
|
38
35
|
|
|
39
|
-
if __name__ == "__main__":
|
|
36
|
+
if __name__ == "__main__": # pragma: no cover
|
|
40
37
|
sys.exit(main())
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Handles terminal output and presentation logic for the CLI.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import dataclasses
|
|
6
|
+
import json
|
|
7
|
+
import sys
|
|
8
|
+
from datetime import UTC, datetime
|
|
9
|
+
|
|
10
|
+
from rich.table import Table
|
|
11
|
+
|
|
12
|
+
from speedtest.models import ApiConfig, Server, SpeedtestResult
|
|
13
|
+
from speedtest.utils import ExitStatus, console
|
|
14
|
+
|
|
15
|
+
__all__ = ["print_json", "print_server_list"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def print_server_list(servers: list[Server]) -> int:
|
|
19
|
+
"""Print nearby servers in a table."""
|
|
20
|
+
|
|
21
|
+
table = Table(title="Available Target Servers")
|
|
22
|
+
|
|
23
|
+
table.add_column("ID", justify="right", style="cyan", no_wrap=True)
|
|
24
|
+
table.add_column("Distance", justify="right", style="green", no_wrap=True)
|
|
25
|
+
table.add_column("Name", style="magenta")
|
|
26
|
+
table.add_column("Country", style="blue")
|
|
27
|
+
table.add_column("Sponsor", style="yellow")
|
|
28
|
+
|
|
29
|
+
for server in servers:
|
|
30
|
+
table.add_row(
|
|
31
|
+
str(server.id),
|
|
32
|
+
f"{server.distance} km",
|
|
33
|
+
server.name,
|
|
34
|
+
server.country,
|
|
35
|
+
server.sponsor,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
console.print(table)
|
|
40
|
+
except BrokenPipeError:
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
return ExitStatus.SUCCESS.value
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def print_json(results: SpeedtestResult, client_config: ApiConfig | None = None) -> None:
|
|
47
|
+
"""Print the machine-readable JSON representation."""
|
|
48
|
+
|
|
49
|
+
json_data = {
|
|
50
|
+
"timestamp": datetime.now(UTC).isoformat(),
|
|
51
|
+
"ping": results.ping_ms,
|
|
52
|
+
"download": results.download_bps,
|
|
53
|
+
"upload": results.upload_bps,
|
|
54
|
+
"bytes_received": results.download_bytes,
|
|
55
|
+
"bytes_sent": results.upload_bytes,
|
|
56
|
+
"share": results.share_url,
|
|
57
|
+
"server": dataclasses.asdict(results.server) if results.server else None,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if client_config:
|
|
61
|
+
json_data["client"] = {
|
|
62
|
+
"ip": client_config.ip_address,
|
|
63
|
+
"isp": client_config.isp_name,
|
|
64
|
+
"isp_id": client_config.isp_id,
|
|
65
|
+
"location": dataclasses.asdict(client_config.location),
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
indent = 2 if sys.stdout.isatty() else None
|
|
69
|
+
print(json.dumps(json_data, indent=indent))
|
|
@@ -75,20 +75,14 @@ def parse_args() -> argparse.Namespace:
|
|
|
75
75
|
action="store_const",
|
|
76
76
|
const=("B", 8),
|
|
77
77
|
default=("b", 1),
|
|
78
|
-
help=(
|
|
79
|
-
"Display values in bytes instead of bits. "
|
|
80
|
-
"Does not affect image generation or JSON output."
|
|
81
|
-
),
|
|
78
|
+
help=("Display values in bytes instead of bits. Does not affect image generation or JSON output."),
|
|
82
79
|
)
|
|
83
80
|
|
|
84
81
|
format_group = output_group.add_mutually_exclusive_group()
|
|
85
82
|
format_group.add_argument(
|
|
86
83
|
"--json",
|
|
87
84
|
action="store_true",
|
|
88
|
-
help=(
|
|
89
|
-
"Suppress verbose output, only show basic information "
|
|
90
|
-
"in JSON format. Speeds listed in bit/s."
|
|
91
|
-
),
|
|
85
|
+
help=("Suppress verbose output, only show basic information in JSON format. Speeds listed in bit/s."),
|
|
92
86
|
)
|
|
93
87
|
|
|
94
88
|
misc_group = parser.add_argument_group("Miscellaneous Options")
|