Open-AutoTools 0.0.4rc1__tar.gz → 0.0.4rc2__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.
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2/Open_AutoTools.egg-info}/PKG-INFO +16 -28
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/Open_AutoTools.egg-info/SOURCES.txt +4 -0
- open_autotools-0.0.4rc2/Open_AutoTools.egg-info/requires.txt +19 -0
- {open_autotools-0.0.4rc1/Open_AutoTools.egg-info → open_autotools-0.0.4rc2}/PKG-INFO +16 -28
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/autoip/commands.py +2 -1
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/autoip/core.py +1 -1
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/autotest/commands.py +9 -8
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/utils/performance.py +67 -35
- open_autotools-0.0.4rc2/autotools/utils/requirements.py +21 -0
- open_autotools-0.0.4rc2/autotools/utils/text.py +16 -0
- open_autotools-0.0.4rc2/requirements.txt +10 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/setup.py +12 -17
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/autoip/test_autoip_integration.py +2 -2
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/utils/test_performance.py +182 -28
- open_autotools-0.0.4rc2/tests/autotools/utils/test_requirements.py +148 -0
- open_autotools-0.0.4rc2/tests/autotools/utils/test_text.py +93 -0
- open_autotools-0.0.4rc1/Open_AutoTools.egg-info/requires.txt +0 -31
- open_autotools-0.0.4rc1/requirements.txt +0 -31
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/LICENSE +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/MANIFEST.in +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/Open_AutoTools.egg-info/dependency_links.txt +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/Open_AutoTools.egg-info/entry_points.txt +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/Open_AutoTools.egg-info/top_level.txt +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/README.md +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/__init__.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/autocaps/__init__.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/autocaps/commands.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/autocaps/core.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/autoip/__init__.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/autolower/__init__.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/autolower/commands.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/autolower/core.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/autopassword/__init__.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/autopassword/commands.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/autopassword/core.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/autotest/__init__.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/cli.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/utils/__init__.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/utils/commands.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/utils/loading.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/utils/updates.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/autotools/utils/version.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/pyproject.toml +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/setup.cfg +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/__init__.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/autocaps/__init__.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/autocaps/test_autocaps_core.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/autocaps/test_autocaps_integration.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/autoip/__init__.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/autoip/test_autoip_core.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/autolower/__init__.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/autolower/test_autolower_core.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/autolower/test_autolower_integration.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/autopassword/test_autopassword_core.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/autopassword/test_autopassword_integration.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/autotest/__init__.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/autotest/test_autotest_core.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/utils/__init__.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/utils/test_updates.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/autotools/utils/test_version.py +0 -0
- {open_autotools-0.0.4rc1 → open_autotools-0.0.4rc2}/tests/test_cli.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Open-AutoTools
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4rc2
|
|
4
4
|
Summary: A suite of automated tools accessible via CLI with a simple `autotools` command
|
|
5
5
|
Home-page: https://github.com/BabylooPro/Open-AutoTools
|
|
6
6
|
Author: BabylooPro
|
|
@@ -14,37 +14,24 @@ Classifier: Operating System :: OS Independent
|
|
|
14
14
|
Requires-Python: >=3.10
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
Requires-Dist:
|
|
19
|
-
Requires-Dist: Brotli==1.1.0
|
|
20
|
-
Requires-Dist: certifi==2024.2.2
|
|
21
|
-
Requires-Dist: charset-normalizer==3.3.2
|
|
22
|
-
Requires-Dist: click==8.1.3
|
|
23
|
-
Requires-Dist: cryptography==42.0.2
|
|
24
|
-
Requires-Dist: halo>=0.0.31
|
|
25
|
-
Requires-Dist: idna==3.6
|
|
26
|
-
Requires-Dist: importlib-metadata>=7.0.1
|
|
27
|
-
Requires-Dist: packaging>=23.0
|
|
28
|
-
Requires-Dist: platformdirs==4.2.0
|
|
29
|
-
Requires-Dist: pycryptodomex==3.20.0
|
|
30
|
-
Requires-Dist: pyperclip==1.8.2
|
|
17
|
+
Requires-Dist: click>=8.1.3
|
|
18
|
+
Requires-Dist: requests>=2.31.0
|
|
31
19
|
Requires-Dist: python-dotenv>=1.0.0
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Requires-Dist:
|
|
34
|
-
Requires-Dist:
|
|
35
|
-
Requires-Dist: urllib3==2.2.1
|
|
36
|
-
Requires-Dist: websockets==13.0.1
|
|
37
|
-
Requires-Dist: yapf==0.40.2
|
|
38
|
-
Requires-Dist: zipp==3.17.0
|
|
20
|
+
Requires-Dist: packaging>=23.0
|
|
21
|
+
Requires-Dist: halo>=0.0.31
|
|
22
|
+
Requires-Dist: pyperclip>=1.8.2
|
|
39
23
|
Requires-Dist: netifaces>=0.11.0
|
|
40
24
|
Requires-Dist: speedtest-cli>=2.1.3
|
|
41
25
|
Requires-Dist: psutil>=5.9.0
|
|
42
|
-
Requires-Dist:
|
|
43
|
-
|
|
44
|
-
Requires-Dist:
|
|
45
|
-
Requires-Dist:
|
|
46
|
-
Requires-Dist: pytest
|
|
47
|
-
Requires-Dist: pytest-
|
|
26
|
+
Requires-Dist: cryptography>=42.0.2
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: build>=1.4.0; extra == "dev"
|
|
29
|
+
Requires-Dist: wheel>=0.45.1; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-sugar>=1.0.0; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-xdist>=3.5.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-timeout>=2.2.0; extra == "dev"
|
|
48
35
|
Dynamic: author
|
|
49
36
|
Dynamic: author-email
|
|
50
37
|
Dynamic: classifier
|
|
@@ -54,6 +41,7 @@ Dynamic: home-page
|
|
|
54
41
|
Dynamic: license
|
|
55
42
|
Dynamic: license-file
|
|
56
43
|
Dynamic: project-url
|
|
44
|
+
Dynamic: provides-extra
|
|
57
45
|
Dynamic: requires-dist
|
|
58
46
|
Dynamic: requires-python
|
|
59
47
|
Dynamic: summary
|
|
@@ -30,6 +30,8 @@ autotools/utils/__init__.py
|
|
|
30
30
|
autotools/utils/commands.py
|
|
31
31
|
autotools/utils/loading.py
|
|
32
32
|
autotools/utils/performance.py
|
|
33
|
+
autotools/utils/requirements.py
|
|
34
|
+
autotools/utils/text.py
|
|
33
35
|
autotools/utils/updates.py
|
|
34
36
|
autotools/utils/version.py
|
|
35
37
|
tests/__init__.py
|
|
@@ -49,5 +51,7 @@ tests/autotools/autotest/__init__.py
|
|
|
49
51
|
tests/autotools/autotest/test_autotest_core.py
|
|
50
52
|
tests/autotools/utils/__init__.py
|
|
51
53
|
tests/autotools/utils/test_performance.py
|
|
54
|
+
tests/autotools/utils/test_requirements.py
|
|
55
|
+
tests/autotools/utils/test_text.py
|
|
52
56
|
tests/autotools/utils/test_updates.py
|
|
53
57
|
tests/autotools/utils/test_version.py
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
click>=8.1.3
|
|
2
|
+
requests>=2.31.0
|
|
3
|
+
python-dotenv>=1.0.0
|
|
4
|
+
packaging>=23.0
|
|
5
|
+
halo>=0.0.31
|
|
6
|
+
pyperclip>=1.8.2
|
|
7
|
+
netifaces>=0.11.0
|
|
8
|
+
speedtest-cli>=2.1.3
|
|
9
|
+
psutil>=5.9.0
|
|
10
|
+
cryptography>=42.0.2
|
|
11
|
+
|
|
12
|
+
[dev]
|
|
13
|
+
build>=1.4.0
|
|
14
|
+
wheel>=0.45.1
|
|
15
|
+
pytest>=7.4.0
|
|
16
|
+
pytest-cov>=4.1.0
|
|
17
|
+
pytest-sugar>=1.0.0
|
|
18
|
+
pytest-xdist>=3.5.0
|
|
19
|
+
pytest-timeout>=2.2.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Open-AutoTools
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4rc2
|
|
4
4
|
Summary: A suite of automated tools accessible via CLI with a simple `autotools` command
|
|
5
5
|
Home-page: https://github.com/BabylooPro/Open-AutoTools
|
|
6
6
|
Author: BabylooPro
|
|
@@ -14,37 +14,24 @@ Classifier: Operating System :: OS Independent
|
|
|
14
14
|
Requires-Python: >=3.10
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
Requires-Dist:
|
|
19
|
-
Requires-Dist: Brotli==1.1.0
|
|
20
|
-
Requires-Dist: certifi==2024.2.2
|
|
21
|
-
Requires-Dist: charset-normalizer==3.3.2
|
|
22
|
-
Requires-Dist: click==8.1.3
|
|
23
|
-
Requires-Dist: cryptography==42.0.2
|
|
24
|
-
Requires-Dist: halo>=0.0.31
|
|
25
|
-
Requires-Dist: idna==3.6
|
|
26
|
-
Requires-Dist: importlib-metadata>=7.0.1
|
|
27
|
-
Requires-Dist: packaging>=23.0
|
|
28
|
-
Requires-Dist: platformdirs==4.2.0
|
|
29
|
-
Requires-Dist: pycryptodomex==3.20.0
|
|
30
|
-
Requires-Dist: pyperclip==1.8.2
|
|
17
|
+
Requires-Dist: click>=8.1.3
|
|
18
|
+
Requires-Dist: requests>=2.31.0
|
|
31
19
|
Requires-Dist: python-dotenv>=1.0.0
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Requires-Dist:
|
|
34
|
-
Requires-Dist:
|
|
35
|
-
Requires-Dist: urllib3==2.2.1
|
|
36
|
-
Requires-Dist: websockets==13.0.1
|
|
37
|
-
Requires-Dist: yapf==0.40.2
|
|
38
|
-
Requires-Dist: zipp==3.17.0
|
|
20
|
+
Requires-Dist: packaging>=23.0
|
|
21
|
+
Requires-Dist: halo>=0.0.31
|
|
22
|
+
Requires-Dist: pyperclip>=1.8.2
|
|
39
23
|
Requires-Dist: netifaces>=0.11.0
|
|
40
24
|
Requires-Dist: speedtest-cli>=2.1.3
|
|
41
25
|
Requires-Dist: psutil>=5.9.0
|
|
42
|
-
Requires-Dist:
|
|
43
|
-
|
|
44
|
-
Requires-Dist:
|
|
45
|
-
Requires-Dist:
|
|
46
|
-
Requires-Dist: pytest
|
|
47
|
-
Requires-Dist: pytest-
|
|
26
|
+
Requires-Dist: cryptography>=42.0.2
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: build>=1.4.0; extra == "dev"
|
|
29
|
+
Requires-Dist: wheel>=0.45.1; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-sugar>=1.0.0; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-xdist>=3.5.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-timeout>=2.2.0; extra == "dev"
|
|
48
35
|
Dynamic: author
|
|
49
36
|
Dynamic: author-email
|
|
50
37
|
Dynamic: classifier
|
|
@@ -54,6 +41,7 @@ Dynamic: home-page
|
|
|
54
41
|
Dynamic: license
|
|
55
42
|
Dynamic: license-file
|
|
56
43
|
Dynamic: project-url
|
|
44
|
+
Dynamic: provides-extra
|
|
57
45
|
Dynamic: requires-dist
|
|
58
46
|
Dynamic: requires-python
|
|
59
47
|
Dynamic: summary
|
|
@@ -2,6 +2,7 @@ import click
|
|
|
2
2
|
from .core import run
|
|
3
3
|
from ..utils.loading import LoadingAnimation
|
|
4
4
|
from ..utils.updates import check_for_updates
|
|
5
|
+
from ..utils.text import safe_text
|
|
5
6
|
|
|
6
7
|
# CLI COMMAND TO DISPLAY NETWORK INFORMATION AND RUN DIAGNOSTICS
|
|
7
8
|
@click.command()
|
|
@@ -19,6 +20,6 @@ def autoip(test, speed, monitor, interval, ports, dns, location, no_ip):
|
|
|
19
20
|
test=test, speed=speed, monitor=monitor, interval=interval,
|
|
20
21
|
ports=ports, dns=dns, location=location, no_ip=no_ip
|
|
21
22
|
)
|
|
22
|
-
click.echo(output)
|
|
23
|
+
click.echo(safe_text(output))
|
|
23
24
|
update_msg = check_for_updates()
|
|
24
25
|
if update_msg: click.echo(update_msg)
|
|
@@ -183,7 +183,7 @@ def _display_connectivity_tests(output):
|
|
|
183
183
|
output.append("\nConnectivity Tests:")
|
|
184
184
|
results = test_connectivity()
|
|
185
185
|
for name, success, latency in results:
|
|
186
|
-
status = f"
|
|
186
|
+
status = f"OK {latency}ms" if success else "X Failed"
|
|
187
187
|
output.append(f"{name:<15} {status}")
|
|
188
188
|
|
|
189
189
|
# DISPLAYS LOCATION INFORMATION
|
|
@@ -4,6 +4,7 @@ import sys
|
|
|
4
4
|
import os
|
|
5
5
|
import re
|
|
6
6
|
from ..utils.updates import check_for_updates
|
|
7
|
+
from ..utils.text import safe_text
|
|
7
8
|
|
|
8
9
|
# CLI COMMAND TO RUN TEST SUITE WITH PYTEST
|
|
9
10
|
@click.command()
|
|
@@ -32,12 +33,12 @@ def _install_test_dependencies():
|
|
|
32
33
|
import pytest
|
|
33
34
|
import pytest_cov
|
|
34
35
|
except ImportError:
|
|
35
|
-
click.echo(click.style("\n
|
|
36
|
+
click.echo(safe_text(click.style("\n[X] pytest and/or pytest-cov not found. Installing...", fg='yellow', bold=True)))
|
|
36
37
|
try:
|
|
37
|
-
subprocess.run(['pip', 'install', 'pytest', 'pytest-cov'], check=True)
|
|
38
|
-
click.echo(click.style("
|
|
38
|
+
subprocess.run([sys.executable, '-m', 'pip', 'install', 'pytest', 'pytest-cov'], check=True)
|
|
39
|
+
click.echo(safe_text(click.style("[OK] Successfully installed pytest and pytest-cov", fg='green', bold=True)))
|
|
39
40
|
except subprocess.CalledProcessError as e:
|
|
40
|
-
click.echo(click.style(f"\n
|
|
41
|
+
click.echo(safe_text(click.style(f"\n[X] Failed to install dependencies: {str(e)}", fg='red', bold=True)))
|
|
41
42
|
sys.exit(1)
|
|
42
43
|
|
|
43
44
|
# BUILDS THE TEST COMMAND ARGUMENTS BY ADDING THE CORRECT TEST PATH AND OPTIONS
|
|
@@ -149,10 +150,10 @@ def _run_test_process(cmd):
|
|
|
149
150
|
coverage_data = _process_test_output(process)
|
|
150
151
|
_handle_test_result(process, coverage_data)
|
|
151
152
|
except subprocess.CalledProcessError as e:
|
|
152
|
-
click.echo(click.style(f"\n
|
|
153
|
+
click.echo(safe_text(click.style(f"\n[X] TESTS FAILED WITH RETURN CODE {e.returncode}", fg='red', bold=True)))
|
|
153
154
|
sys.exit(1)
|
|
154
155
|
except Exception as e:
|
|
155
|
-
click.echo(click.style(f"\n
|
|
156
|
+
click.echo(safe_text(click.style(f"\n[X] ERROR RUNNING TESTS: {str(e)}", fg='red', bold=True)))
|
|
156
157
|
sys.exit(1)
|
|
157
158
|
|
|
158
159
|
# PREPARES ENVIRONMENT FOR TEST PROCESS
|
|
@@ -198,8 +199,8 @@ def _process_test_output(process):
|
|
|
198
199
|
# HANDLES TEST RESULT AND DISPLAYS COVERAGE
|
|
199
200
|
def _handle_test_result(process, coverage_data):
|
|
200
201
|
if process.returncode == 0:
|
|
201
|
-
click.echo(click.style("\n
|
|
202
|
+
click.echo(safe_text(click.style("\n[OK] ALL TESTS PASSED !", fg='green', bold=True)))
|
|
202
203
|
_display_coverage_metrics(coverage_data)
|
|
203
204
|
else:
|
|
204
|
-
click.echo(click.style("\n
|
|
205
|
+
click.echo(safe_text(click.style("\n[X] SOME TESTS FAILED!", fg='red', bold=True)))
|
|
205
206
|
sys.exit(1)
|
|
@@ -3,11 +3,17 @@ import gc
|
|
|
3
3
|
import sys
|
|
4
4
|
import time
|
|
5
5
|
import click
|
|
6
|
-
import resource
|
|
7
6
|
import tracemalloc
|
|
8
7
|
from contextlib import contextmanager
|
|
9
8
|
from typing import Dict, List, Tuple, Optional
|
|
10
9
|
|
|
10
|
+
try:
|
|
11
|
+
import resource
|
|
12
|
+
RESOURCE_AVAILABLE = True
|
|
13
|
+
except ImportError:
|
|
14
|
+
resource = None
|
|
15
|
+
RESOURCE_AVAILABLE = False
|
|
16
|
+
|
|
11
17
|
try:
|
|
12
18
|
import psutil
|
|
13
19
|
PSUTIL_AVAILABLE = True
|
|
@@ -19,9 +25,10 @@ ENABLE_PERFORMANCE_METRICS = False
|
|
|
19
25
|
if os.getenv('AUTOTOOLS_DISABLE_PERF', '').lower() in ('1', 'true', 'yes'): ENABLE_PERFORMANCE_METRICS = False
|
|
20
26
|
|
|
21
27
|
# FLAG TO ENABLE/DISABLE TRACEMALLOC (CAN BE SLOW IN PRODUCTION)
|
|
22
|
-
# ENABLE
|
|
28
|
+
# ONLY ENABLE IF EXPLICITLY REQUESTED VIA ENV VAR OR IF PYTEST IS ACTUALLY RUNNING
|
|
29
|
+
# DO NOT ENABLE BASED ON ARGUMENT VALUES TO AVOID FALSE POSITIVES (EXAMPLE: "test" AS COMMAND ARGUMENT)
|
|
23
30
|
_ENV_TRACEMALLOC = os.getenv('AUTOTOOLS_ENABLE_TRACEMALLOC', '').lower() in ('1', 'true', 'yes')
|
|
24
|
-
_IS_TEST_ENV = 'pytest' in sys.modules or any(
|
|
31
|
+
_IS_TEST_ENV = 'pytest' in sys.modules or any(arg.endswith('pytest') or arg.endswith('py.test') for arg in sys.argv)
|
|
25
32
|
ENABLE_TRACEMALLOC = _ENV_TRACEMALLOC or _IS_TEST_ENV
|
|
26
33
|
|
|
27
34
|
# PERFORMANCE METRICS COLLECTOR
|
|
@@ -133,47 +140,72 @@ class PerformanceMetrics:
|
|
|
133
140
|
|
|
134
141
|
# RECORDS CPU USAGE AT START
|
|
135
142
|
def _record_cpu_start(self):
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
143
|
+
if PSUTIL_AVAILABLE:
|
|
144
|
+
process = psutil.Process()
|
|
145
|
+
cpu_times = process.cpu_times()
|
|
146
|
+
self.cpu_user_start = cpu_times.user
|
|
147
|
+
self.cpu_sys_start = cpu_times.system
|
|
148
|
+
elif RESOURCE_AVAILABLE:
|
|
149
|
+
usage = resource.getrusage(resource.RUSAGE_SELF)
|
|
150
|
+
self.cpu_user_start = usage.ru_utime
|
|
151
|
+
self.cpu_sys_start = usage.ru_stime
|
|
152
|
+
else:
|
|
153
|
+
self.cpu_user_start = time.process_time()
|
|
154
|
+
self.cpu_sys_start = 0.0
|
|
139
155
|
|
|
140
156
|
# RECORDS CPU USAGE AT END
|
|
141
157
|
def _record_cpu_end(self):
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
158
|
+
if PSUTIL_AVAILABLE:
|
|
159
|
+
process = psutil.Process()
|
|
160
|
+
cpu_times = process.cpu_times()
|
|
161
|
+
self.cpu_user_end = cpu_times.user
|
|
162
|
+
self.cpu_sys_end = cpu_times.system
|
|
163
|
+
elif RESOURCE_AVAILABLE:
|
|
164
|
+
usage = resource.getrusage(resource.RUSAGE_SELF)
|
|
165
|
+
self.cpu_user_end = usage.ru_utime
|
|
166
|
+
self.cpu_sys_end = usage.ru_stime
|
|
167
|
+
else:
|
|
168
|
+
self.cpu_user_end = time.process_time()
|
|
169
|
+
self.cpu_sys_end = 0.0
|
|
145
170
|
|
|
146
171
|
# RECORDS MEMORY USAGE AT START
|
|
147
172
|
def _record_rss_start(self):
|
|
148
173
|
if PSUTIL_AVAILABLE:
|
|
149
174
|
process = psutil.Process()
|
|
150
175
|
self.rss_start = process.memory_info().rss / (1024 * 1024) # MB
|
|
151
|
-
|
|
176
|
+
elif RESOURCE_AVAILABLE:
|
|
152
177
|
usage = resource.getrusage(resource.RUSAGE_SELF)
|
|
153
178
|
self.rss_start = usage.ru_maxrss / 1024 # MB (LINUX) OR KB (MACOS)
|
|
154
179
|
if sys.platform == 'darwin':
|
|
155
180
|
self.rss_start = self.rss_start / 1024 # CONVERT KB TO MB ON MACOS
|
|
181
|
+
else:
|
|
182
|
+
self.rss_start = 0.0
|
|
156
183
|
|
|
157
184
|
# RECORDS MEMORY USAGE AT END
|
|
158
185
|
def _record_rss_end(self):
|
|
159
|
-
if PSUTIL_AVAILABLE:
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
self.rss_peak = mem_info.rss / (1024 * 1024) # MB
|
|
186
|
+
if PSUTIL_AVAILABLE: self._record_rss_end_psutil()
|
|
187
|
+
elif RESOURCE_AVAILABLE: self._record_rss_end_resource()
|
|
188
|
+
else: self.rss_peak = self.rss_start if self.rss_start is not None else 0.0
|
|
163
189
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
190
|
+
# RECORDS MEMORY USAGE AT END USING PSUTIL
|
|
191
|
+
def _record_rss_end_psutil(self):
|
|
192
|
+
process = psutil.Process()
|
|
193
|
+
mem_info = process.memory_info()
|
|
194
|
+
self.rss_peak = mem_info.rss / (1024 * 1024) # MB
|
|
195
|
+
|
|
196
|
+
try:
|
|
197
|
+
if hasattr(process, 'memory_info_ex'):
|
|
198
|
+
mem_ext = process.memory_info_ex()
|
|
199
|
+
if hasattr(mem_ext, 'peak_wss'): self.rss_peak = max(self.rss_peak, mem_ext.peak_wss / (1024 * 1024))
|
|
200
|
+
except Exception:
|
|
201
|
+
pass
|
|
202
|
+
|
|
203
|
+
# RECORDS MEMORY USAGE AT END USING RESOURCE
|
|
204
|
+
def _record_rss_end_resource(self):
|
|
205
|
+
usage = resource.getrusage(resource.RUSAGE_SELF)
|
|
206
|
+
rss_current = usage.ru_maxrss / 1024
|
|
207
|
+
if sys.platform == 'darwin': rss_current = rss_current / 1024
|
|
208
|
+
self.rss_peak = max(self.rss_start, rss_current) if self.rss_start else rss_current
|
|
177
209
|
|
|
178
210
|
# RECORDS FILESYSTEM I/O AT START
|
|
179
211
|
def _record_fs_start(self):
|
|
@@ -217,15 +249,15 @@ class PerformanceMetrics:
|
|
|
217
249
|
|
|
218
250
|
# CALCULATES DURATION METRICS IN MILLISECONDS
|
|
219
251
|
def _calculate_durations(self) -> Tuple[float, float, float]:
|
|
220
|
-
total_duration_ms = (self.process_end - self.process_start) * 1000 if self.process_end and self.process_start else 0
|
|
221
|
-
startup_duration_ms = (self.startup_end - self.startup_start) * 1000 if self.startup_end and self.startup_start else 0
|
|
222
|
-
command_duration_ms = (self.command_end - self.command_start) * 1000 if self.command_end and self.command_start else 0
|
|
252
|
+
total_duration_ms = (self.process_end - self.process_start) * 1000 if self.process_end is not None and self.process_start is not None else 0
|
|
253
|
+
startup_duration_ms = (self.startup_end - self.startup_start) * 1000 if self.startup_end is not None and self.startup_start is not None else 0
|
|
254
|
+
command_duration_ms = (self.command_end - self.command_start) * 1000 if self.command_end is not None and self.command_start is not None else 0
|
|
223
255
|
return total_duration_ms, startup_duration_ms, command_duration_ms
|
|
224
256
|
|
|
225
257
|
# CALCULATES CPU TIME METRICS IN MILLISECONDS
|
|
226
258
|
def _calculate_cpu_time(self) -> Tuple[float, float, float]:
|
|
227
|
-
cpu_user_ms = (self.cpu_user_end - self.cpu_user_start) * 1000 if self.cpu_user_end and self.cpu_user_start else 0
|
|
228
|
-
cpu_sys_ms = (self.cpu_sys_end - self.cpu_sys_start) * 1000 if self.cpu_sys_end and self.cpu_sys_start else 0
|
|
259
|
+
cpu_user_ms = (self.cpu_user_end - self.cpu_user_start) * 1000 if self.cpu_user_end is not None and self.cpu_user_start is not None else 0
|
|
260
|
+
cpu_sys_ms = (self.cpu_sys_end - self.cpu_sys_start) * 1000 if self.cpu_sys_end is not None and self.cpu_sys_start is not None else 0
|
|
229
261
|
cpu_time_total_ms = cpu_user_ms + cpu_sys_ms
|
|
230
262
|
return cpu_time_total_ms, cpu_user_ms, cpu_sys_ms
|
|
231
263
|
|
|
@@ -260,9 +292,9 @@ class PerformanceMetrics:
|
|
|
260
292
|
|
|
261
293
|
# CALCULATES FILESYSTEM I/O METRICS
|
|
262
294
|
def _calculate_fs_io(self) -> Tuple[int, int, int]:
|
|
263
|
-
fs_bytes_read_total = self.fs_read_end - self.fs_read_start if self.fs_read_end and self.fs_read_start else 0
|
|
264
|
-
fs_bytes_written_total = self.fs_write_end - self.fs_write_start if self.fs_write_end and self.fs_write_start else 0
|
|
265
|
-
fs_ops_count = self.fs_ops_end - self.fs_ops_start if self.fs_ops_end and self.fs_ops_start else 0
|
|
295
|
+
fs_bytes_read_total = self.fs_read_end - self.fs_read_start if self.fs_read_end is not None and self.fs_read_start is not None else 0
|
|
296
|
+
fs_bytes_written_total = self.fs_write_end - self.fs_write_start if self.fs_write_end is not None and self.fs_write_start is not None else 0
|
|
297
|
+
fs_ops_count = self.fs_ops_end - self.fs_ops_start if self.fs_ops_end is not None and self.fs_ops_start is not None else 0
|
|
266
298
|
return fs_bytes_read_total, fs_bytes_written_total, fs_ops_count
|
|
267
299
|
|
|
268
300
|
# CALCULATES AND RETURNS ALL PERFORMANCE METRICS AS A DICTIONARY
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
# READ REQUIREMENTS FROM A FILE AND RETURN AS A LIST
|
|
4
|
+
# HANDLES MISSING FILES GRACEFULLY BY RETURNING AN EMPTY LIST
|
|
5
|
+
# THE FILENAME IS RELATIVE TO THE PROJECT ROOT (WHERE SETUP.PY IS LOCATED)
|
|
6
|
+
def read_requirements(filename="requirements.txt"):
|
|
7
|
+
project_root = os.path.join(os.path.dirname(__file__), "..", "..")
|
|
8
|
+
requirements_path = os.path.join(os.path.abspath(project_root), filename)
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
with open(requirements_path, "r", encoding="utf-8") as fh:
|
|
12
|
+
requirements = []
|
|
13
|
+
|
|
14
|
+
for line in fh:
|
|
15
|
+
line = line.strip()
|
|
16
|
+
if line.startswith("-r") or line.startswith("--requirement"): continue
|
|
17
|
+
if line and not line.startswith("#"): requirements.append(line)
|
|
18
|
+
|
|
19
|
+
return requirements
|
|
20
|
+
except FileNotFoundError:
|
|
21
|
+
return []
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
# ENSURE TEXT IS SAFE TO WRITE TO THE CURRENT STDOUT ENCODING
|
|
5
|
+
# SOME WINDOWS TERMINALS USE LEGACY ENCODINGS THAT CANNOT ENCODE CERTAIN CHARACTERS
|
|
6
|
+
def safe_text(text: Any) -> Any:
|
|
7
|
+
if not isinstance(text, str): return text
|
|
8
|
+
|
|
9
|
+
encoding = getattr(sys.stdout, "encoding", None) or "utf-8"
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
text.encode(encoding)
|
|
13
|
+
return text
|
|
14
|
+
except Exception:
|
|
15
|
+
try: return text.encode(encoding, errors="replace").decode(encoding)
|
|
16
|
+
except Exception: return text.encode("ascii", errors="replace").decode("ascii")
|
|
@@ -1,31 +1,28 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import importlib.util
|
|
2
3
|
from setuptools import setup, find_packages
|
|
3
4
|
|
|
4
5
|
# READING README.MD FOR LONG DESCRIPTION
|
|
5
6
|
with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read()
|
|
6
7
|
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
# LOADING REQUIREMENTS
|
|
9
|
+
requirements_module_path = os.path.join(os.path.dirname(__file__), "autotools", "utils", "requirements.py")
|
|
10
|
+
spec = importlib.util.spec_from_file_location("requirements", requirements_module_path)
|
|
11
|
+
requirements_module = importlib.util.module_from_spec(spec)
|
|
12
|
+
spec.loader.exec_module(requirements_module)
|
|
13
|
+
read_requirements = requirements_module.read_requirements
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if line and not line.startswith("#"):
|
|
16
|
-
requirements.append(line)
|
|
17
|
-
|
|
18
|
-
return requirements
|
|
19
|
-
|
|
20
|
-
required = read_requirements()
|
|
15
|
+
required = read_requirements("requirements.txt")
|
|
16
|
+
dev_required = read_requirements("requirements-dev.txt")
|
|
21
17
|
|
|
22
18
|
# SETUP CONFIGURATION FOR PACKAGE DISTRIBUTION
|
|
23
19
|
setup(
|
|
24
20
|
name='Open-AutoTools',
|
|
25
|
-
version='0.0.4-rc.
|
|
21
|
+
version='0.0.4-rc.2',
|
|
26
22
|
packages=find_packages(exclude=["tests", "tests.*"]),
|
|
27
23
|
include_package_data=True,
|
|
28
24
|
install_requires=required,
|
|
25
|
+
extras_require={ "dev": dev_required },
|
|
29
26
|
|
|
30
27
|
# ENTRY POINTS FOR CLI COMMANDS
|
|
31
28
|
entry_points='''
|
|
@@ -44,9 +41,7 @@ setup(
|
|
|
44
41
|
long_description=long_description,
|
|
45
42
|
long_description_content_type="text/markdown",
|
|
46
43
|
url="https://github.com/BabylooPro/Open-AutoTools",
|
|
47
|
-
project_urls={
|
|
48
|
-
"Bug Tracker": "https://github.com/BabylooPro/Open-AutoTools/issues",
|
|
49
|
-
},
|
|
44
|
+
project_urls={ "Bug Tracker": "https://github.com/BabylooPro/Open-AutoTools/issues" },
|
|
50
45
|
license="MIT",
|
|
51
46
|
classifiers=[
|
|
52
47
|
"Programming Language :: Python :: 3.10",
|
|
@@ -38,8 +38,8 @@ def test_autoip_cli_test(mock_test):
|
|
|
38
38
|
assert result.exit_code == 0
|
|
39
39
|
assert "Google DNS" in result.output
|
|
40
40
|
assert "CloudFlare" in result.output
|
|
41
|
-
assert "
|
|
42
|
-
assert "
|
|
41
|
+
assert "OK 20ms" in result.output
|
|
42
|
+
assert "X Failed" in result.output
|
|
43
43
|
|
|
44
44
|
# TEST FOR SPEED TEST
|
|
45
45
|
@patch('autotools.autoip.core.run_speedtest')
|