Skip to content

Commit 3bafdd3

Browse files
committed
executors: add basic autodetection from filename
Ref #967
1 parent 2871cb3 commit 3bafdd3

File tree

4 files changed

+42
-21
lines changed

4 files changed

+42
-21
lines changed

dmoj/commands/submit.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
from typing import Optional
22

3-
from dmoj import judgeenv
3+
from dmoj import executors, judgeenv
44
from dmoj.commands.base_command import Command
55
from dmoj.error import InvalidCommandException
6-
from dmoj.executors import executors
76
from dmoj.judge import Submission
87

98

@@ -45,24 +44,18 @@ def execute(self, line: str) -> None:
4544
memory_limit: int = args.memory_limit
4645
source_file: Optional[str] = args.source_file
4746

48-
if language_id not in executors:
47+
if language_id not in executors.executors:
4948
source_file = language_id
5049
language_id = None # source file / language id optional
5150

5251
if problem_id not in judgeenv.get_supported_problems():
5352
raise InvalidCommandException(f"unknown problem '{problem_id}'")
5453
elif not language_id:
5554
if source_file:
56-
filename, dot, ext = source_file.partition('.')
57-
if not ext:
58-
raise InvalidCommandException('invalid file name')
59-
else:
60-
# TODO: this should be a proper lookup elsewhere
61-
ext = ext.upper()
62-
language_id = {'PY': 'PY2', 'CPP': 'CPP11', 'JAVA': 'JAVA8'}.get(ext, ext)
55+
language_id = executors.from_filename(source_file).Executor.name
6356
else:
6457
raise InvalidCommandException('no language is selected')
65-
elif language_id not in executors:
58+
elif language_id not in executors.executors:
6659
raise InvalidCommandException(f"unknown language '{language_id}'")
6760
elif time_limit <= 0:
6861
raise InvalidCommandException('--time-limit must be >= 0')

dmoj/executors/__init__.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,28 @@
1515
executors: Dict[str, Any] = {}
1616

1717

18+
def by_ext(ext: str) -> Any:
19+
ext = ext.lower()
20+
21+
for name, executor in executors.items():
22+
if name.lower() == ext:
23+
return executor
24+
25+
for executor in sorted(executors.values(), key=lambda executor: executor.Executor.name):
26+
if executor.Executor.ext == ext:
27+
return executor
28+
29+
raise KeyError('no executor for extension "%s"' % ext)
30+
31+
32+
def from_filename(filename: str) -> Any:
33+
_, _, ext = filename.partition('.')
34+
if not ext:
35+
raise KeyError('invalid file name')
36+
37+
return by_ext(ext)
38+
39+
1840
def get_available():
1941
return get_available_modules(
2042
_reexecutor, os.path.dirname(__file__), only_executors, exclude_executors | _unsupported_executors

dmoj/utils/helper_files.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def compile_with_auxiliary_files(
2626
compiler_time_limit: Optional[int] = None,
2727
unbuffered: bool = False,
2828
) -> 'BaseExecutor':
29-
from dmoj.executors import executors
29+
from dmoj import executors
3030
from dmoj.executors.compiled_executor import CompiledExecutor
3131

3232
sources = {}
@@ -37,21 +37,29 @@ def compile_with_auxiliary_files(
3737

3838
def find_runtime(languages):
3939
for grader in languages:
40-
if grader in executors:
40+
if grader in executors.executors:
4141
return grader
4242
return None
4343

4444
use_cpp = any(map(lambda name: os.path.splitext(name)[1] in ['.cpp', '.cc'], filenames))
4545
use_c = any(map(lambda name: os.path.splitext(name)[1] in ['.c'], filenames))
46-
if lang is None:
46+
if not lang:
4747
best_choices = ('CPP20', 'CPP17', 'CPP14', 'CPP11', 'CPP03') if use_cpp else ('C11', 'C')
4848
lang = find_runtime(best_choices)
4949

50-
executor = executors.get(lang)
51-
if not executor:
52-
raise IOError('could not find an appropriate C++ executor')
50+
# TODO: remove above code once `from_filename` is smart enough to
51+
# prioritize newer versions of runtimes
52+
if not lang:
53+
for filename in filenames:
54+
try:
55+
lang = executors.from_filename(filename).Executor.name
56+
except KeyError:
57+
continue
5358

54-
executor = executor.Executor
59+
if not lang:
60+
raise IOError('could not find an appropriate executor')
61+
62+
executor = executors.executors[lang].Executor
5563

5664
kwargs = {'fs': executor.fs + [RecursiveDir(tempfile.gettempdir())]}
5765

testsuite/generator_python/init.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
generator:
2-
language: PY2
3-
source: gen.py
1+
generator: gen.py2
42
test_cases:
53
- {generator_args: [1, 2], points: 1}
64
- {generator_args: [10, 20], points: 1}

0 commit comments

Comments
 (0)