Open-AutoTools 0.0.2.post2__py3-none-any.whl → 0.0.3rc2__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.3rc2.dist-info}/METADATA +27 -2
- Open_AutoTools-0.0.3rc2.dist-info/RECORD +31 -0
- {Open_AutoTools-0.0.2.post2.dist-info → Open_AutoTools-0.0.3rc2.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/{downloader → autodownload}/core.py +11 -6
- 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 +422 -47
- Open_AutoTools-0.0.2.post2.dist-info/RECORD +0 -20
- {Open_AutoTools-0.0.2.post2.dist-info → Open_AutoTools-0.0.3rc2.dist-info}/LICENSE +0 -0
- {Open_AutoTools-0.0.2.post2.dist-info → Open_AutoTools-0.0.3rc2.dist-info}/WHEEL +0 -0
- {Open_AutoTools-0.0.2.post2.dist-info → Open_AutoTools-0.0.3rc2.dist-info}/top_level.txt +0 -0
- /autotools/{downloader → autodownload}/__init__.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,237 @@ 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
|
+
try:
|
|
45
|
+
# GET CURRENT VERSION
|
|
46
|
+
pkg_version = get_version('Open-AutoTools')
|
|
47
|
+
click.echo(f"Open-AutoTools version {pkg_version}")
|
|
48
|
+
|
|
49
|
+
# GET DISTRIBUTION INFO
|
|
50
|
+
import pkg_resources
|
|
51
|
+
dist = pkg_resources.get_distribution("Open-AutoTools")
|
|
52
|
+
current_version = parse_version(dist.version)
|
|
53
|
+
|
|
54
|
+
# GET LATEST VERSION FROM PYPI
|
|
55
|
+
pypi_url = "https://pypi.org/pypi/Open-AutoTools/json"
|
|
56
|
+
response = requests.get(pypi_url)
|
|
57
|
+
|
|
58
|
+
# CHECK IF RESPONSE IS SUCCESSFUL
|
|
59
|
+
if response.status_code == 200:
|
|
60
|
+
data = response.json()
|
|
61
|
+
latest_version = data["info"]["version"]
|
|
62
|
+
releases = data["releases"]
|
|
63
|
+
|
|
64
|
+
# GET RELEASE DATE
|
|
65
|
+
if latest_version in releases and releases[latest_version]:
|
|
66
|
+
try:
|
|
67
|
+
upload_time = releases[latest_version][0]["upload_time"]
|
|
68
|
+
for date_format in [
|
|
69
|
+
"%Y-%m-%dT%H:%M:%S",
|
|
70
|
+
"%Y-%m-%dT%H:%M:%S.%fZ",
|
|
71
|
+
"%Y-%m-%d %H:%M:%S"
|
|
72
|
+
]:
|
|
73
|
+
try:
|
|
74
|
+
published_date = datetime.strptime(upload_time, date_format)
|
|
75
|
+
formatted_date = published_date.strftime("%d %B %Y at %H:%M:%S")
|
|
76
|
+
click.echo(f"Released: {formatted_date}")
|
|
77
|
+
break
|
|
78
|
+
except ValueError:
|
|
79
|
+
continue
|
|
80
|
+
except Exception:
|
|
81
|
+
pass # SKIP DATE IF PARSING FAILS
|
|
82
|
+
|
|
83
|
+
# CHECK FOR UPDATES
|
|
84
|
+
latest_parsed = parse_version(latest_version)
|
|
85
|
+
|
|
86
|
+
# COMPARE VERSIONS AND PRINT UPDATE MESSAGE IF NEEDED
|
|
87
|
+
if latest_parsed > current_version:
|
|
88
|
+
update_cmd = "pip install --upgrade Open-AutoTools"
|
|
89
|
+
click.echo(click.style(f"\nUpdate available: v{latest_version}", fg='red', bold=True))
|
|
90
|
+
click.echo(click.style(f"Run '{update_cmd}' to update", fg='red'))
|
|
91
|
+
|
|
92
|
+
except pkg_resources.DistributionNotFound:
|
|
93
|
+
click.echo("Package distribution not found")
|
|
94
|
+
except PackageNotFoundError:
|
|
95
|
+
click.echo("Open-AutoTools version information not available")
|
|
96
|
+
except Exception as e:
|
|
97
|
+
click.echo(f"Error checking updates: {str(e)}")
|
|
98
|
+
|
|
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
|
+
import pkg_resources
|
|
160
|
+
dist = pkg_resources.get_distribution("Open-AutoTools")
|
|
161
|
+
current_version = parse_version(dist.version)
|
|
162
|
+
|
|
163
|
+
# GET LATEST VERSION FROM PYPI
|
|
164
|
+
pypi_url = "https://pypi.org/pypi/Open-AutoTools/json"
|
|
165
|
+
|
|
166
|
+
# CHECK FOR UPDATES FROM PYPI
|
|
167
|
+
response = requests.get(pypi_url)
|
|
168
|
+
|
|
169
|
+
# CHECK IF RESPONSE IS SUCCESSFUL
|
|
170
|
+
if response.status_code == 200:
|
|
171
|
+
data = response.json()
|
|
172
|
+
latest_version = data["info"]["version"]
|
|
173
|
+
|
|
174
|
+
# PARSE VERSIONS FOR COMPARISON
|
|
175
|
+
latest_parsed = parse_version(latest_version)
|
|
176
|
+
|
|
177
|
+
# PRINT UPDATE MESSAGE IF NEEDED
|
|
178
|
+
if latest_parsed > current_version:
|
|
179
|
+
update_cmd = "pip install --upgrade Open-AutoTools"
|
|
180
|
+
return (
|
|
181
|
+
click.style(f"\nUpdate available: v{latest_version}", fg='red', bold=True) + "\n" +
|
|
182
|
+
click.style(f"Run '{update_cmd}' to update", fg='red')
|
|
183
|
+
)
|
|
184
|
+
except Exception as e:
|
|
185
|
+
# FOR DEBUGGING, LOG ERROR
|
|
186
|
+
print(f"Error checking updates: {str(e)}")
|
|
187
|
+
|
|
188
|
+
return None
|
|
28
189
|
|
|
29
190
|
# AUTOCAPS COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
30
191
|
@cli.command()
|
|
31
|
-
@click.argument('text')
|
|
192
|
+
@click.argument('text', nargs=-1)
|
|
32
193
|
def autocaps(text):
|
|
33
|
-
|
|
194
|
+
"""Convert text to UPPERCASE."""
|
|
195
|
+
result = autocaps_transform(" ".join(text))
|
|
34
196
|
click.echo(result)
|
|
197
|
+
|
|
198
|
+
# UPDATE CHECK AT THE END
|
|
199
|
+
update_msg = check_for_updates()
|
|
200
|
+
if update_msg:
|
|
201
|
+
click.echo(update_msg)
|
|
35
202
|
|
|
36
203
|
# AUTOLOWER CASE COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
37
204
|
@cli.command()
|
|
38
|
-
@click.argument('text')
|
|
205
|
+
@click.argument('text', nargs=-1)
|
|
39
206
|
def autolower(text):
|
|
40
|
-
|
|
207
|
+
"""Convert text to lowercase."""
|
|
208
|
+
result = autolower_transform(" ".join(text))
|
|
41
209
|
click.echo(result)
|
|
210
|
+
|
|
211
|
+
# UPDATE CHECK AT THE END
|
|
212
|
+
update_msg = check_for_updates()
|
|
213
|
+
if update_msg:
|
|
214
|
+
click.echo(update_msg)
|
|
42
215
|
|
|
43
216
|
# AUTODOWNLOAD COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
44
217
|
@cli.command()
|
|
45
218
|
@click.argument('url')
|
|
46
|
-
@click.option('--format', type=click.Choice(['mp4', 'mp3'], case_sensitive=False),
|
|
47
|
-
|
|
219
|
+
@click.option('--format', '-f', type=click.Choice(['mp4', 'mp3'], case_sensitive=False),
|
|
220
|
+
default='mp4', help='Output file format')
|
|
221
|
+
@click.option('--quality', '-q', type=click.Choice(['best', '1440p', '1080p', '720p', '480p', '360p', '240p'],
|
|
222
|
+
case_sensitive=False), default='best', help='Video quality (mp4 only)')
|
|
48
223
|
def autodownload(url, format, quality):
|
|
224
|
+
"""Download videos from YouTube or files from any URL.
|
|
225
|
+
|
|
226
|
+
Supports YouTube video download with quality selection and format conversion (mp4/mp3).
|
|
227
|
+
For non-YouTube URLs, downloads the file directly."""
|
|
49
228
|
if "youtube.com" in url or "youtu.be" in url:
|
|
229
|
+
# VALIDATE YOUTUBE URL FIRST
|
|
230
|
+
if not validate_youtube_url(url):
|
|
231
|
+
click.echo("Invalid YouTube URL", err=True)
|
|
232
|
+
sys.exit(1)
|
|
50
233
|
download_youtube_video(url, format, quality)
|
|
51
234
|
else:
|
|
52
235
|
download_file(url)
|
|
236
|
+
|
|
237
|
+
# UPDATE CHECK AT THE END
|
|
238
|
+
update_msg = check_for_updates()
|
|
239
|
+
if update_msg:
|
|
240
|
+
click.echo(update_msg)
|
|
53
241
|
|
|
54
242
|
# AUTOPASSWORD COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
55
243
|
@cli.command()
|
|
56
244
|
@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')
|
|
245
|
+
@click.option('--no-uppercase', '-u', is_flag=True, help='Exclude uppercase letters')
|
|
246
|
+
@click.option('--no-numbers', '-n', is_flag=True, help='Exclude numbers')
|
|
247
|
+
@click.option('--no-special', '-s', is_flag=True, help='Exclude special characters')
|
|
248
|
+
@click.option('--min-special', '-m', default=1, help='Minimum number of special characters')
|
|
249
|
+
@click.option('--min-numbers', '-d', default=1, help='Minimum number of numbers')
|
|
250
|
+
@click.option('--analyze', '-a', is_flag=True, help='Analyze password strength')
|
|
251
|
+
@click.option('--gen-key', '-g', is_flag=True, help='Generate encryption key')
|
|
252
|
+
@click.option('--password-key', '-p', help='Generate key from password')
|
|
65
253
|
def autopassword(length, no_uppercase, no_numbers, no_special,
|
|
66
254
|
min_special, min_numbers, analyze, gen_key, password_key):
|
|
67
255
|
"""Generate secure passwords and encryption keys."""
|
|
@@ -114,6 +302,11 @@ def autopassword(length, no_uppercase, no_numbers, no_special,
|
|
|
114
302
|
# SHOW PASSWORD
|
|
115
303
|
click.echo(f"Generated Password: {password}")
|
|
116
304
|
show_analysis(password, "Password ")
|
|
305
|
+
|
|
306
|
+
# UPDATE CHECK AT THE END
|
|
307
|
+
update_msg = check_for_updates()
|
|
308
|
+
if update_msg:
|
|
309
|
+
click.echo(update_msg)
|
|
117
310
|
|
|
118
311
|
# TRANSLATE COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
119
312
|
@cli.command()
|
|
@@ -123,10 +316,14 @@ def autopassword(length, no_uppercase, no_numbers, no_special,
|
|
|
123
316
|
@click.option('--list-languages', is_flag=True, help='List all supported languages')
|
|
124
317
|
@click.option('--copy', is_flag=True, help='Copy translation to clipboard')
|
|
125
318
|
@click.option('--detect', is_flag=True, help='Show detected source language')
|
|
319
|
+
@click.option('--output', '-o', type=click.Path(), help='Save translation to file')
|
|
126
320
|
def autotranslate(text: str, to: str, from_lang: str, list_languages: bool,
|
|
127
|
-
copy: bool, detect: bool):
|
|
128
|
-
"""
|
|
321
|
+
copy: bool, detect: bool, output: str):
|
|
322
|
+
"""Translate text to specified language.
|
|
129
323
|
|
|
324
|
+
Supports automatic language detection, multiple target languages,
|
|
325
|
+
clipboard operations and file output. Use --list-languages to see
|
|
326
|
+
all supported language codes."""
|
|
130
327
|
# LIST ALL SUPPORTED LANGUAGES
|
|
131
328
|
if list_languages:
|
|
132
329
|
click.echo("\nSupported Languages:")
|
|
@@ -140,44 +337,222 @@ def autotranslate(text: str, to: str, from_lang: str, list_languages: bool,
|
|
|
140
337
|
return
|
|
141
338
|
|
|
142
339
|
result = translate_text(text, to_lang=to, from_lang=from_lang,
|
|
143
|
-
copy=copy, detect_lang=detect)
|
|
340
|
+
copy=copy, detect_lang=detect, output=output)
|
|
144
341
|
click.echo(result)
|
|
342
|
+
|
|
343
|
+
# UPDATE CHECK AT THE END
|
|
344
|
+
update_msg = check_for_updates()
|
|
345
|
+
if update_msg:
|
|
346
|
+
click.echo(update_msg)
|
|
145
347
|
|
|
146
348
|
# AUTOIP COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
147
349
|
@cli.command()
|
|
148
350
|
@click.option('--test', '-t', is_flag=True, help='Run connectivity tests')
|
|
149
351
|
@click.option('--speed', '-s', is_flag=True, help='Run internet speed test')
|
|
150
352
|
@click.option('--monitor', '-m', is_flag=True, help='Monitor network traffic')
|
|
353
|
+
@click.option('--interval', '-i', default=1, help='Monitoring interval in seconds')
|
|
151
354
|
@click.option('--ports', '-p', is_flag=True, help='Check common ports status')
|
|
152
355
|
@click.option('--dns', '-d', is_flag=True, help='Show DNS servers')
|
|
153
356
|
@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
|
-
|
|
357
|
+
@click.option('--no-ip', '-n', is_flag=True, help='Hide IP addresses')
|
|
358
|
+
def autoip(test, speed, monitor, interval, ports, dns, location, no_ip):
|
|
359
|
+
"""Display network information and diagnostics.
|
|
360
|
+
|
|
361
|
+
Shows local and public IP addresses, runs network diagnostics,
|
|
362
|
+
performs speed tests, monitors traffic with custom intervals,
|
|
363
|
+
checks ports, displays DNS information and provides geolocation data."""
|
|
364
|
+
from autotools.autoip.core import run
|
|
365
|
+
output = run(test=test, speed=speed, monitor=monitor, interval=interval,
|
|
366
|
+
ports=ports, dns=dns, location=location, no_ip=no_ip)
|
|
367
|
+
click.echo(output)
|
|
368
|
+
|
|
369
|
+
# UPDATE CHECK AT THE END
|
|
370
|
+
update_msg = check_for_updates()
|
|
371
|
+
if update_msg:
|
|
372
|
+
click.echo(update_msg)
|
|
159
373
|
|
|
160
|
-
#
|
|
161
|
-
|
|
162
|
-
|
|
374
|
+
# AUTOSPELL COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
375
|
+
@cli.command()
|
|
376
|
+
@click.argument('texts', nargs=-1)
|
|
377
|
+
@click.option('--lang', '-l', default='auto', help='Language code (auto for detection)')
|
|
378
|
+
@click.option('--fix', '-f', is_flag=True, help='Auto-fix text and copy to clipboard')
|
|
379
|
+
@click.option('--copy', '-c', is_flag=True, help='Copy result to clipboard')
|
|
380
|
+
@click.option('--list-languages', is_flag=True, help='List supported languages')
|
|
381
|
+
@click.option('--json', '-j', is_flag=True, help='Output results as JSON')
|
|
382
|
+
@click.option('--ignore', '-i', multiple=True,
|
|
383
|
+
type=click.Choice(['spelling', 'grammar', 'style', 'punctuation']),
|
|
384
|
+
help='Error types to ignore')
|
|
385
|
+
@click.option('--interactive', '-n', is_flag=True,
|
|
386
|
+
help='Interactive mode - confirm each correction')
|
|
387
|
+
@click.option('--output', '-o', type=click.Path(),
|
|
388
|
+
help='Save corrections to file')
|
|
389
|
+
def autospell(texts: tuple, lang: str, fix: bool, copy: bool, list_languages: bool,
|
|
390
|
+
json: bool, ignore: tuple, interactive: bool, output: str):
|
|
391
|
+
"""Check and fix text for spelling, grammar, style, and punctuation errors.
|
|
392
|
+
|
|
393
|
+
Provides comprehensive text analysis with support for multiple languages,
|
|
394
|
+
interactive corrections, and various output formats (text/JSON).
|
|
395
|
+
Can ignore specific error types: spelling, grammar, style, or punctuation."""
|
|
396
|
+
checker = SpellChecker()
|
|
397
|
+
|
|
398
|
+
# LIST ALL SUPPORTED LANGUAGES
|
|
399
|
+
if list_languages:
|
|
400
|
+
languages = checker.get_supported_languages()
|
|
401
|
+
if json:
|
|
402
|
+
result = {'languages': languages}
|
|
403
|
+
click.echo(json_module.dumps(result, indent=2))
|
|
404
|
+
else:
|
|
405
|
+
click.echo("\nSupported Languages:")
|
|
406
|
+
for lang in languages:
|
|
407
|
+
click.echo(f"{lang['code']:<8} {lang['name']}")
|
|
408
|
+
return
|
|
409
|
+
|
|
410
|
+
# CHECK AND FIX SPELLING/GRAMMAR IN TEXT
|
|
411
|
+
for text in texts:
|
|
412
|
+
if not text:
|
|
413
|
+
click.echo("Error: Please provide text to check")
|
|
414
|
+
continue
|
|
415
|
+
|
|
416
|
+
# FIX SPELLING/GRAMMAR IN TEXT
|
|
417
|
+
if fix:
|
|
418
|
+
# CORRECT TEXT WITH SPELL CHECKER
|
|
419
|
+
corrected = checker.fix_text(text, lang, copy_to_clipboard=True,
|
|
420
|
+
ignore=ignore, interactive=interactive)
|
|
421
|
+
result = {'corrected_text': corrected} # RESULT TO RETURN
|
|
422
|
+
|
|
423
|
+
# OUTPUT RESULTS AS JSON
|
|
424
|
+
if json:
|
|
425
|
+
click.echo(json_module.dumps(result, indent=2))
|
|
426
|
+
else:
|
|
427
|
+
# LANGUAGE INFORMATION
|
|
428
|
+
check_result = checker.check_text(text, lang)
|
|
429
|
+
lang_info = check_result['language']
|
|
430
|
+
click.echo(f"\nLanguage detected: {lang_info['name']} ({lang_info['code']})")
|
|
431
|
+
click.echo(f"Confidence: {lang_info['confidence']:.2%}")
|
|
432
|
+
click.echo("\nCorrected text (copied to clipboard):")
|
|
433
|
+
click.echo(corrected)
|
|
434
|
+
|
|
435
|
+
# SAVE CORRECTIONS TO FILE
|
|
436
|
+
if output:
|
|
437
|
+
with open(output, 'w', encoding='utf-8') as f:
|
|
438
|
+
if json:
|
|
439
|
+
json_module.dump(result, f, indent=2)
|
|
440
|
+
else:
|
|
441
|
+
f.write(corrected)
|
|
442
|
+
else:
|
|
443
|
+
# CHECK SPELLING/GRAMMAR IN TEXT
|
|
444
|
+
check_result = checker.check_text(text, lang)
|
|
445
|
+
|
|
446
|
+
# OUTPUT RESULTS AS JSON
|
|
447
|
+
if json:
|
|
448
|
+
click.echo(json_module.dumps(check_result, indent=2))
|
|
449
|
+
else:
|
|
450
|
+
lang_info = check_result['language']
|
|
451
|
+
click.echo(f"\nLanguage detected: {lang_info['name']} ({lang_info['code']})")
|
|
452
|
+
click.echo(f"Confidence: {lang_info['confidence']:.2%}")
|
|
453
|
+
click.echo(f"Total errors found: {check_result['statistics']['total_errors']}")
|
|
454
|
+
|
|
455
|
+
# CORRECTIONS SUGGESTED
|
|
456
|
+
if check_result['corrections']:
|
|
457
|
+
click.echo("\nCorrections suggested:")
|
|
458
|
+
for i, corr in enumerate(check_result['corrections'], 1):
|
|
459
|
+
click.echo(f"\n{i}. [{corr['severity'].upper()}] {corr['message']}")
|
|
460
|
+
click.echo(f" Context: {corr['context']}")
|
|
461
|
+
if corr['replacements']:
|
|
462
|
+
click.echo(f" Suggestions: {', '.join(corr['replacements'][:3])}")
|
|
463
|
+
|
|
464
|
+
# SAVE CHECK RESULT TO FILE
|
|
465
|
+
if output:
|
|
466
|
+
with open(output, 'w', encoding='utf-8') as f:
|
|
467
|
+
if json:
|
|
468
|
+
json_module.dump(check_result, f, indent=2)
|
|
469
|
+
else:
|
|
470
|
+
# WRITE A HUMAN-READABLE REPORT
|
|
471
|
+
f.write(f"Language: {lang_info['name']} ({lang_info['code']})\n")
|
|
472
|
+
f.write(f"Confidence: {lang_info['confidence']:.2%}\n")
|
|
473
|
+
f.write(f"Total errors: {check_result['statistics']['total_errors']}\n\n")
|
|
474
|
+
|
|
475
|
+
# CORRECTIONS SUGGESTED
|
|
476
|
+
if check_result['corrections']:
|
|
477
|
+
f.write("Corrections suggested:\n")
|
|
478
|
+
for i, corr in enumerate(check_result['corrections'], 1):
|
|
479
|
+
f.write(f"\n{i}. [{corr['severity'].upper()}] {corr['message']}\n")
|
|
480
|
+
f.write(f" Context: {corr['context']}\n")
|
|
481
|
+
if corr['replacements']:
|
|
482
|
+
f.write(f" Suggestions: {', '.join(corr['replacements'][:3])}\n")
|
|
163
483
|
|
|
164
|
-
|
|
484
|
+
# UPDATE CHECK AT THE END
|
|
485
|
+
update_msg = check_for_updates()
|
|
486
|
+
if update_msg:
|
|
487
|
+
click.echo(update_msg)
|
|
488
|
+
|
|
489
|
+
# TEST COMMAND LINE INTERFACE FUNCTION DEFINITION
|
|
490
|
+
@cli.command()
|
|
491
|
+
@click.option('--unit', '-u', is_flag=True, help='Run only unit tests')
|
|
492
|
+
@click.option('--integration', '-i', is_flag=True, help='Run only integration tests')
|
|
493
|
+
@click.option('--no-cov', is_flag=True, help='Disable coverage report')
|
|
494
|
+
@click.option('--html', is_flag=True, help='Generate HTML coverage report')
|
|
495
|
+
@click.option('--module', '-m', help='Test specific module (e.g., autocaps, autolower)')
|
|
496
|
+
def test(unit, integration, no_cov, html, module):
|
|
497
|
+
"""Run test suite with various options."""
|
|
498
|
+
# CHECK IF PYTEST IS INSTALLED
|
|
499
|
+
try:
|
|
500
|
+
import pytest
|
|
501
|
+
import pytest_cov
|
|
502
|
+
except ImportError:
|
|
503
|
+
click.echo(click.style("\n❌ pytest and/or pytest-cov not found. Installing...", fg='yellow', bold=True))
|
|
504
|
+
try:
|
|
505
|
+
subprocess.run(['pip', 'install', 'pytest', 'pytest-cov'], check=True)
|
|
506
|
+
click.echo(click.style("✅ Successfully installed pytest and pytest-cov", fg='green', bold=True))
|
|
507
|
+
except subprocess.CalledProcessError as e:
|
|
508
|
+
click.echo(click.style(f"\n❌ Failed to install dependencies: {str(e)}", fg='red', bold=True))
|
|
509
|
+
sys.exit(1)
|
|
510
|
+
|
|
511
|
+
cmd = ['python', '-m', 'pytest', '-v'] # BASE COMMAND
|
|
512
|
+
|
|
513
|
+
# COVERAGE OPTIONS
|
|
514
|
+
if not no_cov:
|
|
515
|
+
cmd.extend(['--cov=autotools'])
|
|
516
|
+
if html:
|
|
517
|
+
cmd.extend(['--cov-report=html'])
|
|
518
|
+
else:
|
|
519
|
+
cmd.extend(['--cov-report=term-missing'])
|
|
520
|
+
|
|
521
|
+
# TEST SELECTION
|
|
522
|
+
test_path = 'autotools'
|
|
523
|
+
if module:
|
|
524
|
+
if unit and not integration:
|
|
525
|
+
cmd.append(f'autotools/{module}/tests/test_{module}_core.py')
|
|
526
|
+
elif integration and not unit:
|
|
527
|
+
cmd.append(f'autotools/{module}/tests/test_{module}_integration.py')
|
|
528
|
+
else:
|
|
529
|
+
cmd.append(f'autotools/{module}/tests')
|
|
530
|
+
|
|
531
|
+
# SHOW COMMAND BEING RUN
|
|
532
|
+
click.echo(click.style("\nRunning tests with command:", fg='blue', bold=True))
|
|
533
|
+
click.echo(" ".join(cmd))
|
|
534
|
+
click.echo()
|
|
535
|
+
|
|
536
|
+
# RUN TESTS
|
|
165
537
|
try:
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
with
|
|
174
|
-
|
|
175
|
-
return True
|
|
538
|
+
result = subprocess.run(cmd, check=True)
|
|
539
|
+
if result.returncode == 0:
|
|
540
|
+
click.echo(click.style("\n✅ All tests passed!", fg='green', bold=True))
|
|
541
|
+
else:
|
|
542
|
+
click.echo(click.style("\n❌ Some tests failed!", fg='red', bold=True))
|
|
543
|
+
sys.exit(1)
|
|
544
|
+
except subprocess.CalledProcessError as e:
|
|
545
|
+
click.echo(click.style(f"\n❌ Tests failed with return code {e.returncode}", fg='red', bold=True))
|
|
546
|
+
sys.exit(1)
|
|
176
547
|
except Exception as e:
|
|
177
|
-
|
|
178
|
-
|
|
548
|
+
click.echo(click.style(f"\n❌ Error running tests: {str(e)}", fg='red', bold=True))
|
|
549
|
+
sys.exit(1)
|
|
550
|
+
|
|
551
|
+
# UPDATE CHECK AT THE END
|
|
552
|
+
update_msg = check_for_updates()
|
|
553
|
+
if update_msg:
|
|
554
|
+
click.echo(update_msg)
|
|
179
555
|
|
|
180
|
-
#
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
# ...
|
|
556
|
+
# MAIN FUNCTION TO RUN CLI
|
|
557
|
+
if __name__ == '__main__':
|
|
558
|
+
cli()
|
|
@@ -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.post2.dist-info/LICENSE,sha256=SpbSRxNWos2l0-geleCa6d0L9G_bOsZRkY4rB9OduJ0,1069
|
|
16
|
-
Open_AutoTools-0.0.2.post2.dist-info/METADATA,sha256=Kdoqcu1zmNVqOn8l0KjjRvENTLAN7pxsTdQELObqnwA,8294
|
|
17
|
-
Open_AutoTools-0.0.2.post2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
18
|
-
Open_AutoTools-0.0.2.post2.dist-info/entry_points.txt,sha256=NVN0wuAVjff3e4_MyceS5o22V_l7_0R_wT2adgvWAlY,282
|
|
19
|
-
Open_AutoTools-0.0.2.post2.dist-info/top_level.txt,sha256=x5ZRvdQw7DQnVmR0YDqVSAuuS94KTHDmk6uIeW7YOPw,10
|
|
20
|
-
Open_AutoTools-0.0.2.post2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|