Open-AutoTools 0.0.3rc4__py3-none-any.whl → 0.0.4__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.
Files changed (46) hide show
  1. autotools/autocaps/commands.py +3 -7
  2. autotools/autocaps/core.py +5 -4
  3. autotools/autoip/commands.py +8 -12
  4. autotools/autoip/core.py +151 -200
  5. autotools/autolower/commands.py +3 -7
  6. autotools/autolower/core.py +4 -3
  7. autotools/autopassword/commands.py +27 -33
  8. autotools/autopassword/core.py +32 -73
  9. autotools/autotest/__init__.py +2 -0
  10. autotools/autotest/commands.py +206 -0
  11. autotools/cli.py +123 -62
  12. autotools/utils/commands.py +13 -0
  13. autotools/utils/loading.py +14 -6
  14. autotools/utils/performance.py +424 -0
  15. autotools/utils/requirements.py +21 -0
  16. autotools/utils/text.py +16 -0
  17. autotools/utils/updates.py +30 -22
  18. autotools/utils/version.py +69 -63
  19. open_autotools-0.0.4.dist-info/METADATA +84 -0
  20. open_autotools-0.0.4.dist-info/RECORD +30 -0
  21. {Open_AutoTools-0.0.3rc4.dist-info → open_autotools-0.0.4.dist-info}/WHEEL +1 -1
  22. {Open_AutoTools-0.0.3rc4.dist-info → open_autotools-0.0.4.dist-info}/entry_points.txt +0 -3
  23. Open_AutoTools-0.0.3rc4.dist-info/METADATA +0 -308
  24. Open_AutoTools-0.0.3rc4.dist-info/RECORD +0 -44
  25. autotools/autocaps/tests/__init__.py +0 -1
  26. autotools/autocaps/tests/test_autocaps_core.py +0 -45
  27. autotools/autocaps/tests/test_autocaps_integration.py +0 -46
  28. autotools/autodownload/__init__.py +0 -0
  29. autotools/autodownload/commands.py +0 -38
  30. autotools/autodownload/core.py +0 -373
  31. autotools/autoip/tests/__init__.py +0 -1
  32. autotools/autoip/tests/test_autoip_core.py +0 -72
  33. autotools/autoip/tests/test_autoip_integration.py +0 -92
  34. autotools/autolower/tests/__init__.py +0 -1
  35. autotools/autolower/tests/test_autolower_core.py +0 -45
  36. autotools/autolower/tests/test_autolower_integration.py +0 -46
  37. autotools/autospell/__init__.py +0 -3
  38. autotools/autospell/commands.py +0 -123
  39. autotools/autospell/core.py +0 -222
  40. autotools/autotranslate/__init__.py +0 -3
  41. autotools/autotranslate/commands.py +0 -42
  42. autotools/autotranslate/core.py +0 -52
  43. autotools/test/__init__.py +0 -3
  44. autotools/test/commands.py +0 -120
  45. {Open_AutoTools-0.0.3rc4.dist-info → open_autotools-0.0.4.dist-info/licenses}/LICENSE +0 -0
  46. {Open_AutoTools-0.0.3rc4.dist-info → open_autotools-0.0.4.dist-info}/top_level.txt +0 -0
@@ -1,123 +0,0 @@
1
- import click
2
- import json as json_module
3
- from .core import SpellChecker
4
- from ..utils.loading import LoadingAnimation
5
- from ..utils.updates import check_for_updates
6
-
7
- @click.command()
8
- @click.argument('texts', nargs=-1)
9
- @click.option('--lang', '-l', default='auto', help='Language code (auto for detection)')
10
- @click.option('--fix', '-f', is_flag=True, help='Auto-fix text and copy to clipboard')
11
- @click.option('--copy', '-c', is_flag=True, help='Copy result to clipboard')
12
- @click.option('--list-languages', is_flag=True, help='List supported languages')
13
- @click.option('--json', '-j', is_flag=True, help='Output results as JSON')
14
- @click.option('--ignore', '-i', multiple=True,
15
- type=click.Choice(['spelling', 'grammar', 'style', 'punctuation']),
16
- help='Error types to ignore')
17
- @click.option('--interactive', '-n', is_flag=True,
18
- help='Interactive mode - confirm each correction')
19
- @click.option('--output', '-o', type=click.Path(),
20
- help='Save corrections to file')
21
- def autospell(texts: tuple, lang: str, fix: bool, copy: bool, list_languages: bool,
22
- json: bool, ignore: tuple, interactive: bool, output: str):
23
- """Check and fix text for spelling, grammar, style, and punctuation errors.
24
-
25
- Provides comprehensive text analysis with support for multiple languages,
26
- interactive corrections, and various output formats (text/JSON).
27
- Can ignore specific error types: spelling, grammar, style, or punctuation."""
28
- checker = SpellChecker()
29
-
30
- # LIST ALL SUPPORTED LANGUAGES
31
- if list_languages:
32
- with LoadingAnimation():
33
- languages = checker.get_supported_languages()
34
- if json:
35
- result = {'languages': languages}
36
- click.echo(json_module.dumps(result, indent=2))
37
- else:
38
- click.echo("\nSupported Languages:")
39
- for lang in languages:
40
- click.echo(f"{lang['code']:<8} {lang['name']}")
41
- return
42
-
43
- # --CHECK AND FIX SPELLING/GRAMMAR IN TEXT
44
- for text in texts:
45
- if not text:
46
- click.echo("Error: Please provide text to check")
47
- continue
48
-
49
- # --FIX OPTION: SPELLING/GRAMMAR IN TEXT
50
- if fix:
51
- # CORRECT TEXT WITH SPELL CHECKER
52
- with LoadingAnimation():
53
- corrected = checker.fix_text(text, lang, copy_to_clipboard=True,
54
- ignore=ignore, interactive=interactive)
55
- result = {'corrected_text': corrected}
56
-
57
- # OUTPUT RESULTS AS JSON
58
- if json:
59
- click.echo(json_module.dumps(result, indent=2))
60
- else:
61
- # LANGUAGE INFORMATION
62
- with LoadingAnimation():
63
- check_result = checker.check_text(text, lang)
64
- lang_info = check_result['language']
65
- click.echo(f"\nLanguage detected: {lang_info['name']} ({lang_info['code']})")
66
- click.echo(f"Confidence: {lang_info['confidence']:.2%}")
67
- click.echo("\nCorrected text (copied to clipboard):")
68
- click.echo(corrected)
69
-
70
- # SAVE CORRECTIONS TO FILE
71
- if output:
72
- with open(output, 'w', encoding='utf-8') as f:
73
- if json:
74
- json_module.dump(result, f, indent=2)
75
- else:
76
- f.write(corrected)
77
- else:
78
- # CHECK SPELLING/GRAMMAR IN TEXT
79
- with LoadingAnimation():
80
- check_result = checker.check_text(text, lang)
81
-
82
- # OUTPUT RESULTS AS JSON
83
- if json:
84
- click.echo(json_module.dumps(check_result, indent=2))
85
- else:
86
- lang_info = check_result['language']
87
- click.echo(f"\nLanguage detected: {lang_info['name']} ({lang_info['code']})")
88
- click.echo(f"Confidence: {lang_info['confidence']:.2%}")
89
- click.echo(f"Total errors found: {check_result['statistics']['total_errors']}")
90
-
91
- # CORRECTIONS SUGGESTED
92
- if check_result['corrections']:
93
- click.echo("\nCorrections suggested:")
94
- for i, corr in enumerate(check_result['corrections'], 1):
95
- click.echo(f"\n{i}. [{corr['severity'].upper()}] {corr['message']}")
96
- click.echo(f" Context: {corr['context']}")
97
- if corr['replacements']:
98
- click.echo(f" Suggestions: {', '.join(corr['replacements'][:3])}")
99
-
100
- # SAVE CHECK RESULT TO FILE
101
- if output:
102
- with open(output, 'w', encoding='utf-8') as f:
103
- if json:
104
- json_module.dump(check_result, f, indent=2)
105
- else:
106
- # WRITE A HUMAN-READABLE REPORT
107
- f.write(f"Language: {lang_info['name']} ({lang_info['code']})\n")
108
- f.write(f"Confidence: {lang_info['confidence']:.2%}\n")
109
- f.write(f"Total errors: {check_result['statistics']['total_errors']}\n\n")
110
-
111
- # CORRECTIONS SUGGESTED
112
- if check_result['corrections']:
113
- f.write("Corrections suggested:\n")
114
- for i, corr in enumerate(check_result['corrections'], 1):
115
- f.write(f"\n{i}. [{corr['severity'].upper()}] {corr['message']}\n")
116
- f.write(f" Context: {corr['context']}\n")
117
- if corr['replacements']:
118
- f.write(f" Suggestions: {', '.join(corr['replacements'][:3])}\n")
119
-
120
- # UPDATE CHECK AT THE END
121
- update_msg = check_for_updates()
122
- if update_msg:
123
- click.echo(update_msg)
@@ -1,222 +0,0 @@
1
- import language_tool_python
2
- import spacy
3
- from typing import List, Dict, Optional
4
- import pyperclip
5
- import requests
6
- from langdetect import detect, detect_langs
7
-
8
- class SpellChecker:
9
- def __init__(self):
10
- # INITIALIZE LANGUAGE TOOL
11
- self.tool = language_tool_python.LanguageTool('auto')
12
-
13
- # CACHE FOR SPACY MODELS
14
- self.nlp_models = {}
15
-
16
- # LOAD SPACY MODEL FOR GIVEN LANGUAGE
17
- def _load_spacy_model(self, lang_code: str) -> Optional[spacy.language.Language]:
18
- """LOAD SPACY MODEL FOR GIVEN LANGUAGE"""
19
- try:
20
- if lang_code not in self.nlp_models:
21
- # GET ALL INSTALLED MODELS FOR THIS LANGUAGE
22
- available_models = [
23
- model for model in spacy.util.get_installed_models()
24
- if model.startswith(lang_code)
25
- ]
26
-
27
- if not available_models:
28
- # TRY TO CREATE A BLANK MODEL IF NO TRAINED MODELS
29
- self.nlp_models[lang_code] = spacy.blank(lang_code)
30
- else:
31
- # USE MOST COMPREHENSIVE MODEL (USUALLY ENDS WITH 'lg' OR 'trf')
32
- preferred_model = None
33
- for suffix in ['trf', 'lg', 'md', 'sm']:
34
- for model in available_models:
35
- if model.endswith(suffix):
36
- preferred_model = model
37
- break
38
- if preferred_model:
39
- break
40
-
41
- # IF NO PREFERRED MODEL, USE FIRST AVAILABLE MODEL
42
- if not preferred_model:
43
- preferred_model = available_models[0]
44
-
45
- self.nlp_models[lang_code] = spacy.load(preferred_model) # LOAD PREFERRED MODEL
46
-
47
- return self.nlp_models.get(lang_code) # RETURN LOADED MODEL
48
- except:
49
- return None
50
-
51
- # CHECK TEXT FOR SPELLING AND GRAMMAR ERRORS
52
- def check_text(self, text: str, lang: str = 'auto') -> Dict:
53
- """CHECK TEXT FOR SPELLING AND GRAMMAR ERRORS
54
-
55
- ARGS:
56
- text: Text to check
57
- lang: Language code (auto for automatic detection)
58
-
59
- RETURNS:
60
- Dict with corrections and statistics
61
- """
62
- # DETECT LANGUAGE CONFIDENCE
63
- if lang == 'auto':
64
- try:
65
- lang_scores = detect_langs(text)
66
- lang = lang_scores[0].lang
67
- confidence = lang_scores[0].prob
68
- except:
69
- confidence = 0
70
- else:
71
- confidence = 1.0
72
-
73
- # SET LANGUAGE
74
- if lang != 'auto':
75
- self.tool.language = lang
76
-
77
- # GET MATCHES
78
- matches = self.tool.check(text)
79
-
80
- # PREPARE CORRECTIONS WITH SEVERITY LEVELS
81
- corrections = []
82
- for match in matches:
83
- severity = self._get_error_severity(match)
84
- correction = {
85
- 'message': match.message,
86
- 'context': match.context,
87
- 'offset': match.offset,
88
- 'length': match.errorLength,
89
- 'category': match.category,
90
- 'rule_id': match.ruleId,
91
- 'replacements': match.replacements,
92
- 'severity': severity
93
- }
94
- corrections.append(correction)
95
-
96
- # GET DETAILED STATISTICS
97
- stats = self._get_detailed_stats(corrections)
98
-
99
- return {
100
- 'corrections': corrections,
101
- 'statistics': stats,
102
- 'language': {
103
- 'code': lang,
104
- 'name': lang.upper(),
105
- 'confidence': confidence
106
- }
107
- }
108
-
109
- # DETERMINE ERROR SEVERITY LEVEL
110
- def _get_error_severity(self, match) -> str:
111
- """DETERMINE ERROR SEVERITY LEVEL"""
112
- if 'TYPO' in match.ruleId or 'SPELLING' in match.ruleId:
113
- return 'high'
114
- elif 'GRAMMAR' in match.ruleId:
115
- return 'medium'
116
- else:
117
- return 'low'
118
-
119
- # GET DETAILED ERROR STATISTICS
120
- def _get_detailed_stats(self, corrections: List[Dict]) -> Dict:
121
- """GET DETAILED ERROR STATISTICS"""
122
- stats = {
123
- 'total_errors': len(corrections),
124
- 'categories': {},
125
- 'severity': {
126
- 'high': 0,
127
- 'medium': 0,
128
- 'low': 0
129
- }
130
- }
131
-
132
- # COUNT ERRORS BY CATEGORY AND SEVERITY
133
- for corr in corrections:
134
- # COUNT BY CATEGORY
135
- cat = corr['category']
136
- stats['categories'][cat] = stats['categories'].get(cat, 0) + 1
137
-
138
- # COUNT BY SEVERITY
139
- stats['severity'][corr['severity']] += 1
140
-
141
- return stats
142
-
143
- # FIX TEXT AUTOMATICALLY
144
- def fix_text(self, text: str, lang: str = 'auto', copy_to_clipboard: bool = False,
145
- ignore: list = None, interactive: bool = False) -> str:
146
- """FIX TEXT AUTOMATICALLY"""
147
- if lang != 'auto':
148
- self.tool.language = lang
149
-
150
- if interactive:
151
- # GET ALL CORRECTIONS
152
- matches = self.tool.check(text)
153
- corrected = text
154
-
155
- # ASK FOR EACH CORRECTION
156
- for match in matches:
157
- if ignore and any(t in match.ruleId.lower() for t in ignore):
158
- continue
159
-
160
- print(f"\nError: {match.message}")
161
- print(f"Context: {match.context}")
162
- if match.replacements:
163
- print("Suggestions:")
164
- for i, sugg in enumerate(match.replacements[:3], 1):
165
- print(f"{i}. {sugg}")
166
-
167
- # ASK FOR EACH CORRECTION
168
- choice = input("\nApply correction? (1-3/n): ").lower()
169
- if choice.isdigit() and 1 <= int(choice) <= len(match.replacements[:3]):
170
- replacement = match.replacements[int(choice)-1]
171
- corrected = corrected[:match.offset] + replacement + corrected[match.offset + match.errorLength:]
172
- else:
173
- # NORMAL AUTO-FIX
174
- corrected = self.tool.correct(text)
175
-
176
- # COPY TO CLIPBOARD IF REQUESTED
177
- if copy_to_clipboard:
178
- pyperclip.copy(corrected)
179
-
180
- return corrected
181
-
182
- # GET LIST OF SUPPORTED LANGUAGES
183
- def get_supported_languages(self) -> List[Dict]:
184
- """GET LIST OF SUPPORTED LANGUAGES"""
185
- try:
186
- # GET LANGUAGES FROM LANGUAGE TOOL PUBLIC API
187
- response = requests.get('https://api.languagetool.org/v2/languages')
188
- languages = response.json()
189
-
190
- # FORMAT LANGUAGES INTO REQUIRED STRUCTURE
191
- formatted_langs = []
192
- seen_codes = set()
193
-
194
- # FORMAT LANGUAGES INTO REQUIRED STRUCTURE
195
- for lang in languages:
196
- code = lang['longCode'].split('-')[0]
197
-
198
- # SKIP DUPLICATES
199
- if code in seen_codes:
200
- continue
201
-
202
- # TEST IF LANGUAGE IS ACTUALLY SUPPORTED BY LOCAL TOOL
203
- try:
204
- self.tool.language = code
205
- formatted_langs.append({
206
- 'code': code,
207
- 'name': lang['name'],
208
- 'variants': [v['name'] for v in lang.get('variants', [])]
209
- })
210
- seen_codes.add(code)
211
- except:
212
- continue
213
-
214
- return formatted_langs
215
-
216
- except Exception as e:
217
- # IF API FAILS, GET LANGUAGES FROM LOCAL TOOL
218
- try:
219
- current_lang = self.tool.language
220
- return [{'code': current_lang, 'name': current_lang.upper(), 'variants': []}]
221
- except:
222
- return []
@@ -1,3 +0,0 @@
1
- from .core import translate_text
2
-
3
- __all__ = ['translate_text']
@@ -1,42 +0,0 @@
1
- import click
2
- from .core import translate_text, get_supported_languages
3
- from ..utils.loading import LoadingAnimation
4
- from ..utils.updates import check_for_updates
5
-
6
- @click.command()
7
- @click.argument('text', required=False)
8
- @click.option('--to', default='en', help='Target language (default: en)')
9
- @click.option('--from', 'from_lang', help='Source language (default: auto-detect)')
10
- @click.option('--list-languages', is_flag=True, help='List all supported languages')
11
- @click.option('--copy', is_flag=True, help='Copy translation to clipboard')
12
- @click.option('--detect', is_flag=True, help='Show detected source language')
13
- @click.option('--output', '-o', type=click.Path(), help='Save translation to file')
14
- def autotranslate(text: str, to: str, from_lang: str, list_languages: bool,
15
- copy: bool, detect: bool, output: str):
16
- """Translate text to specified language.
17
-
18
- Supports automatic language detection, multiple target languages,
19
- clipboard operations and file output. Use --list-languages to see
20
- all supported language codes."""
21
- # LIST ALL SUPPORTED LANGUAGES
22
- if list_languages:
23
- with LoadingAnimation():
24
- click.echo("\nSupported Languages:")
25
- for code, name in get_supported_languages().items():
26
- click.echo(f"{code:<8} {name}")
27
- return
28
-
29
- # CHECK IF TEXT IS PROVIDED
30
- if not text:
31
- click.echo("Error: Please provide text to translate")
32
- return
33
-
34
- with LoadingAnimation():
35
- result = translate_text(text, to_lang=to, from_lang=from_lang,
36
- copy=copy, detect_lang=detect, output=output)
37
- click.echo(result)
38
-
39
- # UPDATE CHECK AT THE END
40
- update_msg = check_for_updates()
41
- if update_msg:
42
- click.echo(update_msg)
@@ -1,52 +0,0 @@
1
- from deep_translator import GoogleTranslator
2
- from langdetect import detect
3
- import pyperclip
4
-
5
- def get_supported_languages() -> dict:
6
- """GET ALL SUPPORTED LANGUAGES FROM GOOGLE TRANSLATE"""
7
- # GET LANGUAGES CODES
8
- langs = GoogleTranslator().get_supported_languages(as_dict=True)
9
- # SORT BY LANGUAGE NAME
10
- return dict(sorted(langs.items(), key=lambda x: x[1].lower()))
11
-
12
- def translate_text(text: str, to_lang: str = 'en', from_lang: str = None,
13
- copy: bool = False, detect_lang: bool = False, output: str = None) -> str:
14
- """TRANSLATE TEXT TO SPECIFIED LANGUAGE
15
-
16
- ARGS:
17
- text (str): TEXT TO TRANSLATE
18
- to_lang (str): TARGET LANGUAGE CODE (DEFAULT: EN)
19
- from_lang (str): SOURCE LANGUAGE CODE (DEFAULT: AUTO-DETECT)
20
- copy (bool): COPY RESULT TO CLIPBOARD
21
- detect_lang (bool): SHOW DETECTED SOURCE LANGUAGE
22
- output (str): PATH TO SAVE TRANSLATION TO FILE
23
-
24
- RETURNS:
25
- str: TRANSLATED TEXT
26
- """
27
- # AUTO-DETECT SOURCE LANGUAGE IF NOT SPECIFIED
28
- source_lang = from_lang or detect(text)
29
-
30
- # TRANSLATE
31
- translator = GoogleTranslator(source=source_lang, target=to_lang)
32
- result = translator.translate(text)
33
-
34
- # COPY TO CLIPBOARD IF REQUESTED
35
- if copy:
36
- pyperclip.copy(result)
37
-
38
- # SAVE TO FILE IF OUTPUT PATH PROVIDED
39
- if output:
40
- try:
41
- with open(output, 'w', encoding='utf-8') as f:
42
- if detect_lang:
43
- f.write(f"[Detected: {source_lang}] {result}")
44
- else:
45
- f.write(result)
46
- except Exception as e:
47
- print(f"\nError saving to file: {str(e)}")
48
-
49
- # RETURN RESULT WITH DETECTED LANGUAGE IF REQUESTED
50
- if detect_lang:
51
- return f"[Detected: {source_lang}] {result}"
52
- return result
@@ -1,3 +0,0 @@
1
- from .commands import test
2
-
3
- __all__ = ['test']
@@ -1,120 +0,0 @@
1
- import click
2
- import subprocess
3
- import sys
4
- import os
5
- import re
6
- from ..utils.updates import check_for_updates
7
-
8
- @click.command()
9
- @click.option('--unit', '-u', is_flag=True, help='Run only unit tests')
10
- @click.option('--integration', '-i', is_flag=True, help='Run only integration tests')
11
- @click.option('--no-cov', is_flag=True, help='Disable coverage report')
12
- @click.option('--html', is_flag=True, help='Generate HTML coverage report')
13
- @click.option('--module', '-m', help='Test specific module (e.g., autocaps, autolower)')
14
- def test(unit, integration, no_cov, html, module):
15
- """Run test suite with various options."""
16
- # CHECK IF PYTEST IS INSTALLED
17
- try:
18
- import pytest
19
- import pytest_cov
20
- except ImportError:
21
- click.echo(click.style("\n❌ pytest and/or pytest-cov not found. Installing...", fg='yellow', bold=True))
22
- try:
23
- subprocess.run(['pip', 'install', 'pytest', 'pytest-cov'], check=True)
24
- click.echo(click.style("✅ Successfully installed pytest and pytest-cov", fg='green', bold=True))
25
- except subprocess.CalledProcessError as e:
26
- click.echo(click.style(f"\n❌ Failed to install dependencies: {str(e)}", fg='red', bold=True))
27
- sys.exit(1)
28
-
29
- # BASE COMMAND WITH ENHANCED VERBOSITY
30
- cmd = [
31
- 'python', '-m', 'pytest', # PYTHON MODULE AND TEST COMMAND
32
- '--capture=no', # SHOW PRINT STATEMENTS AND CAPTURED OUTPUT
33
- '--full-trace', # SHOW FULL TRACEBACK
34
- '-vv', # VERY VERBOSE OUTPUT
35
- '--durations=0', # SHOW ALL TEST DURATIONS
36
- '--showlocals', # SHOW LOCAL VARIABLES IN TRACEBACKS
37
- '--log-cli-level=DEBUG', # SHOW DEBUG LOGS
38
- '--tb=long', # LONG TRACEBACK STYLE
39
- '-s' # SHORTCUT FOR --capture=no
40
- ]
41
-
42
- # COVERAGE OPTIONS
43
- if not no_cov:
44
- cmd.extend(['--cov=autotools'])
45
- if html:
46
- cmd.extend(['--cov-report=html'])
47
- else:
48
- cmd.extend(['--cov-report=term-missing'])
49
-
50
- # TEST SELECTION
51
- test_path = 'autotools'
52
- if module:
53
- if unit and not integration:
54
- cmd.append(f'autotools/{module}/tests/test_{module}_core.py')
55
- elif integration and not unit:
56
- cmd.append(f'autotools/{module}/tests/test_{module}_integration.py')
57
- else:
58
- cmd.append(f'autotools/{module}/tests')
59
-
60
- # SHOW COMMAND BEING RUN
61
- click.echo(click.style("\nRunning tests with command:", fg='blue', bold=True))
62
- click.echo(" ".join(cmd))
63
- click.echo()
64
-
65
- # RUN TESTS
66
- try:
67
- env = dict(os.environ)
68
- env['PYTHONPATH'] = os.getcwd()
69
- env['FORCE_COLOR'] = '1' # FORCE COLORS IN OUTPUT
70
-
71
- process = subprocess.Popen(
72
- cmd,
73
- env=env,
74
- stdout=subprocess.PIPE,
75
- stderr=subprocess.STDOUT,
76
- universal_newlines=True,
77
- bufsize=1
78
- )
79
-
80
- # READ AND PROCESS OUTPUT IN REAL-TIME
81
- while True:
82
- line = process.stdout.readline()
83
- if not line and process.poll() is not None:
84
- break
85
- if line:
86
- # CLEAN THE LINE
87
- line = line.strip()
88
- if line: # ONLY PROCESS NON-EMPTY LINES
89
- if '::' in line and 'autotools/' in line:
90
- # REMOVE PARENT DIRECTORY PATHS
91
- line = line.split('autotools/')[-1].replace('/tests/', '/')
92
- # REMOVE MODULE PARENT DIRECTORY
93
- parts = line.split('/')
94
- if len(parts) > 1:
95
- line = parts[-1]
96
- # REMOVE MULTIPLE SPACES AND DOTS
97
- line = re.sub(r'\s+', ' ', line)
98
- line = re.sub(r'\.+', '.', line)
99
- # REMOVE EMPTY LINES WITH JUST DOTS OR SPACES
100
- if line.strip('. '):
101
- sys.stdout.write(line + '\n')
102
- sys.stdout.flush()
103
-
104
- process.wait()
105
- if process.returncode == 0:
106
- click.echo(click.style("\n✅ All tests passed!", fg='green', bold=True))
107
- else:
108
- click.echo(click.style("\n❌ Some tests failed!", fg='red', bold=True))
109
- sys.exit(1)
110
- except subprocess.CalledProcessError as e:
111
- click.echo(click.style(f"\n❌ Tests failed with return code {e.returncode}", fg='red', bold=True))
112
- sys.exit(1)
113
- except Exception as e:
114
- click.echo(click.style(f"\n❌ Error running tests: {str(e)}", fg='red', bold=True))
115
- sys.exit(1)
116
-
117
- # UPDATE CHECK AT THE END
118
- update_msg = check_for_updates()
119
- if update_msg:
120
- click.echo(update_msg)