Skip to content

Commit ec34eef

Browse files
committed
fix: resolve linting and formatting issues
- Fix flake8 E231 error: add missing whitespace after comma in ml_engine.py:138 - Fix flake8 E128 error: correct continuation line indentation in ml_engine.py:191 - Apply Black formatting to 11 files to ensure consistent code style - All files now pass both flake8 and black checks Files modified: - shellrosetta/config.py - shellrosetta/parser.py - shellrosetta/api.py - shellrosetta/core.py - shellrosetta/utils.py - shellrosetta/cli.py - shellrosetta/plugins.py - shellrosetta/mappings.py - shellrosetta/ml_engine.py - tests/test_core.py - tests/test_advanced_features.py
1 parent df31049 commit ec34eef

File tree

11 files changed

+335
-194
lines changed

11 files changed

+335
-194
lines changed

shellrosetta/api.py

Lines changed: 58 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
try:
44
from flask import Flask, request, jsonify, render_template_string
55
from flask_cors import CORS
6+
67
FLASK_AVAILABLE = True
78
except ImportError:
89
FLASK_AVAILABLE = False
@@ -254,53 +255,57 @@
254255
"""
255256

256257

257-
def run_api_server(host='0.0.0.0', port=5000, debug=False):
258+
def run_api_server(host="0.0.0.0", port=5000, debug=False):
258259
"""Run the API server"""
259260
if not FLASK_AVAILABLE:
260-
print("Error: Flask is not installed. Install it with: pip install flask flask-cors")
261+
print(
262+
"Error: Flask is not installed. Install it with: pip install flask flask-cors"
263+
)
261264
return
262265

263266
app = Flask(__name__)
264267
CORS(app) # Enable CORS for all routes
265268

266-
@app.route('/')
269+
@app.route("/")
267270
def index():
268271
"""Serve the web interface"""
269272
return render_template_string(HTML_TEMPLATE)
270273

271-
@app.route('/api/translate', methods=['POST'])
274+
@app.route("/api/translate", methods=["POST"])
272275
def translate_command():
273276
"""Translate a command via API"""
274277
try:
275278
data = request.get_json()
276-
command = data.get('command', '').strip()
277-
direction = data.get('direction', 'lnx2ps')
279+
command = data.get("command", "").strip()
280+
direction = data.get("direction", "lnx2ps")
278281

279282
if not command:
280-
return jsonify({'error': 'No command provided'}), 400
283+
return jsonify({"error": "No command provided"}), 400
281284

282285
# Try plugin translation first
283-
plugin_translation = plugin_manager.translate_with_plugins(command, direction)
286+
plugin_translation = plugin_manager.translate_with_plugins(
287+
command, direction
288+
)
284289

285290
# Try ML translation
286291
ml_translation = ml_engine.get_best_translation(command, direction)
287292

288293
# Use core translation
289-
if direction == 'lnx2ps':
294+
if direction == "lnx2ps":
290295
translation = lnx2ps(command)
291296
else:
292297
translation = ps2lnx(command)
293298

294299
# Prefer plugin translation, then ML, then core
295300
if plugin_translation:
296301
final_translation = plugin_translation
297-
source = 'plugin'
302+
source = "plugin"
298303
elif ml_translation:
299304
final_translation = ml_translation
300-
source = 'ml'
305+
source = "ml"
301306
else:
302307
final_translation = translation
303-
source = 'core'
308+
source = "core"
304309

305310
# Learn the pattern
306311
ml_engine.learn_pattern(command, final_translation, direction, success=True)
@@ -309,93 +314,98 @@ def translate_command():
309314
suggestions = ml_engine.get_suggestions(command, direction, limit=3)
310315
suggestion_texts = [s[0] for s in suggestions]
311316

312-
return jsonify({
313-
'translation': final_translation,
314-
'source': source,
315-
'suggestions': suggestion_texts,
316-
'command': command,
317-
'direction': direction
318-
})
317+
return jsonify(
318+
{
319+
"translation": final_translation,
320+
"source": source,
321+
"suggestions": suggestion_texts,
322+
"command": command,
323+
"direction": direction,
324+
}
325+
)
319326

320327
except Exception as e:
321-
return jsonify({'error': str(e)}), 500
328+
return jsonify({"error": str(e)}), 500
322329

323-
@app.route('/api/stats')
330+
@app.route("/api/stats")
324331
def get_stats():
325332
"""Get translation statistics"""
326333
try:
327334
analysis = ml_engine.analyze_patterns()
328335

329-
return jsonify({
330-
'total_translations': analysis.get('total_patterns', 0),
331-
'success_rate': analysis.get('success_rate', 0),
332-
'learned_patterns': analysis.get('total_patterns', 0),
333-
'command_types': analysis.get('command_types', {}),
334-
'top_patterns': analysis.get('top_successful_patterns', [])
335-
})
336+
return jsonify(
337+
{
338+
"total_translations": analysis.get("total_patterns", 0),
339+
"success_rate": analysis.get("success_rate", 0),
340+
"learned_patterns": analysis.get("total_patterns", 0),
341+
"command_types": analysis.get("command_types", {}),
342+
"top_patterns": analysis.get("top_successful_patterns", []),
343+
}
344+
)
336345

337346
except Exception as e:
338-
return jsonify({'error': str(e)}), 500
347+
return jsonify({"error": str(e)}), 500
339348

340-
@app.route('/api/plugins')
349+
@app.route("/api/plugins")
341350
def list_plugins():
342351
"""List available plugins"""
343352
try:
344353
plugins = plugin_manager.list_plugins()
345-
return jsonify({'plugins': plugins})
354+
return jsonify({"plugins": plugins})
346355

347356
except Exception as e:
348-
return jsonify({'error': str(e)}), 500
357+
return jsonify({"error": str(e)}), 500
349358

350-
@app.route('/api/plugins/<plugin_name>')
359+
@app.route("/api/plugins/<plugin_name>")
351360
def get_plugin_info(plugin_name):
352361
"""Get information about a specific plugin"""
353362
try:
354363
if plugin_name in plugin_manager.plugins:
355364
plugin = plugin_manager.plugins[plugin_name]
356365
return jsonify(plugin.get_metadata())
357366
else:
358-
return jsonify({'error': 'Plugin not found'}), 404
367+
return jsonify({"error": "Plugin not found"}), 404
359368

360369
except Exception as e:
361-
return jsonify({'error': str(e)}), 500
370+
return jsonify({"error": str(e)}), 500
362371

363-
@app.route('/api/learn', methods=['POST'])
372+
@app.route("/api/learn", methods=["POST"])
364373
def learn_pattern():
365374
"""Manually learn a pattern"""
366375
try:
367376
data = request.get_json()
368-
command = data.get('command')
369-
translation = data.get('translation')
370-
direction = data.get('direction')
371-
success = data.get('success', True)
377+
command = data.get("command")
378+
translation = data.get("translation")
379+
direction = data.get("direction")
380+
success = data.get("success", True)
372381

373382
if not all([command, translation, direction]):
374-
return jsonify({'error': 'Missing required fields'}), 400
383+
return jsonify({"error": "Missing required fields"}), 400
375384

376385
ml_engine.learn_pattern(command, translation, direction, success)
377-
return jsonify({'message': 'Pattern learned successfully'})
386+
return jsonify({"message": "Pattern learned successfully"})
378387

379388
except Exception as e:
380-
return jsonify({'error': str(e)}), 500
389+
return jsonify({"error": str(e)}), 500
381390

382-
@app.route('/api/cleanup', methods=['POST'])
391+
@app.route("/api/cleanup", methods=["POST"])
383392
def cleanup_patterns():
384393
"""Clean up old patterns"""
385394
try:
386395
data = request.get_json()
387-
days = data.get('days', 30)
396+
days = data.get("days", 30)
388397

389398
ml_engine.cleanup_old_patterns(days)
390-
return jsonify({'message': f'Cleaned up patterns older than {days} days'})
399+
return jsonify({"message": f"Cleaned up patterns older than {days} days"})
391400

392401
except Exception as e:
393-
return jsonify({'error': str(e)}), 500
402+
return jsonify({"error": str(e)}), 500
394403

395404
print(f"Starting ShellRosetta API server on http://{host}:{port}")
396405
print("Press Ctrl+C to stop the server")
397406

398407
app.run(host=host, port=port, debug=debug)
399408

400-
if __name__ == '__main__':
409+
410+
if __name__ == "__main__":
401411
run_api_server()

shellrosetta/cli.py

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,30 @@
33
from .config import config
44
from .plugins import plugin_manager
55
from .ml_engine import ml_engine
6-
from .utils import print_header, print_translation, sanitize_command, format_command_history
6+
from .utils import (
7+
print_header,
8+
print_translation,
9+
sanitize_command,
10+
format_command_history,
11+
)
712
from .api import run_api_server
813

914
import sys
15+
1016
try:
1117
import readline
1218
except ImportError:
1319
# readline not available on Windows
1420
pass
1521

1622
from .core import lnx2ps, ps2lnx
23+
24+
1725
def show_help():
1826
print_header()
1927
print("Usage:")
20-
print(" shellrosetta lnx2ps \"linux command here\"")
21-
print(" shellrosetta ps2lnx \"powershell command here\"")
28+
print(' shellrosetta lnx2ps "linux command here"')
29+
print(' shellrosetta ps2lnx "powershell command here"')
2230
print(" shellrosetta # Interactive shell mode")
2331
print(" shellrosetta config # Show configuration")
2432
print(" shellrosetta history # Show command history")
@@ -27,16 +35,18 @@ def show_help():
2735
print(" shellrosetta ml # Show ML insights")
2836
print("")
2937
print("Examples:")
30-
print(" shellrosetta lnx2ps \"ls -alh | grep foo\"")
31-
print(" shellrosetta ps2lnx \"Get-ChildItem -Force | Select-String foo\"")
38+
print(' shellrosetta lnx2ps "ls -alh | grep foo"')
39+
print(' shellrosetta ps2lnx "Get-ChildItem -Force | Select-String foo"')
3240
print(" shellrosetta api --port 8080 # Start API on port 8080")
3341
print("=" * 65)
3442

3543

3644
def run_interactive():
3745
print_header()
3846
print("Welcome to ShellRosetta Interactive Mode!")
39-
print("Type 'exit' to quit, 'mode' to switch translation direction, or 'help' for commands.")
47+
print(
48+
"Type 'exit' to quit, 'mode' to switch translation direction, or 'help' for commands."
49+
)
4050

4151
# Initialize history
4252
history = []
@@ -52,7 +62,9 @@ def run_interactive():
5262
show_interactive_help()
5363
continue
5464

55-
print(f"Type your {mode.upper()} commands below. Type 'mode' to switch, 'exit' to quit.\n")
65+
print(
66+
f"Type your {mode.upper()} commands below. Type 'mode' to switch, 'exit' to quit.\n"
67+
)
5668

5769
while True:
5870
try:
@@ -107,7 +119,7 @@ def run_interactive():
107119

108120
# Store in history
109121
history.append((sanitized, translated, mode))
110-
if len(history) > config.get('max_history', 100):
122+
if len(history) > config.get("max_history", 100):
111123
history.pop(0)
112124

113125
# Print translation
@@ -144,7 +156,7 @@ def show_plugins():
144156
for plugin in plugins:
145157
print(f" {plugin['name']} v{plugin['version']}")
146158
print(f" Commands: {', '.join(plugin['supported_commands'])}")
147-
if plugin.get('description'):
159+
if plugin.get("description"):
148160
print(f" Description: {plugin['description']}")
149161
print()
150162
else:
@@ -162,7 +174,7 @@ def show_ml_insights():
162174
print(f" Success Rate: {analysis.get('success_rate', 0):.1%}")
163175
print(f" Command Types: {dict(analysis.get('command_types', {}))}")
164176

165-
top_patterns = analysis.get('top_successful_patterns', [])
177+
top_patterns = analysis.get("top_successful_patterns", [])
166178
if top_patterns:
167179
print("\n Top Successful Patterns:")
168180
for cmd, rate in top_patterns[:5]:
@@ -180,22 +192,22 @@ def main():
180192

181193
# Handle special commands
182194
if len(sys.argv) == 2:
183-
if sys.argv[1] in ('-h', '--help', 'help'):
195+
if sys.argv[1] in ("-h", "--help", "help"):
184196
show_help()
185197
sys.exit(0)
186-
elif sys.argv[1] == 'config':
198+
elif sys.argv[1] == "config":
187199
show_config()
188200
sys.exit(0)
189-
elif sys.argv[1] == 'history':
201+
elif sys.argv[1] == "history":
190202
print("History feature not yet implemented for non-interactive mode.")
191203
sys.exit(0)
192-
elif sys.argv[1] == 'plugins':
204+
elif sys.argv[1] == "plugins":
193205
show_plugins()
194206
sys.exit(0)
195-
elif sys.argv[1] == 'ml':
207+
elif sys.argv[1] == "ml":
196208
show_ml_insights()
197209
sys.exit(0)
198-
elif sys.argv[1] == 'api':
210+
elif sys.argv[1] == "api":
199211
run_api_server()
200212
return
201213

@@ -204,7 +216,7 @@ def main():
204216
sys.exit(1)
205217

206218
mode = sys.argv[1].lower()
207-
if mode not in ['lnx2ps', 'ps2lnx']:
219+
if mode not in ["lnx2ps", "ps2lnx"]:
208220
print("Unknown mode:", mode)
209221
show_help()
210222
sys.exit(1)
@@ -224,6 +236,7 @@ def main():
224236
translated = ps2lnx(sanitized)
225237
print_translation(command, translated, mode)
226238

239+
227240
# Allow both python -m and entry point execution
228241
if __name__ == "__main__" or __name__ == "shellrosetta.cli":
229242
main()

shellrosetta/config.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from pathlib import Path
33
import os
44
import json
5+
6+
57
class Config:
68
"""Configuration management for ShellRosetta"""
79

@@ -14,15 +16,15 @@ def __init__(self):
1416
"preferred_shell": "auto", # auto, powershell, bash
1517
"color_output": True,
1618
"max_history": 100,
17-
"auto_complete": True
19+
"auto_complete": True,
1820
}
1921
self.config = self.load_config()
2022

2123
def load_config(self):
2224
"""Load configuration from file or create default"""
2325
if self.config_file.exists():
2426
try:
25-
with open(self.config_file, 'r') as f:
27+
with open(self.config_file, "r") as f:
2628
config = json.load(f)
2729
# Merge with defaults for any missing keys
2830
for key, value in self.default_config.items():
@@ -42,7 +44,7 @@ def save_config(self, config=None):
4244
if config is None:
4345
config = self.config
4446
try:
45-
with open(self.config_file, 'w') as f:
47+
with open(self.config_file, "w") as f:
4648
json.dump(config, f, indent=2)
4749
except IOError:
4850
pass # Silently fail if we can't write config
@@ -61,5 +63,6 @@ def reset(self):
6163
self.config = self.default_config.copy()
6264
self.save_config()
6365

66+
6467
# Global config instance
6568
config = Config()

0 commit comments

Comments
 (0)