Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

executors: add basic autodetection from filename #968

Merged
merged 1 commit into from
Dec 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions dmoj/commands/submit.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from typing import Optional

from dmoj import judgeenv
from dmoj import executors, judgeenv
from dmoj.commands.base_command import Command
from dmoj.error import InvalidCommandException
from dmoj.executors import executors
from dmoj.judge import Submission


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

if language_id not in executors:
if language_id not in executors.executors:
source_file = language_id
language_id = None # source file / language id optional

if problem_id not in judgeenv.get_supported_problems():
raise InvalidCommandException(f"unknown problem '{problem_id}'")
elif not language_id:
if source_file:
filename, dot, ext = source_file.partition('.')
if not ext:
raise InvalidCommandException('invalid file name')
else:
# TODO: this should be a proper lookup elsewhere
ext = ext.upper()
language_id = {'PY': 'PY2', 'CPP': 'CPP11', 'JAVA': 'JAVA8'}.get(ext, ext)
language_id = executors.from_filename(source_file).Executor.name
else:
raise InvalidCommandException('no language is selected')
elif language_id not in executors:
elif language_id not in executors.executors:
raise InvalidCommandException(f"unknown language '{language_id}'")
elif time_limit <= 0:
raise InvalidCommandException('--time-limit must be >= 0')
Expand Down
22 changes: 22 additions & 0 deletions dmoj/executors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,28 @@
executors: Dict[str, Any] = {}


def by_ext(ext: str) -> Any:
ext = ext.lower()

for name, executor in executors.items():
if name.lower() == ext:
return executor

for executor in sorted(executors.values(), key=lambda executor: executor.Executor.name):
if executor.Executor.ext == ext:
return executor

raise KeyError('no executor for extension "%s"' % ext)


def from_filename(filename: str) -> Any:
_, _, ext = filename.partition('.')
if not ext:
raise KeyError('invalid file name')

return by_ext(ext)


def get_available():
return get_available_modules(
_reexecutor, os.path.dirname(__file__), only_executors, exclude_executors | _unsupported_executors
Expand Down
34 changes: 22 additions & 12 deletions dmoj/utils/helper_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def compile_with_auxiliary_files(
compiler_time_limit: Optional[int] = None,
unbuffered: bool = False,
) -> 'BaseExecutor':
from dmoj.executors import executors
from dmoj import executors
from dmoj.executors.compiled_executor import CompiledExecutor

sources = {}
Expand All @@ -35,23 +35,33 @@ def compile_with_auxiliary_files(
with open(filename, 'rb') as f:
sources[os.path.basename(filename)] = f.read()

def find_runtime(languages):
def find_runtime(*languages):
for grader in languages:
if grader in executors:
if grader in executors.executors:
return grader
return None

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

executor = executors.get(lang)
if not executor:
raise IOError('could not find an appropriate C++ executor')

executor = executor.Executor
if not lang:
if use_cpp:
lang = find_runtime('CPP20', 'CPP17', 'CPP14', 'CPP11', 'CPP03')
elif use_c:
lang = find_runtime('C11', 'C')

# TODO: remove above code once `from_filename` is smart enough to
# prioritize newer versions of runtimes
if not lang:
for filename in filenames:
try:
lang = executors.from_filename(filename).Executor.name
except KeyError:
continue

if not lang:
raise IOError('could not find an appropriate executor')

executor = executors.executors[lang].Executor

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

Expand Down
File renamed without changes.
4 changes: 1 addition & 3 deletions testsuite/generator_python/init.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
generator:
language: PY2
source: gen.py
generator: gen.py2
test_cases:
- {generator_args: [1, 2], points: 1}
- {generator_args: [10, 20], points: 1}
Expand Down