Open-AutoTools 0.0.2.post2__py3-none-any.whl → 0.0.3rc1__py3-none-any.whl
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.2.post2.dist-info → Open_AutoTools-0.0.3rc1.dist-info}/METADATA +27 -2
- Open_AutoTools-0.0.3rc1.dist-info/RECORD +31 -0
- {Open_AutoTools-0.0.2.post2.dist-info → Open_AutoTools-0.0.3rc1.dist-info}/entry_points.txt +2 -1
- autotools/autocaps/tests/__init__.py +1 -0
- autotools/autocaps/tests/test_autocaps_core.py +45 -0
- autotools/autocaps/tests/test_autocaps_integration.py +46 -0
- autotools/autoip/core.py +133 -40
- autotools/autoip/tests/__init__.py +1 -0
- autotools/autoip/tests/test_autoip_core.py +72 -0
- autotools/autoip/tests/test_autoip_integration.py +92 -0
- autotools/autolower/tests/__init__.py +1 -0
- autotools/autolower/tests/test_autolower_core.py +45 -0
- autotools/autolower/tests/test_autolower_integration.py +46 -0
- autotools/autospell/__init__.py +3 -0
- autotools/autospell/core.py +222 -0
- autotools/autotranslate/core.py +13 -1
- autotools/cli.py +431 -47
- Open_AutoTools-0.0.2.post2.dist-info/RECORD +0 -20
- {Open_AutoTools-0.0.2.post2.dist-info → Open_AutoTools-0.0.3rc1.dist-info}/LICENSE +0 -0
- {Open_AutoTools-0.0.2.post2.dist-info → Open_AutoTools-0.0.3rc1.dist-info}/WHEEL +0 -0
- {Open_AutoTools-0.0.2.post2.dist-info → Open_AutoTools-0.0.3rc1.dist-info}/top_level.txt +0 -0
- /autotools/{downloader → autodownload}/__init__.py +0 -0
- /autotools/{downloader → autodownload}/core.py +0 -0
- /autotools/{password → autopassword}/__init__.py +0 -0
- /autotools/{password → autopassword}/core.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: Open-AutoTools
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3rc1
|
|
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
|
|
@@ -18,14 +18,16 @@ Requires-Dist: charset-normalizer==3.3.2
|
|
|
18
18
|
Requires-Dist: click==8.1.3
|
|
19
19
|
Requires-Dist: cryptography==42.0.2
|
|
20
20
|
Requires-Dist: idna==3.6
|
|
21
|
-
Requires-Dist: importlib-metadata
|
|
21
|
+
Requires-Dist: importlib-metadata>=7.0.1
|
|
22
22
|
Requires-Dist: joblib==1.3.2
|
|
23
23
|
Requires-Dist: Levenshtein==0.25.0
|
|
24
24
|
Requires-Dist: mutagen==1.47.0
|
|
25
|
+
Requires-Dist: packaging>=23.0
|
|
25
26
|
Requires-Dist: platformdirs==4.2.0
|
|
26
27
|
Requires-Dist: pycryptodomex==3.20.0
|
|
27
28
|
Requires-Dist: pyperclip==1.8.2
|
|
28
29
|
Requires-Dist: python-Levenshtein==0.25.0
|
|
30
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
29
31
|
Requires-Dist: rapidfuzz==3.6.1
|
|
30
32
|
Requires-Dist: regex==2023.12.25
|
|
31
33
|
Requires-Dist: requests>=2.32.2
|
|
@@ -44,6 +46,12 @@ Requires-Dist: netifaces>=0.11.0
|
|
|
44
46
|
Requires-Dist: speedtest-cli>=2.1.3
|
|
45
47
|
Requires-Dist: psutil>=5.9.0
|
|
46
48
|
Requires-Dist: setuptools>=40.8.0
|
|
49
|
+
Requires-Dist: language-tool-python>=2.7.1
|
|
50
|
+
Requires-Dist: spacy>=3.7.2
|
|
51
|
+
Requires-Dist: beautifulsoup4>=4.12.0
|
|
52
|
+
Provides-Extra: test
|
|
53
|
+
Requires-Dist: pytest>=7.4.0; extra == "test"
|
|
54
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "test"
|
|
47
55
|
Dynamic: author
|
|
48
56
|
Dynamic: author-email
|
|
49
57
|
Dynamic: classifier
|
|
@@ -51,6 +59,7 @@ Dynamic: description
|
|
|
51
59
|
Dynamic: description-content-type
|
|
52
60
|
Dynamic: home-page
|
|
53
61
|
Dynamic: project-url
|
|
62
|
+
Dynamic: provides-extra
|
|
54
63
|
Dynamic: requires-dist
|
|
55
64
|
Dynamic: requires-python
|
|
56
65
|
Dynamic: summary
|
|
@@ -164,6 +173,22 @@ These examples demonstrate how the terminal will display the results after execu
|
|
|
164
173
|
- `--detect`: Show detected source language
|
|
165
174
|
- `--list-languages`: Show all supported language codes and names
|
|
166
175
|
|
|
176
|
+
### AutoSpell (unreleased)
|
|
177
|
+
|
|
178
|
+
- **Description:** Checks and corrects spelling in text with multi-language support.
|
|
179
|
+
- **Usage:**
|
|
180
|
+
```
|
|
181
|
+
~ ❯ autospell "Your text with misspellings"
|
|
182
|
+
~ ❯ autospell --lang fr "Votre texte avec des fautes"
|
|
183
|
+
~ ❯ autospell --file document.txt
|
|
184
|
+
```
|
|
185
|
+
- **Options:**
|
|
186
|
+
- `--lang`: Language code (default: en)
|
|
187
|
+
- `--file`: Input from file
|
|
188
|
+
- `--copy`: Copy corrected text to clipboard
|
|
189
|
+
- `--suggest`: Show alternative suggestions
|
|
190
|
+
- `--interactive`: Interactive correction mode
|
|
191
|
+
|
|
167
192
|
### AutoDownload
|
|
168
193
|
|
|
169
194
|
- **Description:** Downloads videos from YouTube and files from other sources.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
autotools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
autotools/cli.py,sha256=YJ_0Dq7t97SPkmmRSvqFuBkOVsh2UcnNcS8wdNSoESg,24389
|
|
3
|
+
autotools/autocaps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
autotools/autocaps/core.py,sha256=NnOacVp0kMoq__KHWi5UMcApSuq6Iyo5bFxN40dRw7U,253
|
|
5
|
+
autotools/autocaps/tests/__init__.py,sha256=CckydfM7SZdXtW3pLgAeRdrC60sovNx_v59nyFvslFo,23
|
|
6
|
+
autotools/autocaps/tests/test_autocaps_core.py,sha256=fzpci_sK7L1fSf_IJ1paJ__bmnHwC9OUOD7ftd3w07c,1672
|
|
7
|
+
autotools/autocaps/tests/test_autocaps_integration.py,sha256=Qe2hzVEvzf0-INp14oTTrHi0RiRDCE2fxo9abVNcd_E,1435
|
|
8
|
+
autotools/autodownload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
autotools/autodownload/core.py,sha256=xmQSEEi3UYPkbbwsL-H4vGKcpqLCkwhIYlZxDWrIEpI,8266
|
|
10
|
+
autotools/autoip/__init__.py,sha256=T_5hz9G4reFPXDucdzRoMFPYlAKwTPt9TejOpkRPgn0,23
|
|
11
|
+
autotools/autoip/core.py,sha256=Q3dzLstZQruwYkSbCSlKQNmKVGCyNpo1DGst5VFtHLU,10123
|
|
12
|
+
autotools/autoip/tests/__init__.py,sha256=CckydfM7SZdXtW3pLgAeRdrC60sovNx_v59nyFvslFo,23
|
|
13
|
+
autotools/autoip/tests/test_autoip_core.py,sha256=Q8865qqhopcGBzS4mIlDlEzxu-mTIbZxpgJyzIyuQXc,2153
|
|
14
|
+
autotools/autoip/tests/test_autoip_integration.py,sha256=-vS2gnY8ZfT-tfY2FRbUtTzY0lcIBtVZHbPbWsKyueo,2746
|
|
15
|
+
autotools/autolower/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
autotools/autolower/core.py,sha256=vjM2ognA3tDCbv10a9vta9WPuAiqTPjOXZ1JHL_b-nk,260
|
|
17
|
+
autotools/autolower/tests/__init__.py,sha256=CckydfM7SZdXtW3pLgAeRdrC60sovNx_v59nyFvslFo,23
|
|
18
|
+
autotools/autolower/tests/test_autolower_core.py,sha256=ChkS3qZgXz75iLfC9EXVH_kMd-sjaxpRKFjaxKoBnxo,1694
|
|
19
|
+
autotools/autolower/tests/test_autolower_integration.py,sha256=M2yN1Ym7kGulys62-IwKq-uWn7CFvI3sCnoo-e3CTaA,1446
|
|
20
|
+
autotools/autopassword/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
21
|
+
autotools/autopassword/core.py,sha256=GQrd-QGWpgxuq6Nf28URcTZRku8Gji1NfpbecXAsIF0,3146
|
|
22
|
+
autotools/autospell/__init__.py,sha256=jkpkiE7pksBgllXKfkNpYYvqtlm8vN0h4kXnQOqcb_U,60
|
|
23
|
+
autotools/autospell/core.py,sha256=WPvi9Xs6uF3dte_g2I9oHfTjCV1-NasrJElLP9bbC8U,8103
|
|
24
|
+
autotools/autotranslate/__init__.py,sha256=6BxuZqhyQhfsZ5x7DkB1BAEpC08GT_5l5bl0AY_eLpU,64
|
|
25
|
+
autotools/autotranslate/core.py,sha256=H2f90IWr_jNGiJD3XAv-20i5sRGM-VDYWrYt65EDEkI,1836
|
|
26
|
+
Open_AutoTools-0.0.3rc1.dist-info/LICENSE,sha256=SpbSRxNWos2l0-geleCa6d0L9G_bOsZRkY4rB9OduJ0,1069
|
|
27
|
+
Open_AutoTools-0.0.3rc1.dist-info/METADATA,sha256=Vvbj28d0I4k0RdUeBE6v2lxmkvr5UxV89nznLpU9bVs,9120
|
|
28
|
+
Open_AutoTools-0.0.3rc1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
29
|
+
Open_AutoTools-0.0.3rc1.dist-info/entry_points.txt,sha256=QLIsUk6vHo0wAYDk1K74kIuYunJMwWe2xbwQhJXLoKo,312
|
|
30
|
+
Open_AutoTools-0.0.3rc1.dist-info/top_level.txt,sha256=x5ZRvdQw7DQnVmR0YDqVSAuuS94KTHDmk6uIeW7YOPw,10
|
|
31
|
+
Open_AutoTools-0.0.3rc1.dist-info/RECORD,,
|
|
@@ -4,5 +4,6 @@ autodownload = autotools.cli:autodownload
|
|
|
4
4
|
autoip = autotools.cli:autoip
|
|
5
5
|
autolower = autotools.cli:autolower
|
|
6
6
|
autopassword = autotools.cli:autopassword
|
|
7
|
-
|
|
7
|
+
autospell = autotools.cli:autospell
|
|
8
|
+
autotools = autotools.cli:cli
|
|
8
9
|
autotranslate = autotools.cli:autotranslate
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# INIT FILE FOR TESTS
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from autotools.autocaps.core import autocaps_transform
|
|
3
|
+
|
|
4
|
+
# UNIT TESTS
|
|
5
|
+
|
|
6
|
+
# TEST FOR BASIC STRING TRANSFORMATION
|
|
7
|
+
def test_autocaps_transform_basic():
|
|
8
|
+
"""TEST BASIC STRING TRANSFORMATION"""
|
|
9
|
+
assert autocaps_transform("hello") == "HELLO"
|
|
10
|
+
assert autocaps_transform("Hello World") == "HELLO WORLD"
|
|
11
|
+
assert autocaps_transform("123") == "123"
|
|
12
|
+
|
|
13
|
+
# TEST FOR EMPTY STRING
|
|
14
|
+
def test_autocaps_transform_empty():
|
|
15
|
+
"""TEST EMPTY STRING"""
|
|
16
|
+
assert autocaps_transform("") == ""
|
|
17
|
+
|
|
18
|
+
# TEST FOR SPECIAL CHARACTERS
|
|
19
|
+
def test_autocaps_transform_special_chars():
|
|
20
|
+
"""TEST STRING WITH SPECIAL CHARACTERS"""
|
|
21
|
+
assert autocaps_transform("hello@world.com") == "HELLO@WORLD.COM"
|
|
22
|
+
assert autocaps_transform("hello-world!") == "HELLO-WORLD!"
|
|
23
|
+
|
|
24
|
+
# TEST FOR MIXED CASE STRING
|
|
25
|
+
def test_autocaps_transform_mixed_case():
|
|
26
|
+
"""TEST MIXED CASE STRING"""
|
|
27
|
+
assert autocaps_transform("HeLLo WoRLD") == "HELLO WORLD"
|
|
28
|
+
|
|
29
|
+
# TEST FOR WHITESPACE
|
|
30
|
+
def test_autocaps_transform_whitespace():
|
|
31
|
+
"""TEST STRING WITH WHITESPACE"""
|
|
32
|
+
assert autocaps_transform(" hello world ") == " HELLO WORLD "
|
|
33
|
+
assert autocaps_transform("\thello\nworld") == "\tHELLO\nWORLD"
|
|
34
|
+
|
|
35
|
+
# TEST FOR NUMBERS
|
|
36
|
+
def test_autocaps_transform_numbers():
|
|
37
|
+
"""TEST STRING WITH NUMBERS"""
|
|
38
|
+
assert autocaps_transform("hello123world") == "HELLO123WORLD"
|
|
39
|
+
assert autocaps_transform("123hello456world789") == "123HELLO456WORLD789"
|
|
40
|
+
|
|
41
|
+
# TEST FOR UNICODE CHARACTERS
|
|
42
|
+
def test_autocaps_transform_unicode():
|
|
43
|
+
"""TEST UNICODE CHARACTERS"""
|
|
44
|
+
assert autocaps_transform("héllo wörld") == "HÉLLO WÖRLD"
|
|
45
|
+
assert autocaps_transform("こんにちは") == "こんにちは" # JAPANESE SHOULD REMAIN UNCHANGED
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from click.testing import CliRunner
|
|
3
|
+
from autotools.cli import autocaps
|
|
4
|
+
|
|
5
|
+
# INTEGRATION TESTS
|
|
6
|
+
|
|
7
|
+
# TEST FOR BASIC CLI FUNCTIONALITY
|
|
8
|
+
def test_autocaps_cli_basic():
|
|
9
|
+
"""TEST BASIC CLI FUNCTIONALITY"""
|
|
10
|
+
runner = CliRunner()
|
|
11
|
+
result = runner.invoke(autocaps, ["hello world"])
|
|
12
|
+
assert result.exit_code == 0
|
|
13
|
+
assert "HELLO WORLD" in result.output
|
|
14
|
+
|
|
15
|
+
# TEST FOR EMPTY INPUT
|
|
16
|
+
def test_autocaps_cli_empty():
|
|
17
|
+
"""TEST CLI WITH EMPTY INPUT"""
|
|
18
|
+
runner = CliRunner()
|
|
19
|
+
result = runner.invoke(autocaps, [""])
|
|
20
|
+
assert result.exit_code == 0
|
|
21
|
+
assert "" in result.output
|
|
22
|
+
|
|
23
|
+
# TEST FOR SPECIAL CHARACTERS
|
|
24
|
+
def test_autocaps_cli_special_chars():
|
|
25
|
+
"""TEST CLI WITH SPECIAL CHARACTERS"""
|
|
26
|
+
runner = CliRunner()
|
|
27
|
+
result = runner.invoke(autocaps, ["hello@world.com"])
|
|
28
|
+
assert result.exit_code == 0
|
|
29
|
+
assert "HELLO@WORLD.COM" in result.output
|
|
30
|
+
|
|
31
|
+
# TEST FOR UNICODE CHARACTERS
|
|
32
|
+
def test_autocaps_cli_unicode():
|
|
33
|
+
"""TEST CLI WITH UNICODE CHARACTERS"""
|
|
34
|
+
runner = CliRunner()
|
|
35
|
+
result = runner.invoke(autocaps, ["héllo wörld"])
|
|
36
|
+
assert result.exit_code == 0
|
|
37
|
+
assert "HÉLLO WÖRLD" in result.output
|
|
38
|
+
|
|
39
|
+
# TEST FOR MULTIPLE ARGUMENTS
|
|
40
|
+
def test_autocaps_cli_multiple_args():
|
|
41
|
+
"""TEST CLI WITH MULTIPLE ARGUMENTS"""
|
|
42
|
+
runner = CliRunner()
|
|
43
|
+
result = runner.invoke(autocaps, ["hello", "world"])
|
|
44
|
+
assert result.exit_code == 0
|
|
45
|
+
# SHOULD ONLY PROCESS FIRST ARGUMENT
|
|
46
|
+
assert "HELLO" in result.output
|
autotools/autoip/core.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import socket
|
|
2
2
|
import requests
|
|
3
|
+
import json
|
|
4
|
+
import ipaddress
|
|
3
5
|
import netifaces
|
|
4
6
|
import time
|
|
5
7
|
import speedtest
|
|
@@ -125,94 +127,185 @@ def run_speedtest():
|
|
|
125
127
|
print(f"\nSpeed test failed: {str(e)}")
|
|
126
128
|
return False
|
|
127
129
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
# GET PUBLIC IP ADDRESS USING IPIFY API
|
|
131
|
+
def get_public_ip():
|
|
132
|
+
"""GET PUBLIC IP ADDRESS USING IPIFY API"""
|
|
133
|
+
try:
|
|
134
|
+
response = requests.get('https://api.ipify.org')
|
|
135
|
+
return response.text
|
|
136
|
+
except requests.RequestException:
|
|
137
|
+
# FALLBACK TO ANOTHER SERVICE IF IPIFY FAILS
|
|
138
|
+
try:
|
|
139
|
+
response = requests.get('https://api.ipapi.com/api/check')
|
|
140
|
+
return response.json()['ip']
|
|
141
|
+
except:
|
|
142
|
+
return None
|
|
143
|
+
|
|
144
|
+
# GET LOCAL IP ADDRESS
|
|
145
|
+
def get_local_ip():
|
|
146
|
+
"""GET LOCAL IP ADDRESS"""
|
|
147
|
+
try:
|
|
148
|
+
# GET DEFAULT INTERFACE
|
|
149
|
+
gateways = netifaces.gateways()
|
|
150
|
+
default_interface = gateways['default'][netifaces.AF_INET][1]
|
|
151
|
+
|
|
152
|
+
# GET IP FROM DEFAULT INTERFACE
|
|
153
|
+
addrs = netifaces.ifaddresses(default_interface)
|
|
154
|
+
return addrs[netifaces.AF_INET][0]['addr']
|
|
155
|
+
except:
|
|
156
|
+
# FALLBACK METHOD
|
|
157
|
+
try:
|
|
158
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
159
|
+
s.connect(("8.8.8.8", 80))
|
|
160
|
+
ip = s.getsockname()[0]
|
|
161
|
+
s.close()
|
|
162
|
+
return ip
|
|
163
|
+
except:
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
# GET IP INFORMATION USING IPAPI.CO
|
|
167
|
+
def get_ip_info(ip=None):
|
|
168
|
+
"""GET IP INFORMATION USING IPAPI.CO
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
ip (str, optional): IP address to get info for. If None, uses current IP.
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
dict: Dictionary containing IP information
|
|
175
|
+
|
|
176
|
+
Raises:
|
|
177
|
+
ValueError: If IP is invalid or private
|
|
178
|
+
"""
|
|
179
|
+
if ip:
|
|
180
|
+
# VALIDATE IP
|
|
181
|
+
try:
|
|
182
|
+
ip_obj = ipaddress.ip_address(ip)
|
|
183
|
+
if ip_obj.is_private:
|
|
184
|
+
raise ValueError("Cannot get info for private IP addresses")
|
|
185
|
+
except ValueError as e:
|
|
186
|
+
raise ValueError(f"Invalid IP address: {str(e)}")
|
|
187
|
+
|
|
188
|
+
try:
|
|
189
|
+
# USE IPAPI.CO FOR IP INFO
|
|
190
|
+
url = f'https://ipapi.co/{ip}/json' if ip else 'https://ipapi.co/json'
|
|
191
|
+
response = requests.get(url)
|
|
192
|
+
data = response.json()
|
|
193
|
+
|
|
194
|
+
if 'error' in data:
|
|
195
|
+
raise ValueError(f"Error getting IP info: {data['error']}")
|
|
196
|
+
|
|
197
|
+
return data
|
|
198
|
+
except requests.RequestException as e:
|
|
199
|
+
raise ValueError(f"Error connecting to IP info service: {str(e)}")
|
|
200
|
+
|
|
201
|
+
# MAIN FUNCTION TO RUN IP TOOLS
|
|
202
|
+
def run(test=False, speed=False, monitor=False, interval=1, ports=False, dns=False, location=False, no_ip=False):
|
|
203
|
+
"""MAIN FUNCTION TO RUN IP TOOLS
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
test (bool): Run connectivity tests
|
|
207
|
+
speed (bool): Run speed test
|
|
208
|
+
monitor (bool): Monitor network traffic
|
|
209
|
+
interval (int): Monitoring interval in seconds
|
|
210
|
+
ports (bool): Check common ports status
|
|
211
|
+
dns (bool): Show DNS servers
|
|
212
|
+
location (bool): Show IP location info
|
|
213
|
+
no_ip (bool): Hide IP addresses
|
|
214
|
+
"""
|
|
215
|
+
output = []
|
|
133
216
|
|
|
134
|
-
#
|
|
217
|
+
# GET IP ADDRESSES IF NOT HIDDEN
|
|
135
218
|
if not no_ip:
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
219
|
+
local_ips = get_local_ips()
|
|
220
|
+
public_ips = get_public_ips()
|
|
221
|
+
|
|
222
|
+
output.append("\nLocal IPs:")
|
|
223
|
+
if local_ips['ipv4']:
|
|
224
|
+
for ip in local_ips['ipv4']:
|
|
225
|
+
output.append(f"IPv4: {ip}")
|
|
140
226
|
else:
|
|
141
|
-
|
|
227
|
+
output.append("IPv4: Not available")
|
|
142
228
|
|
|
143
|
-
if
|
|
144
|
-
for ip in
|
|
145
|
-
|
|
229
|
+
if local_ips['ipv6']:
|
|
230
|
+
for ip in local_ips['ipv6']:
|
|
231
|
+
output.append(f"IPv6: {ip}")
|
|
146
232
|
else:
|
|
147
|
-
|
|
233
|
+
output.append("IPv6: Not available")
|
|
148
234
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
235
|
+
output.append("\nPublic IPs:")
|
|
236
|
+
output.append(f"IPv4: {public_ips['ipv4'] or 'Not available'}")
|
|
237
|
+
output.append(f"IPv6: {public_ips['ipv6'] or 'Not available'}")
|
|
152
238
|
|
|
153
239
|
# RUN CONNECTIVITY TESTS IF REQUESTED
|
|
154
240
|
if test:
|
|
155
|
-
|
|
241
|
+
output.append("\nConnectivity Tests:")
|
|
156
242
|
results = test_connectivity()
|
|
157
243
|
for name, success, latency in results:
|
|
158
244
|
status = f"✓ {latency}ms" if success else "✗ Failed"
|
|
159
|
-
|
|
245
|
+
output.append(f"{name:<15} {status}")
|
|
160
246
|
|
|
161
247
|
# RUN SPEED TEST IF REQUESTED
|
|
162
248
|
if speed:
|
|
163
|
-
|
|
249
|
+
output.append("\nRunning speed test...")
|
|
250
|
+
if run_speedtest():
|
|
251
|
+
output.append("Speed test completed successfully")
|
|
252
|
+
else:
|
|
253
|
+
output.append("Speed test failed")
|
|
164
254
|
|
|
165
255
|
# DISPLAY LOCATION INFO IF REQUESTED
|
|
166
256
|
if location:
|
|
167
257
|
try:
|
|
168
|
-
loc =
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
except:
|
|
175
|
-
|
|
258
|
+
loc = get_ip_info()
|
|
259
|
+
output.append("\nLocation Info:")
|
|
260
|
+
output.append(f"City: {loc.get('city', 'Unknown')}")
|
|
261
|
+
output.append(f"Region: {loc.get('region', 'Unknown')}")
|
|
262
|
+
output.append(f"Country: {loc.get('country', 'Unknown')}")
|
|
263
|
+
output.append(f"ISP: {loc.get('org', 'Unknown')}")
|
|
264
|
+
except Exception as e:
|
|
265
|
+
output.append(f"\nLocation lookup failed: {str(e)}")
|
|
176
266
|
|
|
177
267
|
# DISPLAY DNS SERVERS IF REQUESTED
|
|
178
268
|
if dns:
|
|
179
|
-
|
|
269
|
+
output.append("\nDNS Servers:")
|
|
180
270
|
try:
|
|
181
271
|
with open('/etc/resolv.conf', 'r') as f:
|
|
182
272
|
for line in f:
|
|
183
273
|
if 'nameserver' in line:
|
|
184
|
-
|
|
274
|
+
output.append(f"DNS: {line.split()[1]}")
|
|
185
275
|
except:
|
|
186
|
-
|
|
276
|
+
output.append("Could not read DNS configuration")
|
|
187
277
|
|
|
188
278
|
# CHECK COMMON PORTS IF REQUESTED
|
|
189
279
|
if ports:
|
|
190
280
|
common_ports = [80, 443, 22, 21, 25, 3306]
|
|
191
|
-
|
|
281
|
+
output.append("\nCommon Ports Status (localhost):")
|
|
192
282
|
for port in common_ports:
|
|
193
283
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
194
284
|
result = sock.connect_ex(('127.0.0.1', port))
|
|
195
285
|
status = "Open" if result == 0 else "Closed"
|
|
196
|
-
|
|
286
|
+
output.append(f"Port {port}: {status}")
|
|
197
287
|
sock.close()
|
|
198
288
|
|
|
199
289
|
# MONITOR NETWORK TRAFFIC IF REQUESTED
|
|
200
290
|
if monitor:
|
|
201
|
-
|
|
291
|
+
output.append("\nNetwork Monitor (Press Ctrl+C to stop):")
|
|
202
292
|
try:
|
|
203
293
|
prev_bytes_sent = psutil.net_io_counters().bytes_sent
|
|
204
294
|
prev_bytes_recv = psutil.net_io_counters().bytes_recv
|
|
205
295
|
while True:
|
|
206
|
-
time.sleep(
|
|
296
|
+
time.sleep(interval)
|
|
207
297
|
bytes_sent = psutil.net_io_counters().bytes_sent
|
|
208
298
|
bytes_recv = psutil.net_io_counters().bytes_recv
|
|
209
299
|
|
|
210
|
-
|
|
211
|
-
|
|
300
|
+
# CALCULATE UPLOAD AND DOWNLOAD SPEEDS
|
|
301
|
+
upload_speed = (bytes_sent - prev_bytes_sent) / (1024 * interval)
|
|
302
|
+
download_speed = (bytes_recv - prev_bytes_recv) / (1024 * interval)
|
|
212
303
|
|
|
213
|
-
|
|
304
|
+
output.append(f"\rUp: {upload_speed:.2f} KB/s | Down: {download_speed:.2f} KB/s")
|
|
214
305
|
|
|
215
306
|
prev_bytes_sent = bytes_sent
|
|
216
307
|
prev_bytes_recv = bytes_recv
|
|
217
308
|
except KeyboardInterrupt:
|
|
218
|
-
|
|
309
|
+
output.append("\nMonitoring stopped")
|
|
310
|
+
|
|
311
|
+
return "\n".join(output)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# INIT FILE FOR TESTS
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from unittest.mock import patch, Mock
|
|
3
|
+
from autotools.autoip.core import get_public_ip, get_local_ip, get_ip_info
|
|
4
|
+
|
|
5
|
+
# MOCK DATA
|
|
6
|
+
MOCK_IP_INFO = {
|
|
7
|
+
'ip': '8.8.8.8',
|
|
8
|
+
'city': 'Mountain View',
|
|
9
|
+
'region': 'California',
|
|
10
|
+
'country': 'US',
|
|
11
|
+
'loc': '37.4056,-122.0775',
|
|
12
|
+
'org': 'Google LLC',
|
|
13
|
+
'timezone': 'America/Los_Angeles'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
# UNIT TESTS
|
|
17
|
+
|
|
18
|
+
# TEST FOR PUBLIC IP RETRIEVAL
|
|
19
|
+
@patch('requests.get')
|
|
20
|
+
def test_get_public_ip(mock_get):
|
|
21
|
+
"""TEST PUBLIC IP RETRIEVAL"""
|
|
22
|
+
mock_get.return_value.text = "1.2.3.4"
|
|
23
|
+
ip = get_public_ip()
|
|
24
|
+
assert ip == "1.2.3.4"
|
|
25
|
+
mock_get.assert_called_once()
|
|
26
|
+
|
|
27
|
+
# TEST FOR LOCAL IP RETRIEVAL
|
|
28
|
+
@patch('socket.socket')
|
|
29
|
+
@patch('netifaces.gateways')
|
|
30
|
+
@patch('netifaces.ifaddresses')
|
|
31
|
+
def test_get_local_ip(mock_ifaddresses, mock_gateways, mock_socket):
|
|
32
|
+
"""TEST LOCAL IP RETRIEVAL"""
|
|
33
|
+
# MOCK NETIFACES
|
|
34
|
+
mock_gateways.return_value = {'default': {2: ('192.168.1.1', 'eth0')}}
|
|
35
|
+
mock_ifaddresses.return_value = {2: [{'addr': '192.168.1.100'}]}
|
|
36
|
+
|
|
37
|
+
ip = get_local_ip()
|
|
38
|
+
assert ip == "192.168.1.100"
|
|
39
|
+
|
|
40
|
+
# TEST FOR IP INFO RETRIEVAL
|
|
41
|
+
@patch('requests.get')
|
|
42
|
+
def test_get_ip_info(mock_get):
|
|
43
|
+
"""TEST IP INFO RETRIEVAL"""
|
|
44
|
+
mock_get.return_value.json.return_value = MOCK_IP_INFO
|
|
45
|
+
info = get_ip_info()
|
|
46
|
+
assert isinstance(info, dict)
|
|
47
|
+
assert info == MOCK_IP_INFO
|
|
48
|
+
|
|
49
|
+
# TEST FOR IP INFO WITH SPECIFIC IP
|
|
50
|
+
@patch('requests.get')
|
|
51
|
+
def test_get_ip_info_with_ip(mock_get):
|
|
52
|
+
"""TEST IP INFO WITH SPECIFIC IP"""
|
|
53
|
+
mock_get.return_value.json.return_value = MOCK_IP_INFO
|
|
54
|
+
test_ip = "8.8.8.8" # GOOGLE DNS
|
|
55
|
+
info = get_ip_info(test_ip)
|
|
56
|
+
assert isinstance(info, dict)
|
|
57
|
+
assert info['ip'] == test_ip
|
|
58
|
+
assert 'Google' in info['org']
|
|
59
|
+
|
|
60
|
+
# TEST FOR IP INFO WITH INVALID IP
|
|
61
|
+
def test_get_ip_info_invalid():
|
|
62
|
+
"""TEST IP INFO WITH INVALID IP"""
|
|
63
|
+
with pytest.raises(ValueError):
|
|
64
|
+
get_ip_info("invalid.ip.address")
|
|
65
|
+
|
|
66
|
+
# TEST FOR IP INFO WITH PRIVATE IP
|
|
67
|
+
def test_get_ip_info_private():
|
|
68
|
+
"""TEST IP INFO WITH PRIVATE IP"""
|
|
69
|
+
private_ips = ["192.168.1.1", "10.0.0.1", "172.16.0.1"]
|
|
70
|
+
for ip in private_ips:
|
|
71
|
+
with pytest.raises(ValueError):
|
|
72
|
+
get_ip_info(ip)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from unittest.mock import patch, Mock
|
|
3
|
+
from click.testing import CliRunner
|
|
4
|
+
from autotools.cli import autoip
|
|
5
|
+
|
|
6
|
+
# MOCK DATA
|
|
7
|
+
MOCK_IP_INFO = {
|
|
8
|
+
'ip': '8.8.8.8',
|
|
9
|
+
'city': 'Mountain View',
|
|
10
|
+
'region': 'California',
|
|
11
|
+
'country': 'US',
|
|
12
|
+
'loc': '37.4056,-122.0775',
|
|
13
|
+
'org': 'Google LLC',
|
|
14
|
+
'timezone': 'America/Los_Angeles'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
# INTEGRATION TESTS
|
|
18
|
+
|
|
19
|
+
# TEST FOR BASIC CLI FUNCTIONALITY
|
|
20
|
+
@patch('autotools.autoip.core.get_local_ips')
|
|
21
|
+
@patch('autotools.autoip.core.get_public_ips')
|
|
22
|
+
def test_autoip_cli_basic(mock_public_ips, mock_local_ips):
|
|
23
|
+
"""TEST BASIC CLI FUNCTIONALITY"""
|
|
24
|
+
mock_local_ips.return_value = {
|
|
25
|
+
'ipv4': ['192.168.1.100'],
|
|
26
|
+
'ipv6': ['fe80::1']
|
|
27
|
+
}
|
|
28
|
+
mock_public_ips.return_value = {
|
|
29
|
+
'ipv4': '1.2.3.4',
|
|
30
|
+
'ipv6': None
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
runner = CliRunner()
|
|
34
|
+
result = runner.invoke(autoip)
|
|
35
|
+
assert result.exit_code == 0
|
|
36
|
+
assert "192.168.1.100" in result.output
|
|
37
|
+
assert "1.2.3.4" in result.output
|
|
38
|
+
assert "fe80::1" in result.output
|
|
39
|
+
|
|
40
|
+
# TEST FOR CONNECTIVITY TEST
|
|
41
|
+
@patch('autotools.autoip.core.test_connectivity')
|
|
42
|
+
def test_autoip_cli_test(mock_test):
|
|
43
|
+
"""TEST CONNECTIVITY TEST"""
|
|
44
|
+
mock_test.return_value = [
|
|
45
|
+
('Google DNS', True, 20),
|
|
46
|
+
('CloudFlare', False, None)
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
runner = CliRunner()
|
|
50
|
+
result = runner.invoke(autoip, ['--test'])
|
|
51
|
+
assert result.exit_code == 0
|
|
52
|
+
assert "Google DNS" in result.output
|
|
53
|
+
assert "CloudFlare" in result.output
|
|
54
|
+
assert "✓ 20ms" in result.output
|
|
55
|
+
assert "✗ Failed" in result.output
|
|
56
|
+
|
|
57
|
+
# TEST FOR SPEED TEST
|
|
58
|
+
@patch('autotools.autoip.core.run_speedtest')
|
|
59
|
+
def test_autoip_cli_speed(mock_speed):
|
|
60
|
+
"""TEST SPEED TEST"""
|
|
61
|
+
mock_speed.return_value = True
|
|
62
|
+
|
|
63
|
+
runner = CliRunner()
|
|
64
|
+
result = runner.invoke(autoip, ['--speed'])
|
|
65
|
+
assert result.exit_code == 0
|
|
66
|
+
assert "Running speed test" in result.output
|
|
67
|
+
assert "completed successfully" in result.output
|
|
68
|
+
|
|
69
|
+
# TEST FOR LOCATION INFO DISPLAY
|
|
70
|
+
@patch('autotools.autoip.core.get_ip_info')
|
|
71
|
+
def test_autoip_cli_location(mock_get_info):
|
|
72
|
+
"""TEST LOCATION INFO DISPLAY"""
|
|
73
|
+
mock_get_info.return_value = MOCK_IP_INFO
|
|
74
|
+
|
|
75
|
+
runner = CliRunner()
|
|
76
|
+
result = runner.invoke(autoip, ['--location'])
|
|
77
|
+
assert result.exit_code == 0
|
|
78
|
+
assert "Mountain View" in result.output
|
|
79
|
+
assert "California" in result.output
|
|
80
|
+
assert "Google LLC" in result.output
|
|
81
|
+
|
|
82
|
+
# TEST FOR HELP DISPLAY
|
|
83
|
+
def test_autoip_cli_help():
|
|
84
|
+
"""TEST HELP DISPLAY"""
|
|
85
|
+
runner = CliRunner()
|
|
86
|
+
result = runner.invoke(autoip, ['--help'])
|
|
87
|
+
assert result.exit_code == 0
|
|
88
|
+
assert "Usage:" in result.output
|
|
89
|
+
assert "Options:" in result.output
|
|
90
|
+
assert "--test" in result.output
|
|
91
|
+
assert "--speed" in result.output
|
|
92
|
+
assert "--location" in result.output
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# INIT FILE FOR TESTS
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from autotools.autolower.core import autolower_transform
|
|
3
|
+
|
|
4
|
+
# UNIT TESTS
|
|
5
|
+
|
|
6
|
+
# TEST FOR BASIC STRING TRANSFORMATION
|
|
7
|
+
def test_autolower_transform_basic():
|
|
8
|
+
"""TEST BASIC STRING TRANSFORMATION"""
|
|
9
|
+
assert autolower_transform("HELLO") == "hello"
|
|
10
|
+
assert autolower_transform("Hello World") == "hello world"
|
|
11
|
+
assert autolower_transform("123") == "123"
|
|
12
|
+
|
|
13
|
+
# TEST FOR EMPTY STRING
|
|
14
|
+
def test_autolower_transform_empty():
|
|
15
|
+
"""TEST EMPTY STRING"""
|
|
16
|
+
assert autolower_transform("") == ""
|
|
17
|
+
|
|
18
|
+
# TEST FOR SPECIAL CHARACTERS
|
|
19
|
+
def test_autolower_transform_special_chars():
|
|
20
|
+
"""TEST STRING WITH SPECIAL CHARACTERS"""
|
|
21
|
+
assert autolower_transform("HELLO@WORLD.COM") == "hello@world.com"
|
|
22
|
+
assert autolower_transform("HELLO-WORLD!") == "hello-world!"
|
|
23
|
+
|
|
24
|
+
# TEST FOR MIXED CASE STRING
|
|
25
|
+
def test_autolower_transform_mixed_case():
|
|
26
|
+
"""TEST MIXED CASE STRING"""
|
|
27
|
+
assert autolower_transform("HeLLo WoRLD") == "hello world"
|
|
28
|
+
|
|
29
|
+
# TEST FOR WHITESPACE
|
|
30
|
+
def test_autolower_transform_whitespace():
|
|
31
|
+
"""TEST STRING WITH WHITESPACE"""
|
|
32
|
+
assert autolower_transform(" HELLO WORLD ") == " hello world "
|
|
33
|
+
assert autolower_transform("\tHELLO\nWORLD") == "\thello\nworld"
|
|
34
|
+
|
|
35
|
+
# TEST FOR NUMBERS
|
|
36
|
+
def test_autolower_transform_numbers():
|
|
37
|
+
"""TEST STRING WITH NUMBERS"""
|
|
38
|
+
assert autolower_transform("HELLO123WORLD") == "hello123world"
|
|
39
|
+
assert autolower_transform("123HELLO456WORLD789") == "123hello456world789"
|
|
40
|
+
|
|
41
|
+
# TEST FOR UNICODE CHARACTERS
|
|
42
|
+
def test_autolower_transform_unicode():
|
|
43
|
+
"""TEST UNICODE CHARACTERS"""
|
|
44
|
+
assert autolower_transform("HÉLLO WÖRLD") == "héllo wörld"
|
|
45
|
+
assert autolower_transform("こんにちは") == "こんにちは" # JAPANESE SHOULD REMAIN UNCHANGED
|