Open-AutoTools 0.0.2.post1__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.3rc1.dist-info/METADATA +307 -0
- Open_AutoTools-0.0.3rc1.dist-info/RECORD +31 -0
- {Open_AutoTools-0.0.2.post1.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.post1.dist-info/METADATA +0 -37
- Open_AutoTools-0.0.2.post1.dist-info/RECORD +0 -20
- {Open_AutoTools-0.0.2.post1.dist-info → Open_AutoTools-0.0.3rc1.dist-info}/LICENSE +0 -0
- {Open_AutoTools-0.0.2.post1.dist-info → Open_AutoTools-0.0.3rc1.dist-info}/WHEEL +0 -0
- {Open_AutoTools-0.0.2.post1.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
autotools/cli.py
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import click
|
|
3
3
|
import base64
|
|
4
|
+
import json as json_module
|
|
5
|
+
from importlib.metadata import version as get_version, PackageNotFoundError
|
|
6
|
+
from packaging.version import parse as parse_version
|
|
4
7
|
from autotools.autocaps.core import autocaps_transform
|
|
5
8
|
from autotools.autolower.core import autolower_transform
|
|
6
|
-
from autotools.
|
|
7
|
-
|
|
9
|
+
from autotools.autodownload.core import (
|
|
10
|
+
download_youtube_video,
|
|
11
|
+
download_file,
|
|
12
|
+
validate_youtube_url
|
|
13
|
+
)
|
|
14
|
+
from autotools.autopassword.core import (
|
|
8
15
|
generate_password,
|
|
9
16
|
generate_encryption_key,
|
|
10
17
|
analyze_password_strength
|
|
@@ -12,56 +19,246 @@ from autotools.password.core import (
|
|
|
12
19
|
from translate import Translator
|
|
13
20
|
from autotools.autotranslate.core import translate_text, get_supported_languages
|
|
14
21
|
import yt_dlp
|
|
15
|
-
from autotools import
|
|
22
|
+
from autotools import autodownload, autolower, autocaps, autoip
|
|
16
23
|
import argparse
|
|
24
|
+
from autotools.autospell.core import SpellChecker
|
|
25
|
+
from urllib.parse import urlparse
|
|
26
|
+
import requests
|
|
27
|
+
from datetime import datetime
|
|
28
|
+
import pytest
|
|
29
|
+
import sys
|
|
30
|
+
import subprocess
|
|
31
|
+
from dotenv import load_dotenv
|
|
32
|
+
|
|
33
|
+
# LOAD ENVIRONMENT VARIABLES FROM .ENV FILE
|
|
34
|
+
load_dotenv()
|
|
35
|
+
|
|
36
|
+
# VERSION CALLBACK
|
|
37
|
+
def print_version(ctx, param, value):
|
|
38
|
+
"""PRINT VERSION AND CHECK FOR UPDATES"""
|
|
39
|
+
|
|
40
|
+
# EXIT IF VERSION IS NOT REQUESTED
|
|
41
|
+
if not value or ctx.resilient_parsing:
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
# GET CURRENT VERSION
|
|
45
|
+
try:
|
|
46
|
+
pkg_version = get_version('Open-AutoTools')
|
|
47
|
+
click.echo(f"Open-AutoTools version {pkg_version}")
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
# CHECK IF PACKAGE IS FROM TESTPYPI
|
|
51
|
+
is_testpypi = False
|
|
52
|
+
try:
|
|
53
|
+
import pkg_resources
|
|
54
|
+
dist = pkg_resources.get_distribution('Open-AutoTools')
|
|
55
|
+
is_testpypi = 'test.pypi.org' in dist.location
|
|
56
|
+
except:
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
# DETERMINE PYPI URL BASED ON SOURCE
|
|
60
|
+
pypi_url = "https://test.pypi.org/pypi/Open-AutoTools/json" if is_testpypi else "https://pypi.org/pypi/Open-AutoTools/json"
|
|
61
|
+
|
|
62
|
+
# CHECK LATEST VERSION FROM PYPI
|
|
63
|
+
response = requests.get(pypi_url)
|
|
64
|
+
if response.status_code == 200:
|
|
65
|
+
data = response.json()
|
|
66
|
+
latest_version = data["info"]["version"]
|
|
67
|
+
# GET RELEASE DATE
|
|
68
|
+
releases = data["releases"]
|
|
69
|
+
if latest_version in releases and releases[latest_version]:
|
|
70
|
+
try:
|
|
71
|
+
upload_time = releases[latest_version][0]["upload_time"]
|
|
72
|
+
# TRY DIFFERENT DATE FORMATS
|
|
73
|
+
try:
|
|
74
|
+
published_date = datetime.strptime(upload_time, "%Y-%m-%dT%H:%M:%S")
|
|
75
|
+
except ValueError:
|
|
76
|
+
try:
|
|
77
|
+
published_date = datetime.strptime(upload_time, "%Y-%m-%dT%H:%M:%S.%fZ")
|
|
78
|
+
except ValueError:
|
|
79
|
+
published_date = datetime.strptime(upload_time, "%Y-%m-%d %H:%M:%S")
|
|
80
|
+
formatted_date = published_date.strftime("%d %B %Y at %H:%M:%S")
|
|
81
|
+
click.echo(f"Released: {formatted_date}")
|
|
82
|
+
except Exception:
|
|
83
|
+
# IF DATE PARSING FAILS, SKIP SHOWING THE DATE
|
|
84
|
+
pass
|
|
85
|
+
|
|
86
|
+
# PARSE VERSIONS FOR COMPARISON
|
|
87
|
+
current_parsed = parse_version(pkg_version)
|
|
88
|
+
latest_parsed = parse_version(latest_version)
|
|
89
|
+
|
|
90
|
+
# COMPARE VERSIONS AND PRINT UPDATE MESSAGE IF NEEDED
|
|
91
|
+
if latest_parsed > current_parsed:
|
|
92
|
+
update_cmd = "pip install --upgrade -i https://test.pypi.org/simple/ Open-AutoTools" if is_testpypi else "pip install --upgrade Open-AutoTools"
|
|
93
|
+
click.echo(click.style(f"\nUpdate available: v{latest_version}", fg='red', bold=True))
|
|
94
|
+
click.echo(click.style(f"Run '{update_cmd}' to update", fg='red'))
|
|
95
|
+
except Exception as e:
|
|
96
|
+
click.echo(f"Error checking updates: {str(e)}")
|
|
97
|
+
except PackageNotFoundError:
|
|
98
|
+
click.echo("Open-AutoTools version information not available")
|
|
99
|
+
ctx.exit()
|
|
17
100
|
|
|
18
101
|
# CLI FUNCTION DEFINITION
|
|
19
102
|
@click.group()
|
|
103
|
+
@click.option('--version', '--v', is_flag=True, callback=print_version,
|
|
104
|
+
expose_value=False, is_eager=True, help='Show version and check for updates')
|
|
105
|
+
@click.option('--help', '-h', is_flag=True, callback=lambda ctx, param, value:
|
|
106
|
+
None if not value else (click.echo(ctx.get_help() + '\n' +
|
|
107
|
+
(check_for_updates() or '')) or ctx.exit()),
|
|
108
|
+
is_eager=True, expose_value=False, help='Show this message and exit.')
|
|
20
109
|
def cli():
|
|
21
|
-
"""
|
|
110
|
+
"""A suite of automated tools for various tasks.
|
|
111
|
+
|
|
112
|
+
Run 'autotools COMMAND --help' for more information on each command."""
|
|
22
113
|
pass
|
|
23
114
|
|
|
24
115
|
# AUTOTOOLS COMMAND LINE INTERFACE FUNCTION DEFINITION FOR SHOW HELP MESSAGE
|
|
25
116
|
@cli.command()
|
|
26
117
|
def autotools():
|
|
27
|
-
|
|
118
|
+
"""Display available commands and tool information."""
|
|
119
|
+
# SHOW COMMANDS LIST WITH BETTER FORMATTING
|
|
120
|
+
ctx = click.get_current_context()
|
|
121
|
+
commands = cli.list_commands(ctx)
|
|
122
|
+
|
|
123
|
+
click.echo(click.style("\nOpen-AutoTools Commands:", fg='blue', bold=True))
|
|
124
|
+
for cmd in sorted(commands):
|
|
125
|
+
if cmd != 'autotools':
|
|
126
|
+
cmd_obj = cli.get_command(ctx, cmd)
|
|
127
|
+
help_text = cmd_obj.help or cmd_obj.short_help or ''
|
|
128
|
+
click.echo(f"\n{click.style(cmd, fg='green', bold=True)}")
|
|
129
|
+
click.echo(f" {help_text}")
|
|
130
|
+
|
|
131
|
+
# GET OPTIONS FOR EACH COMMAND
|
|
132
|
+
if hasattr(cmd_obj, 'params'):
|
|
133
|
+
click.echo(click.style("\n Options:", fg='yellow'))
|
|
134
|
+
for param in cmd_obj.params:
|
|
135
|
+
if isinstance(param, click.Option):
|
|
136
|
+
opts = '/'.join(param.opts)
|
|
137
|
+
help_text = param.help or ''
|
|
138
|
+
click.echo(f" {click.style(opts, fg='yellow')}")
|
|
139
|
+
click.echo(f" {help_text}")
|
|
140
|
+
|
|
141
|
+
# SHOW USAGE EXAMPLES
|
|
142
|
+
click.echo(click.style("\nUsage Examples:", fg='blue', bold=True))
|
|
143
|
+
click.echo(" autotools --help Show this help message")
|
|
144
|
+
click.echo(" autotools --version Show version information")
|
|
145
|
+
click.echo(" autotools COMMAND Run a specific command")
|
|
146
|
+
click.echo(" autotools COMMAND --help Show help for a specific command")
|
|
147
|
+
|
|
148
|
+
# CHECK FOR UPDATES
|
|
149
|
+
update_msg = check_for_updates()
|
|
150
|
+
if update_msg:
|
|
151
|
+
click.echo(click.style("\nUpdate Available:", fg='red', bold=True))
|
|
152
|
+
click.echo(update_msg)
|
|
153
|
+
|
|
154
|
+
def check_for_updates():
|
|
155
|
+
"""CHECK IF AN UPDATE IS AVAILABLE AND RETURN UPDATE MESSAGE IF NEEDED"""
|
|
156
|
+
|
|
157
|
+
# GET CURRENT VERSION
|
|
158
|
+
try:
|
|
159
|
+
current_version = get_version('Open-AutoTools')
|
|
160
|
+
|
|
161
|
+
# CHECK IF PACKAGE IS FROM TESTPYPI
|
|
162
|
+
is_testpypi = False
|
|
163
|
+
try:
|
|
164
|
+
# ATTEMPT TO GET PACKAGE METADATA
|
|
165
|
+
import pkg_resources
|
|
166
|
+
dist = pkg_resources.get_distribution('Open-AutoTools')
|
|
167
|
+
is_testpypi = 'test.pypi.org' in dist.location
|
|
168
|
+
except:
|
|
169
|
+
pass
|
|
170
|
+
|
|
171
|
+
# DETERMINE PYPI URL BASED ON SOURCE
|
|
172
|
+
pypi_url = "https://test.pypi.org/pypi/Open-AutoTools/json" if is_testpypi else "https://pypi.org/pypi/Open-AutoTools/json"
|
|
173
|
+
|
|
174
|
+
# CHECK FOR UPDATES FROM PYPI
|
|
175
|
+
response = requests.get(pypi_url)
|
|
176
|
+
|
|
177
|
+
# CHECK IF RESPONSE IS SUCCESSFUL
|
|
178
|
+
if response.status_code == 200:
|
|
179
|
+
data = response.json()
|
|
180
|
+
latest_version = data["info"]["version"]
|
|
181
|
+
|
|
182
|
+
# PARSE VERSIONS FOR COMPARISON
|
|
183
|
+
current_parsed = parse_version(current_version)
|
|
184
|
+
latest_parsed = parse_version(latest_version)
|
|
185
|
+
|
|
186
|
+
# PRINT UPDATE MESSAGE IF NEEDED
|
|
187
|
+
if latest_parsed > current_parsed:
|
|
188
|
+
update_cmd = "pip install --upgrade -i https://test.pypi.org/simple/ Open-AutoTools" if is_testpypi else "pip install --upgrade Open-AutoTools"
|
|
189
|
+
return (
|
|
190
|
+
click.style(f"\nUpdate available: v{latest_version}", fg='red', bold=True) + "\n" +
|
|
191
|
+
click.style(f"Run '{update_cmd}' to update", fg='red')
|
|
192
|
+
)
|
|
193
|
+
except Exception as e:
|
|
194
|
+
# FOR DEBUGGING, LOG ERROR
|
|
195
|
+
print(f"Error checking updates: {str(e)}")
|
|
196
|
+
pass
|
|
197
|
+
return None
|
|
28
198
|
|
|
29
199
|
# AUTOCAPS COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
30
200
|
@cli.command()
|
|
31
|
-
@click.argument('text')
|
|
201
|
+
@click.argument('text', nargs=-1)
|
|
32
202
|
def autocaps(text):
|
|
33
|
-
|
|
203
|
+
"""Convert text to UPPERCASE."""
|
|
204
|
+
result = autocaps_transform(" ".join(text))
|
|
34
205
|
click.echo(result)
|
|
206
|
+
|
|
207
|
+
# UPDATE CHECK AT THE END
|
|
208
|
+
update_msg = check_for_updates()
|
|
209
|
+
if update_msg:
|
|
210
|
+
click.echo(update_msg)
|
|
35
211
|
|
|
36
212
|
# AUTOLOWER CASE COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
37
213
|
@cli.command()
|
|
38
|
-
@click.argument('text')
|
|
214
|
+
@click.argument('text', nargs=-1)
|
|
39
215
|
def autolower(text):
|
|
40
|
-
|
|
216
|
+
"""Convert text to lowercase."""
|
|
217
|
+
result = autolower_transform(" ".join(text))
|
|
41
218
|
click.echo(result)
|
|
219
|
+
|
|
220
|
+
# UPDATE CHECK AT THE END
|
|
221
|
+
update_msg = check_for_updates()
|
|
222
|
+
if update_msg:
|
|
223
|
+
click.echo(update_msg)
|
|
42
224
|
|
|
43
225
|
# AUTODOWNLOAD COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
44
226
|
@cli.command()
|
|
45
227
|
@click.argument('url')
|
|
46
|
-
@click.option('--format', type=click.Choice(['mp4', 'mp3'], case_sensitive=False),
|
|
47
|
-
|
|
228
|
+
@click.option('--format', '-f', type=click.Choice(['mp4', 'mp3'], case_sensitive=False),
|
|
229
|
+
default='mp4', help='Output file format')
|
|
230
|
+
@click.option('--quality', '-q', type=click.Choice(['best', '1440p', '1080p', '720p', '480p', '360p', '240p'],
|
|
231
|
+
case_sensitive=False), default='best', help='Video quality (mp4 only)')
|
|
48
232
|
def autodownload(url, format, quality):
|
|
233
|
+
"""Download videos from YouTube or files from any URL.
|
|
234
|
+
|
|
235
|
+
Supports YouTube video download with quality selection and format conversion (mp4/mp3).
|
|
236
|
+
For non-YouTube URLs, downloads the file directly."""
|
|
49
237
|
if "youtube.com" in url or "youtu.be" in url:
|
|
238
|
+
# VALIDATE YOUTUBE URL FIRST
|
|
239
|
+
if not validate_youtube_url(url):
|
|
240
|
+
click.echo("Invalid YouTube URL", err=True)
|
|
241
|
+
sys.exit(1)
|
|
50
242
|
download_youtube_video(url, format, quality)
|
|
51
243
|
else:
|
|
52
244
|
download_file(url)
|
|
245
|
+
|
|
246
|
+
# UPDATE CHECK AT THE END
|
|
247
|
+
update_msg = check_for_updates()
|
|
248
|
+
if update_msg:
|
|
249
|
+
click.echo(update_msg)
|
|
53
250
|
|
|
54
251
|
# AUTOPASSWORD COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
55
252
|
@cli.command()
|
|
56
253
|
@click.option('--length', '-l', default=12, help='Password length (default: 12)')
|
|
57
|
-
@click.option('--no-uppercase', is_flag=True, help='Exclude uppercase letters')
|
|
58
|
-
@click.option('--no-numbers', is_flag=True, help='Exclude numbers')
|
|
59
|
-
@click.option('--no-special', is_flag=True, help='Exclude special characters')
|
|
60
|
-
@click.option('--min-special', default=1, help='Minimum number of special characters')
|
|
61
|
-
@click.option('--min-numbers', default=1, help='Minimum number of numbers')
|
|
62
|
-
@click.option('--analyze', is_flag=True, help='Analyze password strength')
|
|
63
|
-
@click.option('--gen-key', is_flag=True, help='Generate encryption key')
|
|
64
|
-
@click.option('--password-key', help='Generate key from password')
|
|
254
|
+
@click.option('--no-uppercase', '-u', is_flag=True, help='Exclude uppercase letters')
|
|
255
|
+
@click.option('--no-numbers', '-n', is_flag=True, help='Exclude numbers')
|
|
256
|
+
@click.option('--no-special', '-s', is_flag=True, help='Exclude special characters')
|
|
257
|
+
@click.option('--min-special', '-m', default=1, help='Minimum number of special characters')
|
|
258
|
+
@click.option('--min-numbers', '-d', default=1, help='Minimum number of numbers')
|
|
259
|
+
@click.option('--analyze', '-a', is_flag=True, help='Analyze password strength')
|
|
260
|
+
@click.option('--gen-key', '-g', is_flag=True, help='Generate encryption key')
|
|
261
|
+
@click.option('--password-key', '-p', help='Generate key from password')
|
|
65
262
|
def autopassword(length, no_uppercase, no_numbers, no_special,
|
|
66
263
|
min_special, min_numbers, analyze, gen_key, password_key):
|
|
67
264
|
"""Generate secure passwords and encryption keys."""
|
|
@@ -114,6 +311,11 @@ def autopassword(length, no_uppercase, no_numbers, no_special,
|
|
|
114
311
|
# SHOW PASSWORD
|
|
115
312
|
click.echo(f"Generated Password: {password}")
|
|
116
313
|
show_analysis(password, "Password ")
|
|
314
|
+
|
|
315
|
+
# UPDATE CHECK AT THE END
|
|
316
|
+
update_msg = check_for_updates()
|
|
317
|
+
if update_msg:
|
|
318
|
+
click.echo(update_msg)
|
|
117
319
|
|
|
118
320
|
# TRANSLATE COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
119
321
|
@cli.command()
|
|
@@ -123,10 +325,14 @@ def autopassword(length, no_uppercase, no_numbers, no_special,
|
|
|
123
325
|
@click.option('--list-languages', is_flag=True, help='List all supported languages')
|
|
124
326
|
@click.option('--copy', is_flag=True, help='Copy translation to clipboard')
|
|
125
327
|
@click.option('--detect', is_flag=True, help='Show detected source language')
|
|
328
|
+
@click.option('--output', '-o', type=click.Path(), help='Save translation to file')
|
|
126
329
|
def autotranslate(text: str, to: str, from_lang: str, list_languages: bool,
|
|
127
|
-
copy: bool, detect: bool):
|
|
128
|
-
"""
|
|
330
|
+
copy: bool, detect: bool, output: str):
|
|
331
|
+
"""Translate text to specified language.
|
|
129
332
|
|
|
333
|
+
Supports automatic language detection, multiple target languages,
|
|
334
|
+
clipboard operations and file output. Use --list-languages to see
|
|
335
|
+
all supported language codes."""
|
|
130
336
|
# LIST ALL SUPPORTED LANGUAGES
|
|
131
337
|
if list_languages:
|
|
132
338
|
click.echo("\nSupported Languages:")
|
|
@@ -140,44 +346,222 @@ def autotranslate(text: str, to: str, from_lang: str, list_languages: bool,
|
|
|
140
346
|
return
|
|
141
347
|
|
|
142
348
|
result = translate_text(text, to_lang=to, from_lang=from_lang,
|
|
143
|
-
copy=copy, detect_lang=detect)
|
|
349
|
+
copy=copy, detect_lang=detect, output=output)
|
|
144
350
|
click.echo(result)
|
|
351
|
+
|
|
352
|
+
# UPDATE CHECK AT THE END
|
|
353
|
+
update_msg = check_for_updates()
|
|
354
|
+
if update_msg:
|
|
355
|
+
click.echo(update_msg)
|
|
145
356
|
|
|
146
357
|
# AUTOIP COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
147
358
|
@cli.command()
|
|
148
359
|
@click.option('--test', '-t', is_flag=True, help='Run connectivity tests')
|
|
149
360
|
@click.option('--speed', '-s', is_flag=True, help='Run internet speed test')
|
|
150
361
|
@click.option('--monitor', '-m', is_flag=True, help='Monitor network traffic')
|
|
362
|
+
@click.option('--interval', '-i', default=1, help='Monitoring interval in seconds')
|
|
151
363
|
@click.option('--ports', '-p', is_flag=True, help='Check common ports status')
|
|
152
364
|
@click.option('--dns', '-d', is_flag=True, help='Show DNS servers')
|
|
153
365
|
@click.option('--location', '-l', is_flag=True, help='Show IP location info')
|
|
154
|
-
@click.option('--no-ip', '-n', is_flag=True, help='Hide IP addresses
|
|
155
|
-
def autoip(test, speed, monitor, ports, dns, location, no_ip):
|
|
156
|
-
"""
|
|
157
|
-
|
|
158
|
-
|
|
366
|
+
@click.option('--no-ip', '-n', is_flag=True, help='Hide IP addresses')
|
|
367
|
+
def autoip(test, speed, monitor, interval, ports, dns, location, no_ip):
|
|
368
|
+
"""Display network information and diagnostics.
|
|
369
|
+
|
|
370
|
+
Shows local and public IP addresses, runs network diagnostics,
|
|
371
|
+
performs speed tests, monitors traffic with custom intervals,
|
|
372
|
+
checks ports, displays DNS information and provides geolocation data."""
|
|
373
|
+
from autotools.autoip.core import run
|
|
374
|
+
output = run(test=test, speed=speed, monitor=monitor, interval=interval,
|
|
375
|
+
ports=ports, dns=dns, location=location, no_ip=no_ip)
|
|
376
|
+
click.echo(output)
|
|
377
|
+
|
|
378
|
+
# UPDATE CHECK AT THE END
|
|
379
|
+
update_msg = check_for_updates()
|
|
380
|
+
if update_msg:
|
|
381
|
+
click.echo(update_msg)
|
|
159
382
|
|
|
160
|
-
#
|
|
161
|
-
|
|
162
|
-
|
|
383
|
+
# AUTOSPELL COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
384
|
+
@cli.command()
|
|
385
|
+
@click.argument('texts', nargs=-1)
|
|
386
|
+
@click.option('--lang', '-l', default='auto', help='Language code (auto for detection)')
|
|
387
|
+
@click.option('--fix', '-f', is_flag=True, help='Auto-fix text and copy to clipboard')
|
|
388
|
+
@click.option('--copy', '-c', is_flag=True, help='Copy result to clipboard')
|
|
389
|
+
@click.option('--list-languages', is_flag=True, help='List supported languages')
|
|
390
|
+
@click.option('--json', '-j', is_flag=True, help='Output results as JSON')
|
|
391
|
+
@click.option('--ignore', '-i', multiple=True,
|
|
392
|
+
type=click.Choice(['spelling', 'grammar', 'style', 'punctuation']),
|
|
393
|
+
help='Error types to ignore')
|
|
394
|
+
@click.option('--interactive', '-n', is_flag=True,
|
|
395
|
+
help='Interactive mode - confirm each correction')
|
|
396
|
+
@click.option('--output', '-o', type=click.Path(),
|
|
397
|
+
help='Save corrections to file')
|
|
398
|
+
def autospell(texts: tuple, lang: str, fix: bool, copy: bool, list_languages: bool,
|
|
399
|
+
json: bool, ignore: tuple, interactive: bool, output: str):
|
|
400
|
+
"""Check and fix text for spelling, grammar, style, and punctuation errors.
|
|
401
|
+
|
|
402
|
+
Provides comprehensive text analysis with support for multiple languages,
|
|
403
|
+
interactive corrections, and various output formats (text/JSON).
|
|
404
|
+
Can ignore specific error types: spelling, grammar, style, or punctuation."""
|
|
405
|
+
checker = SpellChecker()
|
|
406
|
+
|
|
407
|
+
# LIST ALL SUPPORTED LANGUAGES
|
|
408
|
+
if list_languages:
|
|
409
|
+
languages = checker.get_supported_languages()
|
|
410
|
+
if json:
|
|
411
|
+
result = {'languages': languages}
|
|
412
|
+
click.echo(json_module.dumps(result, indent=2))
|
|
413
|
+
else:
|
|
414
|
+
click.echo("\nSupported Languages:")
|
|
415
|
+
for lang in languages:
|
|
416
|
+
click.echo(f"{lang['code']:<8} {lang['name']}")
|
|
417
|
+
return
|
|
418
|
+
|
|
419
|
+
# CHECK AND FIX SPELLING/GRAMMAR IN TEXT
|
|
420
|
+
for text in texts:
|
|
421
|
+
if not text:
|
|
422
|
+
click.echo("Error: Please provide text to check")
|
|
423
|
+
continue
|
|
424
|
+
|
|
425
|
+
# FIX SPELLING/GRAMMAR IN TEXT
|
|
426
|
+
if fix:
|
|
427
|
+
# CORRECT TEXT WITH SPELL CHECKER
|
|
428
|
+
corrected = checker.fix_text(text, lang, copy_to_clipboard=True,
|
|
429
|
+
ignore=ignore, interactive=interactive)
|
|
430
|
+
result = {'corrected_text': corrected} # RESULT TO RETURN
|
|
431
|
+
|
|
432
|
+
# OUTPUT RESULTS AS JSON
|
|
433
|
+
if json:
|
|
434
|
+
click.echo(json_module.dumps(result, indent=2))
|
|
435
|
+
else:
|
|
436
|
+
# LANGUAGE INFORMATION
|
|
437
|
+
check_result = checker.check_text(text, lang)
|
|
438
|
+
lang_info = check_result['language']
|
|
439
|
+
click.echo(f"\nLanguage detected: {lang_info['name']} ({lang_info['code']})")
|
|
440
|
+
click.echo(f"Confidence: {lang_info['confidence']:.2%}")
|
|
441
|
+
click.echo("\nCorrected text (copied to clipboard):")
|
|
442
|
+
click.echo(corrected)
|
|
443
|
+
|
|
444
|
+
# SAVE CORRECTIONS TO FILE
|
|
445
|
+
if output:
|
|
446
|
+
with open(output, 'w', encoding='utf-8') as f:
|
|
447
|
+
if json:
|
|
448
|
+
json_module.dump(result, f, indent=2)
|
|
449
|
+
else:
|
|
450
|
+
f.write(corrected)
|
|
451
|
+
else:
|
|
452
|
+
# CHECK SPELLING/GRAMMAR IN TEXT
|
|
453
|
+
check_result = checker.check_text(text, lang)
|
|
454
|
+
|
|
455
|
+
# OUTPUT RESULTS AS JSON
|
|
456
|
+
if json:
|
|
457
|
+
click.echo(json_module.dumps(check_result, indent=2))
|
|
458
|
+
else:
|
|
459
|
+
lang_info = check_result['language']
|
|
460
|
+
click.echo(f"\nLanguage detected: {lang_info['name']} ({lang_info['code']})")
|
|
461
|
+
click.echo(f"Confidence: {lang_info['confidence']:.2%}")
|
|
462
|
+
click.echo(f"Total errors found: {check_result['statistics']['total_errors']}")
|
|
463
|
+
|
|
464
|
+
# CORRECTIONS SUGGESTED
|
|
465
|
+
if check_result['corrections']:
|
|
466
|
+
click.echo("\nCorrections suggested:")
|
|
467
|
+
for i, corr in enumerate(check_result['corrections'], 1):
|
|
468
|
+
click.echo(f"\n{i}. [{corr['severity'].upper()}] {corr['message']}")
|
|
469
|
+
click.echo(f" Context: {corr['context']}")
|
|
470
|
+
if corr['replacements']:
|
|
471
|
+
click.echo(f" Suggestions: {', '.join(corr['replacements'][:3])}")
|
|
472
|
+
|
|
473
|
+
# SAVE CHECK RESULT TO FILE
|
|
474
|
+
if output:
|
|
475
|
+
with open(output, 'w', encoding='utf-8') as f:
|
|
476
|
+
if json:
|
|
477
|
+
json_module.dump(check_result, f, indent=2)
|
|
478
|
+
else:
|
|
479
|
+
# WRITE A HUMAN-READABLE REPORT
|
|
480
|
+
f.write(f"Language: {lang_info['name']} ({lang_info['code']})\n")
|
|
481
|
+
f.write(f"Confidence: {lang_info['confidence']:.2%}\n")
|
|
482
|
+
f.write(f"Total errors: {check_result['statistics']['total_errors']}\n\n")
|
|
483
|
+
|
|
484
|
+
# CORRECTIONS SUGGESTED
|
|
485
|
+
if check_result['corrections']:
|
|
486
|
+
f.write("Corrections suggested:\n")
|
|
487
|
+
for i, corr in enumerate(check_result['corrections'], 1):
|
|
488
|
+
f.write(f"\n{i}. [{corr['severity'].upper()}] {corr['message']}\n")
|
|
489
|
+
f.write(f" Context: {corr['context']}\n")
|
|
490
|
+
if corr['replacements']:
|
|
491
|
+
f.write(f" Suggestions: {', '.join(corr['replacements'][:3])}\n")
|
|
492
|
+
|
|
493
|
+
# UPDATE CHECK AT THE END
|
|
494
|
+
update_msg = check_for_updates()
|
|
495
|
+
if update_msg:
|
|
496
|
+
click.echo(update_msg)
|
|
163
497
|
|
|
164
|
-
|
|
498
|
+
# TEST COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
499
|
+
@cli.command()
|
|
500
|
+
@click.option('--unit', '-u', is_flag=True, help='Run only unit tests')
|
|
501
|
+
@click.option('--integration', '-i', is_flag=True, help='Run only integration tests')
|
|
502
|
+
@click.option('--no-cov', is_flag=True, help='Disable coverage report')
|
|
503
|
+
@click.option('--html', is_flag=True, help='Generate HTML coverage report')
|
|
504
|
+
@click.option('--module', '-m', help='Test specific module (e.g., autocaps, autolower)')
|
|
505
|
+
def test(unit, integration, no_cov, html, module):
|
|
506
|
+
"""Run test suite with various options."""
|
|
507
|
+
# CHECK IF PYTEST IS INSTALLED
|
|
165
508
|
try:
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
509
|
+
import pytest
|
|
510
|
+
import pytest_cov
|
|
511
|
+
except ImportError:
|
|
512
|
+
click.echo(click.style("\n❌ pytest and/or pytest-cov not found. Installing...", fg='yellow', bold=True))
|
|
513
|
+
try:
|
|
514
|
+
subprocess.run(['pip', 'install', 'pytest', 'pytest-cov'], check=True)
|
|
515
|
+
click.echo(click.style("✅ Successfully installed pytest and pytest-cov", fg='green', bold=True))
|
|
516
|
+
except subprocess.CalledProcessError as e:
|
|
517
|
+
click.echo(click.style(f"\n❌ Failed to install dependencies: {str(e)}", fg='red', bold=True))
|
|
518
|
+
sys.exit(1)
|
|
519
|
+
|
|
520
|
+
cmd = ['python', '-m', 'pytest', '-v'] # BASE COMMAND
|
|
521
|
+
|
|
522
|
+
# COVERAGE OPTIONS
|
|
523
|
+
if not no_cov:
|
|
524
|
+
cmd.extend(['--cov=autotools'])
|
|
525
|
+
if html:
|
|
526
|
+
cmd.extend(['--cov-report=html'])
|
|
527
|
+
else:
|
|
528
|
+
cmd.extend(['--cov-report=term-missing'])
|
|
529
|
+
|
|
530
|
+
# TEST SELECTION
|
|
531
|
+
test_path = 'autotools'
|
|
532
|
+
if module:
|
|
533
|
+
if unit and not integration:
|
|
534
|
+
cmd.append(f'autotools/{module}/tests/test_{module}_core.py')
|
|
535
|
+
elif integration and not unit:
|
|
536
|
+
cmd.append(f'autotools/{module}/tests/test_{module}_integration.py')
|
|
537
|
+
else:
|
|
538
|
+
cmd.append(f'autotools/{module}/tests')
|
|
539
|
+
|
|
540
|
+
# SHOW COMMAND BEING RUN
|
|
541
|
+
click.echo(click.style("\nRunning tests with command:", fg='blue', bold=True))
|
|
542
|
+
click.echo(" ".join(cmd))
|
|
543
|
+
click.echo()
|
|
544
|
+
|
|
545
|
+
# RUN TESTS
|
|
546
|
+
try:
|
|
547
|
+
result = subprocess.run(cmd, check=True)
|
|
548
|
+
if result.returncode == 0:
|
|
549
|
+
click.echo(click.style("\n✅ All tests passed!", fg='green', bold=True))
|
|
550
|
+
else:
|
|
551
|
+
click.echo(click.style("\n❌ Some tests failed!", fg='red', bold=True))
|
|
552
|
+
sys.exit(1)
|
|
553
|
+
except subprocess.CalledProcessError as e:
|
|
554
|
+
click.echo(click.style(f"\n❌ Tests failed with return code {e.returncode}", fg='red', bold=True))
|
|
555
|
+
sys.exit(1)
|
|
176
556
|
except Exception as e:
|
|
177
|
-
|
|
178
|
-
|
|
557
|
+
click.echo(click.style(f"\n❌ Error running tests: {str(e)}", fg='red', bold=True))
|
|
558
|
+
sys.exit(1)
|
|
559
|
+
|
|
560
|
+
# UPDATE CHECK AT THE END
|
|
561
|
+
update_msg = check_for_updates()
|
|
562
|
+
if update_msg:
|
|
563
|
+
click.echo(update_msg)
|
|
179
564
|
|
|
180
|
-
#
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
# ...
|
|
565
|
+
# MAIN FUNCTION TO RUN CLI
|
|
566
|
+
if __name__ == '__main__':
|
|
567
|
+
cli()
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.2
|
|
2
|
-
Name: Open-AutoTools
|
|
3
|
-
Version: 0.0.2.post1
|
|
4
|
-
License-File: LICENSE
|
|
5
|
-
Requires-Dist: Brotli==1.1.0
|
|
6
|
-
Requires-Dist: certifi==2024.2.2
|
|
7
|
-
Requires-Dist: charset-normalizer==3.3.2
|
|
8
|
-
Requires-Dist: click==8.1.3
|
|
9
|
-
Requires-Dist: cryptography==42.0.2
|
|
10
|
-
Requires-Dist: idna==3.6
|
|
11
|
-
Requires-Dist: importlib-metadata==7.0.1
|
|
12
|
-
Requires-Dist: joblib==1.3.2
|
|
13
|
-
Requires-Dist: Levenshtein==0.25.0
|
|
14
|
-
Requires-Dist: mutagen==1.47.0
|
|
15
|
-
Requires-Dist: platformdirs==4.2.0
|
|
16
|
-
Requires-Dist: pycryptodomex==3.20.0
|
|
17
|
-
Requires-Dist: pyperclip==1.8.2
|
|
18
|
-
Requires-Dist: python-Levenshtein==0.25.0
|
|
19
|
-
Requires-Dist: rapidfuzz==3.6.1
|
|
20
|
-
Requires-Dist: regex==2023.12.25
|
|
21
|
-
Requires-Dist: requests>=2.32.2
|
|
22
|
-
Requires-Dist: textblob==0.18.0.post0
|
|
23
|
-
Requires-Dist: tomli==2.0.1
|
|
24
|
-
Requires-Dist: tqdm==4.66.2
|
|
25
|
-
Requires-Dist: urllib3==2.2.1
|
|
26
|
-
Requires-Dist: websockets==13.0.1
|
|
27
|
-
Requires-Dist: yapf==0.40.2
|
|
28
|
-
Requires-Dist: yt-dlp>=2024.3.10
|
|
29
|
-
Requires-Dist: zipp==3.17.0
|
|
30
|
-
Requires-Dist: translate==3.6.1
|
|
31
|
-
Requires-Dist: langdetect==1.0.9
|
|
32
|
-
Requires-Dist: deep-translator==1.11.4
|
|
33
|
-
Requires-Dist: netifaces>=0.11.0
|
|
34
|
-
Requires-Dist: speedtest-cli>=2.1.3
|
|
35
|
-
Requires-Dist: psutil>=5.9.0
|
|
36
|
-
Requires-Dist: setuptools>=40.8.0
|
|
37
|
-
Dynamic: requires-dist
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
autotools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
autotools/cli.py,sha256=VWQgHF0WuAD9XGtqaF48EHF5pczrg7VCq-w_wylV9Tc,7167
|
|
3
|
-
autotools/autocaps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
autotools/autocaps/core.py,sha256=NnOacVp0kMoq__KHWi5UMcApSuq6Iyo5bFxN40dRw7U,253
|
|
5
|
-
autotools/autoip/__init__.py,sha256=T_5hz9G4reFPXDucdzRoMFPYlAKwTPt9TejOpkRPgn0,23
|
|
6
|
-
autotools/autoip/core.py,sha256=_Gy8QyDIUaQmfBF6CIP3Ju3_KYbZhs2mst9Vm0sPQUI,6940
|
|
7
|
-
autotools/autolower/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
autotools/autolower/core.py,sha256=vjM2ognA3tDCbv10a9vta9WPuAiqTPjOXZ1JHL_b-nk,260
|
|
9
|
-
autotools/autotranslate/__init__.py,sha256=6BxuZqhyQhfsZ5x7DkB1BAEpC08GT_5l5bl0AY_eLpU,64
|
|
10
|
-
autotools/autotranslate/core.py,sha256=-QdWBIF-eNbuN5qhf45BlOzaOkckwhaF4IMG3OOeRcw,1383
|
|
11
|
-
autotools/downloader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
autotools/downloader/core.py,sha256=xmQSEEi3UYPkbbwsL-H4vGKcpqLCkwhIYlZxDWrIEpI,8266
|
|
13
|
-
autotools/password/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
14
|
-
autotools/password/core.py,sha256=GQrd-QGWpgxuq6Nf28URcTZRku8Gji1NfpbecXAsIF0,3146
|
|
15
|
-
Open_AutoTools-0.0.2.post1.dist-info/LICENSE,sha256=SpbSRxNWos2l0-geleCa6d0L9G_bOsZRkY4rB9OduJ0,1069
|
|
16
|
-
Open_AutoTools-0.0.2.post1.dist-info/METADATA,sha256=U8eB5odvQPlYUs044z2s3EMNS9wSYT4CofxyclBTn-s,1163
|
|
17
|
-
Open_AutoTools-0.0.2.post1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
18
|
-
Open_AutoTools-0.0.2.post1.dist-info/entry_points.txt,sha256=NVN0wuAVjff3e4_MyceS5o22V_l7_0R_wT2adgvWAlY,282
|
|
19
|
-
Open_AutoTools-0.0.2.post1.dist-info/top_level.txt,sha256=x5ZRvdQw7DQnVmR0YDqVSAuuS94KTHDmk6uIeW7YOPw,10
|
|
20
|
-
Open_AutoTools-0.0.2.post1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|