Skip to content

Commit e61a2be

Browse files
feat: language mapping and result handling
1 parent d5daa90 commit e61a2be

File tree

7 files changed

+318
-239
lines changed

7 files changed

+318
-239
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
TODO.md
22
__pycache__
33
.venv
4-
leetcode_cli.egg-info
4+
leetcode_cli.egg-info
5+
*.cpp

src/commands/edit.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from ..server.solution_manager import SolutionManager
44
from ..server.auth import Auth
5-
from .test import map_lang
5+
from ..server.config import LANGUAGE_MAP
66

77
solution_manager = SolutionManager(Auth().get_session())
88

@@ -26,7 +26,7 @@ def create_file_with_template(lang: str):
2626
filename = f"{filename_prefix}.{lang}"
2727
with open(filename, "w") as f:
2828
for snippet in question_data.get('codeSnippets', []):
29-
if snippet.get('langSlug').lower() == map_lang.get(lang):
29+
if snippet.get('langSlug').lower() == LANGUAGE_MAP.get(lang):
3030
f.write(snippet.get('code'))
3131
return
3232
typer.echo(f"No template found for language {lang}")

src/commands/submit.py

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from typing import Optional
55
from ..server.auth import Auth
66
from ..server.solution_manager import SolutionManager
7+
from ..server.config import LANGUAGE_MAP
78
from ..lib.submission_ui import (
89
display_auth_error, display_file_not_found_error, display_language_detection_message,
910
display_language_detection_error, display_problem_not_found_error, display_submission_details,
@@ -14,21 +15,6 @@
1415
auth_manager = Auth()
1516
solution_manager = SolutionManager(auth_manager.get_session())
1617

17-
LANGUAGE_MAP = {
18-
'.py': 'python3',
19-
'.cpp': 'cpp',
20-
'.c': 'c',
21-
'.java': 'java',
22-
'.js': 'javascript',
23-
'.ts': 'typescript',
24-
'.go': 'golang',
25-
'.rs': 'rust',
26-
'.rb': 'ruby',
27-
'.cs': 'csharp',
28-
'.swift': 'swift',
29-
'.php': 'php',
30-
}
31-
3218
def submit(
3319
problem: str = typer.Argument(..., help="Problem slug or number (e.g., 'two-sum' or '1')"),
3420
file: Path = typer.Argument(..., help="Path to solution file"),

src/commands/test.py

Lines changed: 25 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,68 +2,50 @@
22
from pathlib import Path
33
from ..server.auth import Auth
44
from ..server.solution_manager import SolutionManager
5+
from ..server.config import LANGUAGE_MAP
6+
from ..lib.submission_ui import (
7+
display_auth_error, display_file_not_found_error,
8+
display_language_detection_error, display_submission_results, display_exception_error,
9+
create_submission_progress, display_language_detection_message
10+
)
511

612
auth_manager = Auth()
713
solution_manager = SolutionManager(auth_manager.get_session())
814

9-
map_lang = {
10-
"py": "python3",
11-
"java": "java",
12-
"js": "javascript",
13-
"ts": "typescript",
14-
"c": "c",
15-
"cpp": "cpp",
16-
"cs": "csharp",
17-
"go": "golang",
18-
"rb": "ruby",
19-
"swift": "swift",
20-
"rs": "rust",
21-
"php": "php"
22-
}
15+
FILE_EXT_TO_LANG = {ext.lstrip('.'): lang for ext, lang in LANGUAGE_MAP.items()}
2316

2417
def test(
2518
problem: str = typer.Argument(..., help="Problem slug (e.g., 'two-sum')"),
2619
file: Path = typer.Argument(..., help="Path to solution file"),
2720
):
2821
"""Test a solution with LeetCode's test cases"""
2922
if not auth_manager.is_authenticated:
30-
typer.echo(typer.style("❌ Please login first using the login command", fg=typer.colors.RED))
31-
raise typer.Exit(1)
23+
display_auth_error()
3224

3325
if not file.exists():
34-
typer.echo(typer.style(f"❌ File not found: {file}", fg=typer.colors.RED))
35-
raise typer.Exit(1)
26+
display_file_not_found_error(file)
3627

3728
with open(file, 'r') as f:
3829
code = f.read()
3930

40-
lang = map_lang.get(file.suffix[1:])
31+
file_ext = file.suffix[1:] if file.suffix else ""
32+
lang = FILE_EXT_TO_LANG.get(file_ext)
4133
if not lang:
42-
typer.echo(typer.style(f"❌ Unsupported file extension: {file.suffix}", fg=typer.colors.RED))
43-
typer.echo(f"Supported extensions: {', '.join(map_lang.keys())}")
44-
raise typer.Exit(1)
34+
display_language_detection_error(file.suffix)
35+
return
36+
37+
display_language_detection_message(lang)
4538

4639
typer.echo(typer.style("🧪 Testing solution with LeetCode test cases...", fg=typer.colors.YELLOW))
40+
4741
try:
48-
result = solution_manager.test_solution(problem, code, lang)
49-
except Exception as e:
50-
typer.echo(typer.style(f"❌ Error connecting to LeetCode: {str(e)}", fg=typer.colors.RED))
51-
raise typer.Exit(1)
42+
with create_submission_progress() as progress:
43+
test_task = progress.add_task("Testing...", total=1)
44+
progress.update(test_task, advance=0.5)
45+
result = solution_manager.test_solution(problem, code, lang)
46+
progress.update(test_task, advance=0.5)
5247

53-
if result["success"]:
54-
status_color = typer.colors.GREEN if result["status"] == "Accepted" else typer.colors.RED
55-
status_prefix = "✨" if result['status'] == "Accepted" else "❌"
56-
typer.echo(typer.style(f"\n{status_prefix} Status: {result['status']}", fg=status_color))
57-
if "runtime" in result:
58-
typer.echo(f"⏱️Runtime: {result['runtime']}")
59-
if "memory" in result:
60-
typer.echo(f"💾 Memory: {result['memory']}")
61-
typer.echo("\nTest Case Results:\n")
62-
typer.echo(f"📤 Your Output:\n{result['output']}")
63-
typer.echo(f"✅ Expected:\n{result['expected']}")
64-
else:
65-
typer.echo(typer.style(f"\n{result['status']}", fg=typer.colors.BRIGHT_RED))
66-
error_message = f"\n{result['error']}"
67-
if result.get('full_error'):
68-
error_message += f"\n\nFull error:\n{result['full_error']}"
69-
typer.echo(typer.style(error_message, fg=typer.colors.RED))
48+
display_submission_results(result)
49+
50+
except Exception as e:
51+
display_exception_error(e)

src/lib/submission_ui.py

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
from rich.console import Console
22
from rich.panel import Panel
3-
from rich.table import Table
43
from rich.progress import Progress, BarColumn, TextColumn
54
from rich import box
6-
from rich.text import Text
75
from rich.columns import Columns
86
import typer
97

@@ -37,7 +35,6 @@ def display_problem_not_found_error(problem):
3735

3836
def display_submission_details(problem, problem_name, lang, file):
3937
"""Display submission details and confirmation prompt using a clean layout"""
40-
# Create formatted text lines instead of a nested table
4138
content = [
4239
f"[cyan]Problem:[/] {problem} - {problem_name}",
4340
f"[cyan]Language:[/] {lang}",
@@ -71,7 +68,6 @@ def display_submission_results(result):
7168
if result["success"]:
7269
status = result['status']
7370

74-
# Set colors based on status
7571
if status == "Accepted":
7672
status_style = "bold green"
7773
border_style = "green"
@@ -85,19 +81,27 @@ def display_submission_results(result):
8581
border_style = "red"
8682
emoji = "❌"
8783

88-
# Get metrics
8984
runtime = result.get('runtime', 'N/A')
9085
memory = result.get('memory', 'N/A')
86+
87+
memory_warning = result.get('memory_warning')
88+
if memory_warning:
89+
memory = f"{memory} [bold yellow](!)[/]"
90+
9191
passed = result.get('passed_testcases', 0)
9292
total = result.get('total_testcases', 0)
9393
test_case_str = f"{passed}/{total} ({passed/total*100:.1f}%)" if total > 0 else "N/A"
9494

9595
content = [
9696
f"[cyan]⏱️ Runtime:[/] {runtime}",
97-
f"[cyan]💾 Memory:[/] {memory}",
98-
f"[cyan]🧪 Test Cases:[/] {test_case_str}"
97+
f"[cyan]💾 Memory:[/] {memory}"
9998
]
10099

100+
if result.get('elapsed_time'):
101+
content.append(f"[cyan]⏲️ Elapsed Time:[/] {result.get('elapsed_time')} ms")
102+
103+
content.append(f"[cyan]🧪 Test Cases:[/] {test_case_str}")
104+
101105
title = f"{emoji} Submission Result: [{status_style}]{status}[/]"
102106
console.print(Panel(
103107
"\n".join(content),
@@ -106,9 +110,48 @@ def display_submission_results(result):
106110
box=box.ROUNDED
107111
))
108112

109-
if status != "Accepted" and result.get('error_message'):
110-
error_msg = result.get('error_message', 'No details available')
113+
if memory_warning:
114+
console.print(Panel(
115+
memory_warning,
116+
title="⚠️ Memory Usage Warning",
117+
border_style="yellow",
118+
box=box.ROUNDED
119+
))
120+
121+
if result.get('stdout'):
122+
console.print(Panel(
123+
result.get('stdout'),
124+
title="📝 Standard Output",
125+
border_style="blue",
126+
box=box.ROUNDED
127+
))
128+
129+
if result.get('output') and result.get('expected'):
130+
is_wrong_answer = status == "Wrong Answer"
131+
132+
output_panel = Panel(
133+
result.get('output', ''),
134+
title="Your Output",
135+
border_style="red" if is_wrong_answer else "blue"
136+
)
137+
expected_panel = Panel(
138+
result.get('expected', ''),
139+
title="Expected Output",
140+
border_style="green"
141+
)
142+
console.print(Columns([output_panel, expected_panel]))
143+
144+
if status != "Accepted" and result.get('error'):
145+
error_msg = result.get('error', 'No details available')
111146
console.print(Panel(error_msg, title="Error Details", border_style="red"))
147+
148+
if result.get('full_error'):
149+
console.print(Panel(
150+
result.get('full_error', ''),
151+
title="Full Error Trace",
152+
border_style="red",
153+
box=box.ROUNDED
154+
))
112155
else:
113156
error_panel = Panel(
114157
f"{result.get('error', 'Unknown error')}",
@@ -117,6 +160,22 @@ def display_submission_results(result):
117160
)
118161
console.print(error_panel)
119162

163+
if result.get('stdout'):
164+
console.print(Panel(
165+
result.get('stdout'),
166+
title="📝 Standard Output",
167+
border_style="blue",
168+
box=box.ROUNDED
169+
))
170+
171+
if result.get('full_error'):
172+
console.print(Panel(
173+
result.get('full_error', ''),
174+
title="Full Error Trace",
175+
border_style="red",
176+
box=box.ROUNDED
177+
))
178+
120179
def display_exception_error(e):
121180
"""Display exception error message"""
122181
console.print(Panel(f"❌ Error: {str(e)}", style="bold red", border_style="red"))

src/server/config.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,28 @@
11
BASE_URL = "https://leetcode.com/graphql"
2+
LEETCODE_BASE_URL = "https://leetcode.com"
3+
STATUS_CODES = {
4+
10: "Accepted",
5+
14: "Time Limit Exceeded",
6+
15: "Runtime Error",
7+
16: "Memory Limit Exceeded",
8+
20: "Compile Error",
9+
30: "Wrong Answer"
10+
}
11+
LANGUAGE_MAP = {
12+
'.py': 'python3',
13+
'.cpp': 'cpp',
14+
'.c': 'c',
15+
'.java': 'java',
16+
'.js': 'javascript',
17+
'.ts': 'typescript',
18+
'.go': 'golang',
19+
'.rs': 'rust',
20+
'.rb': 'ruby',
21+
'.cs': 'csharp',
22+
'.swift': 'swift',
23+
'.php': 'php',
24+
}
25+
MEMORY_WARNING_THRESHOLD = 100000000 # 100MB
26+
MEMORY_LIMIT_THRESHOLD = 450000000 # 450MB
27+
TEST_RESULT_TIMEOUT = 30
28+
SUBMISSION_RESULT_TIMEOUT = 20

0 commit comments

Comments
 (0)