rbx.cp 0.13.3__py3-none-any.whl → 0.13.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 (53) hide show
  1. rbx/annotations.py +5 -5
  2. rbx/box/checkers.py +24 -13
  3. rbx/box/cli.py +1 -4
  4. rbx/box/contest/build_contest_statements.py +16 -3
  5. rbx/box/contest/schema.py +1 -2
  6. rbx/box/fields.py +25 -1
  7. rbx/box/generators.py +5 -2
  8. rbx/box/global_package.py +5 -1
  9. rbx/box/header.py +19 -11
  10. rbx/box/package.py +3 -1
  11. rbx/box/presets/__init__.py +2 -2
  12. rbx/box/schema.py +4 -25
  13. rbx/box/statements/build_statements.py +5 -1
  14. rbx/box/statements/builders.py +7 -7
  15. rbx/box/statements/schema.py +11 -2
  16. rbx/box/testcase_utils.py +2 -0
  17. rbx/box/testing/__init__.py +0 -0
  18. rbx/box/testing/testing_package.py +241 -0
  19. rbx/box/testing/testing_preset.py +36 -0
  20. rbx/box/testing/testing_shared.py +81 -0
  21. rbx/box/validators.py +2 -1
  22. rbx/grading/caching.py +3 -2
  23. rbx/resources/presets/default/shared/contest_template.rbx.tex +1 -1
  24. rbx/resources/presets/default/shared/problem_template.rbx.tex +5 -1
  25. rbx/testing_utils.py +1 -1
  26. rbx/utils.py +8 -0
  27. {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.4.dist-info}/METADATA +2 -1
  28. {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.4.dist-info}/RECORD +31 -49
  29. rbx/box/conftest.py +0 -42
  30. rbx/box/generators_test.py +0 -67
  31. rbx/box/lazy_importing_test.py +0 -25
  32. rbx/box/solutions_test.py +0 -47
  33. rbx/box/validators_test.py +0 -15
  34. rbx/checker.py +0 -128
  35. rbx/clone.py +0 -197
  36. rbx/conftest.py +0 -38
  37. rbx/create.py +0 -37
  38. rbx/edit.py +0 -24
  39. rbx/grading/conftest.py +0 -33
  40. rbx/grading/steps_with_caching_run_test.py +0 -707
  41. rbx/grading_utils.py +0 -148
  42. rbx/hydration.py +0 -101
  43. rbx/main.py +0 -118
  44. rbx/metadata.py +0 -105
  45. rbx/run.py +0 -45
  46. rbx/schema.py +0 -64
  47. rbx/submit.py +0 -61
  48. rbx/test.py +0 -349
  49. rbx/testcase.py +0 -70
  50. rbx/testcase_rendering.py +0 -79
  51. {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.4.dist-info}/LICENSE +0 -0
  52. {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.4.dist-info}/WHEEL +0 -0
  53. {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.4.dist-info}/entry_points.txt +0 -0
rbx/grading_utils.py DELETED
@@ -1,148 +0,0 @@
1
- import pathlib
2
- from pathlib import PosixPath
3
- from typing import List
4
-
5
- from rbx import config
6
- from rbx.config import Artifact, Language, format_vars
7
- from rbx.grading import steps
8
- from rbx.grading.judge.sandbox import MERGE_STDERR, SandboxParams
9
- from rbx.grading.steps import (
10
- GradingArtifacts,
11
- GradingFileInput,
12
- GradingFileOutput,
13
- TestcaseIO,
14
- )
15
- from rbx.schema import DumpedProblem, Problem
16
-
17
-
18
- def build_formatted_command(
19
- command: str, problem: DumpedProblem, lang: Language
20
- ) -> str:
21
- return format_vars(
22
- command,
23
- **problem.get_vars(),
24
- file=lang.get_file(problem.code),
25
- submit_file=lang.get_submit_file(problem.code),
26
- )
27
-
28
-
29
- def build_preprocess_commands(problem: DumpedProblem, lang: Language) -> List[str]:
30
- return [
31
- build_formatted_command(cmd, problem, lang) for cmd in (lang.preprocess or [])
32
- ]
33
-
34
-
35
- def build_preprocess_sandbox_params() -> SandboxParams:
36
- params = SandboxParams(
37
- max_processes=None,
38
- preserve_env=True,
39
- )
40
- params.add_mapped_directory(pathlib.Path('/usr'))
41
- params.add_mapped_directory(pathlib.Path('/etc'))
42
- return params
43
-
44
-
45
- def build_compile_grading_artifacts(
46
- problem: DumpedProblem, lang: Language
47
- ) -> GradingArtifacts:
48
- res = GradingArtifacts(root=PosixPath('.'))
49
- file = lang.get_file(problem.code)
50
- submit_file = lang.get_submit_file(problem.code)
51
- # Copy input file.
52
- res.inputs.append(GradingFileInput(src=PosixPath(file), dest=PosixPath(file)))
53
- # Copy output file.
54
- if lang.has_submit_file():
55
- res.outputs.append(
56
- GradingFileOutput(
57
- src=PosixPath(submit_file),
58
- dest=PosixPath(submit_file),
59
- )
60
- )
61
- # Copy other artifacts.
62
- for artifact_name, artifact_cfg in lang.artifacts.items():
63
- artifact_cfg = artifact_cfg or Artifact()
64
- artifact_path = format_vars(
65
- artifact_name, **problem.get_vars(), file=file, submit_file=submit_file
66
- )
67
- res.outputs.append(
68
- GradingFileOutput(
69
- src=PosixPath(artifact_path),
70
- dest=PosixPath(artifact_cfg.filename or artifact_path),
71
- optional=artifact_cfg.optional,
72
- executable=artifact_cfg.executable,
73
- )
74
- )
75
-
76
- return res
77
-
78
-
79
- def build_run_sandbox_params(problem: Problem, has_input: bool) -> SandboxParams:
80
- params = SandboxParams()
81
- params.timeout = problem.timeLimit * 2
82
- params.wallclock_timeout = problem.timeLimit * 5
83
- params.address_space = problem.memoryLimit or 1024 # 1 GB
84
- params.set_stdall(
85
- stdin=PosixPath('stdin.txt') if has_input else None,
86
- stdout=PosixPath('stdout.txt'),
87
- stderr=MERGE_STDERR,
88
- )
89
- return params
90
-
91
-
92
- def build_run_grading_artifacts(
93
- testcase: TestcaseIO, persist_root: pathlib.Path
94
- ) -> GradingArtifacts:
95
- res = GradingArtifacts(root=PosixPath('.'))
96
- res.inputs.append(
97
- GradingFileInput(
98
- src=testcase.input,
99
- dest=PosixPath('stdin.txt'),
100
- )
101
- )
102
- res.outputs.append(
103
- GradingFileOutput(
104
- src=PosixPath('stdout.txt'),
105
- dest=persist_root / f'stdout-{testcase.index}.txt',
106
- maxlen=steps.MAX_STDOUT_LEN,
107
- )
108
- )
109
- return res
110
-
111
-
112
- def build_checker_compile_grading_artifacts(
113
- problem: DumpedProblem, persist_root: pathlib.Path
114
- ) -> GradingArtifacts:
115
- res = GradingArtifacts(root=PosixPath('.'))
116
- if not problem.checker:
117
- return res
118
-
119
- checker_path = PosixPath(problem.checker)
120
- if not checker_path.is_file():
121
- checker_path = config.get_builtin_checker(problem.checker)
122
- if not checker_path:
123
- return res
124
-
125
- res.inputs.append(GradingFileInput(src=checker_path, dest=PosixPath('checker.cpp')))
126
- testlib = config.get_testlib()
127
- if testlib.is_file():
128
- res.inputs.append(GradingFileInput(src=testlib, dest=PosixPath('testlib.h')))
129
- res.outputs.append(
130
- GradingFileOutput(
131
- src=PosixPath('checker'), dest=persist_root / 'checker', executable=True
132
- )
133
- )
134
- return res
135
-
136
-
137
- def build_checker_run_grading_artifacts(
138
- problem: DumpedProblem, persist_root: pathlib.Path
139
- ) -> GradingArtifacts:
140
- res = GradingArtifacts(root=PosixPath('.'))
141
- if not problem.checker:
142
- return res
143
- res.inputs.append(
144
- GradingFileInput(
145
- src=persist_root / 'checker', dest=PosixPath('checker'), executable=True
146
- )
147
- )
148
- return res
rbx/hydration.py DELETED
@@ -1,101 +0,0 @@
1
- import pathlib
2
- from typing import List, Optional, Tuple
3
-
4
- from rbx import config, hydration, metadata
5
- from rbx.console import console
6
- from rbx.schema import DumpedProblem, Testcase
7
- from rbx.test import get_testcases_io
8
-
9
-
10
- def get_testcase_paths(
11
- root: pathlib.Path, problem: DumpedProblem, i: int
12
- ) -> Tuple[pathlib.Path, pathlib.Path]:
13
- return (root / f'{problem.code}.{i}.in', root / f'{problem.code}.{i}.out')
14
-
15
-
16
- def hydrate_problem(root: pathlib.Path, problem: DumpedProblem):
17
- for i, testcase in enumerate(problem.tests or []):
18
- in_path, out_path = get_testcase_paths(root, problem, i)
19
- in_path.write_text(testcase.input)
20
- out_path.write_text(testcase.output)
21
-
22
-
23
- def add_testcase(root: pathlib.Path, problem: DumpedProblem, testcase: Testcase):
24
- problem_path = metadata.find_problem_path_by_code(problem.code, root)
25
- if not problem_path or not problem_path.is_file():
26
- console.print(
27
- f'[error]Problem [item]{problem.pretty_name()}[/item] not found.[/error]'
28
- )
29
- return
30
-
31
- # Pick next number.
32
- i = max([tc.index for tc in get_testcases_io(problem, root)] + [-1]) + 1
33
- in_path, out_path = get_testcase_paths(root, problem, i)
34
- in_path.write_text(testcase.input)
35
- out_path.write_text(testcase.output)
36
-
37
- console.print(
38
- f'Added testcase [item]{i}[/item] to problem [item]{problem.pretty_name()}[/item].'
39
- )
40
-
41
-
42
- def remove_testcase(root: pathlib.Path, problem: DumpedProblem, i: int):
43
- problem_path = metadata.find_problem_path_by_code(problem.code, root)
44
- if not problem_path or not problem_path.is_file():
45
- console.print(
46
- f'[error]Problem [item]{problem.pretty_name()}[/item] not found.[/error]'
47
- )
48
- return
49
-
50
- testcases = get_testcases_io(problem, root)
51
- testcases = [testcase for testcase in testcases if testcase.index == i]
52
- if not testcases:
53
- console.print(
54
- f'[error]Testcase [item]{i}[/item] not found in problem [item]{problem.pretty_name()}[/item].[/error]'
55
- )
56
- return
57
- if testcases[0].input:
58
- testcases[0].input.unlink(missing_ok=True)
59
- if testcases[0].output:
60
- testcases[0].output.unlink(missing_ok=True)
61
-
62
- console.print(
63
- f'Removed testcase [item]{i}[/item] from problem [item]{problem.pretty_name()}[/item].'
64
- )
65
-
66
-
67
- def edit_testcase(root: pathlib.Path, problem: DumpedProblem, i: int):
68
- problem_path = metadata.find_problem_path_by_code(problem.code, root)
69
- if not problem_path or not problem_path.is_file():
70
- console.print(
71
- f'[error]Problem [item]{problem.pretty_name()}[/item] not found.[/error]'
72
- )
73
- return
74
-
75
- testcases = get_testcases_io(problem, root)
76
- testcases = [testcase for testcase in testcases if testcase.index == i]
77
- if not testcases:
78
- console.print(
79
- f'[error]Testcase [item]{i}[/item] not found in problem [item]{problem.pretty_name()}[/item].[/error]'
80
- )
81
- return
82
-
83
- paths: List[Optional[pathlib.Path]] = [testcases[0].input, testcases[0].output]
84
- config.open_editor(*[path for path in paths if path is not None and path.is_file()])
85
-
86
-
87
- def main(problem: Optional[str] = None):
88
- problems_to_hydrate = []
89
- if not problem:
90
- problems_to_hydrate = metadata.find_problems()
91
- else:
92
- dumped_problem = metadata.find_problem_by_anything(problem)
93
- problems_to_hydrate.append(dumped_problem)
94
-
95
- root = pathlib.Path()
96
-
97
- for dumped_problem in problems_to_hydrate:
98
- console.print(
99
- f'Hydrating problem [item]{dumped_problem.pretty_name()}[/item]...'
100
- )
101
- hydration.hydrate_problem(root, dumped_problem)
rbx/main.py DELETED
@@ -1,118 +0,0 @@
1
- # flake8: noqa
2
- import typer
3
- from typing_extensions import Annotated
4
-
5
- from rbx import annotations, checker, config, testcase
6
- from rbx import clone as clone_pkg
7
- from rbx import create as create_pkg
8
- from rbx import edit as edit_pkg
9
- from rbx import run as run_pkg
10
- from rbx import submit as submit_pkg
11
- from rbx import test as test_pkg
12
- from rbx.box import main
13
-
14
- app = typer.Typer(no_args_is_help=True, cls=annotations.AliasGroup)
15
- app.add_typer(main.app, name='box', cls=annotations.AliasGroup)
16
- app.add_typer(
17
- config.app,
18
- name='config, cfg',
19
- cls=annotations.AliasGroup,
20
- help='Manage the configuration of the tool.',
21
- )
22
- app.add_typer(
23
- testcase.app,
24
- name='testcase, tc',
25
- cls=annotations.AliasGroup,
26
- help='Commands to manage the testcases of a problem.',
27
- )
28
- app.add_typer(
29
- checker.app,
30
- name='checker, check',
31
- cls=annotations.AliasGroup,
32
- help='Commands to manage the checker of a problem.',
33
- )
34
-
35
-
36
- @app.command('clone, c')
37
- def clone(lang: annotations.Language):
38
- """
39
- Clones by waiting for a set of problems to be sent through Competitive Companion.
40
- """
41
- clone_pkg.main(lang=lang)
42
-
43
-
44
- @app.command('new, n')
45
- def new(
46
- name: str,
47
- language: annotations.Language,
48
- timelimit: annotations.Timelimit = 1000,
49
- memorylimit: annotations.Memorylimit = 256,
50
- multitest: annotations.Multitest = False,
51
- ):
52
- """
53
- Create a new problem from scratch.
54
- """
55
- create_pkg.main(name, language, timelimit, memorylimit, multitest)
56
-
57
-
58
- @app.command('edit, e')
59
- def edit(
60
- problem: annotations.Problem, language: annotations.LanguageWithDefault = None
61
- ):
62
- """
63
- Edit the code of a problem using the provided language.
64
- """
65
- edit_pkg.main(problem, language)
66
-
67
-
68
- @app.command('test, t')
69
- def test(
70
- problem: annotations.Problem,
71
- language: annotations.LanguageWithDefault = None,
72
- keep_sandbox: bool = False,
73
- index: annotations.TestcaseIndex = None,
74
- interactive: Annotated[bool, typer.Option('--interactive', '--int')] = False,
75
- ):
76
- """
77
- Test a problem using the provided language.
78
- """
79
- test_pkg.main(
80
- problem,
81
- language,
82
- keep_sandbox=keep_sandbox,
83
- index=index,
84
- interactive=interactive,
85
- )
86
-
87
-
88
- @app.command('run, r')
89
- def run(
90
- problem: annotations.Problem,
91
- language: annotations.LanguageWithDefault = None,
92
- keep_sandbox: bool = False,
93
- ):
94
- """
95
- Run a problem using the provided language.
96
- """
97
- run_pkg.main(
98
- problem,
99
- language,
100
- keep_sandbox=keep_sandbox,
101
- )
102
-
103
-
104
- @app.command('submit, s')
105
- def submit(
106
- problem: annotations.Problem,
107
- language: annotations.LanguageWithDefault = None,
108
- keep_sandbox: bool = False,
109
- ):
110
- """
111
- Submit a problem using the provided language.
112
- """
113
- submit_pkg.main(problem, language, keep_sandbox=keep_sandbox)
114
-
115
-
116
- @app.callback()
117
- def callback():
118
- pass
rbx/metadata.py DELETED
@@ -1,105 +0,0 @@
1
- import pathlib
2
- from typing import List, Optional, Tuple
3
-
4
- from rbx.schema import DumpedProblem
5
-
6
-
7
- def _normalize_alias(alias: str) -> str:
8
- return alias.lower()
9
-
10
-
11
- def _find_alias(alias: str, haystack: List[str]) -> Optional[int]:
12
- normalized_alias = _normalize_alias(alias)
13
- for i, candidate in enumerate(haystack):
14
- if _normalize_alias(candidate) == normalized_alias:
15
- return i
16
- return None
17
-
18
-
19
- def _get_best_alias_from_candidates(
20
- alias: str, candidates: List[Tuple[pathlib.Path, DumpedProblem]]
21
- ) -> Optional[Tuple[pathlib.Path, DumpedProblem]]:
22
- best_priority = 1e9
23
- best_candidates = []
24
- for path, problem in candidates:
25
- index = _find_alias(alias, problem.aliases)
26
- if index is None:
27
- continue
28
- if index < best_priority:
29
- best_priority = index
30
- best_candidates = [(path, problem)]
31
- elif index == best_priority:
32
- best_candidates.append((path, problem))
33
-
34
- if len(best_candidates) != 1:
35
- # TODO
36
- return None
37
-
38
- return best_candidates[0]
39
-
40
-
41
- def find_problem_path_by_code(
42
- code: str, root: Optional[pathlib.Path] = None
43
- ) -> Optional[pathlib.Path]:
44
- if not root:
45
- root = pathlib.Path()
46
-
47
- metadata_path = root / f'{code}.rbx.json'
48
- if not metadata_path.is_file():
49
- return None
50
- return metadata_path
51
-
52
-
53
- def find_problem_path_by_alias(
54
- alias: str, root: Optional[pathlib.Path] = None
55
- ) -> Optional[pathlib.Path]:
56
- if not root:
57
- root = pathlib.Path()
58
-
59
- candidates: List[Tuple[pathlib.Path, DumpedProblem]] = []
60
- for metadata_path in root.glob('*.rbx.json'):
61
- problem = DumpedProblem.model_validate_json(metadata_path.read_text())
62
- if _find_alias(alias, problem.aliases) is not None:
63
- candidates.append((metadata_path, problem))
64
-
65
- picked_candidate = _get_best_alias_from_candidates(alias, candidates)
66
- if not picked_candidate:
67
- return None
68
- return picked_candidate[0]
69
-
70
-
71
- def find_problem_by_alias(
72
- alias: str, root: Optional[pathlib.Path] = None
73
- ) -> Optional[DumpedProblem]:
74
- metadata_path = find_problem_path_by_alias(alias, root)
75
- if not metadata_path:
76
- return None
77
- return DumpedProblem.model_validate_json(metadata_path.read_text())
78
-
79
-
80
- def find_problem_by_code(
81
- code: str, root: Optional[pathlib.Path] = None
82
- ) -> Optional[DumpedProblem]:
83
- metadata_path = find_problem_path_by_code(code, root)
84
- if not metadata_path:
85
- return None
86
- return DumpedProblem.model_validate_json(metadata_path.read_text())
87
-
88
-
89
- def find_problem_by_anything(
90
- anything: str, root: Optional[pathlib.Path] = None
91
- ) -> Optional[DumpedProblem]:
92
- problem = find_problem_by_code(anything, root)
93
- if problem:
94
- return problem
95
- return find_problem_by_alias(anything, root)
96
-
97
-
98
- def find_problems(root: Optional[pathlib.Path] = None) -> List[DumpedProblem]:
99
- if not root:
100
- root = pathlib.Path()
101
-
102
- problems = []
103
- for metadata_path in root.glob('*.rbx.json'):
104
- problems.append(DumpedProblem.model_validate_json(metadata_path.read_text()))
105
- return problems
rbx/run.py DELETED
@@ -1,45 +0,0 @@
1
- import atexit
2
- import os
3
- import shlex
4
-
5
- from rbx import annotations, grading_utils, metadata
6
- from rbx.config import get_config
7
- from rbx.console import stderr_console
8
- from rbx.grading import steps
9
- from rbx.grading.judge.sandboxes import stupid_sandbox
10
-
11
-
12
- def main(
13
- problem: annotations.Problem,
14
- language: annotations.LanguageWithDefault = None,
15
- keep_sandbox: bool = False,
16
- ):
17
- dumped_problem = metadata.find_problem_by_anything(problem)
18
- if not dumped_problem:
19
- stderr_console.print(
20
- f'[error]Problem with identifier [item]{problem}[/item] not found.[/error]'
21
- )
22
- return
23
-
24
- lang = get_config().get_language(language)
25
- if not lang:
26
- stderr_console.print(
27
- f'[error]Language {language or get_config().defaultLanguage} not found in config. Please check your configuration.[/error]'
28
- )
29
- return
30
-
31
- box = stupid_sandbox.StupidSandbox()
32
- atexit.register(lambda: box.cleanup(delete=not keep_sandbox))
33
-
34
- preprocess_cmds = grading_utils.build_preprocess_commands(dumped_problem, lang)
35
- sandbox_params = grading_utils.build_preprocess_sandbox_params()
36
- artifacts = grading_utils.build_compile_grading_artifacts(dumped_problem, lang)
37
-
38
- if not steps.compile(preprocess_cmds, sandbox_params, box, artifacts):
39
- stderr_console.print(
40
- f'[error]Failed to preprocess problem [item]{dumped_problem.pretty_name()}[/item].[/error]'
41
- )
42
- return
43
-
44
- cmd = shlex.split(lang.exec)
45
- os.execv(cmd[0], cmd)
rbx/schema.py DELETED
@@ -1,64 +0,0 @@
1
- import uuid
2
- from typing import Dict, List, Optional
3
-
4
- from pydantic import BaseModel
5
-
6
- from rbx import utils
7
-
8
-
9
- class Testcase(BaseModel):
10
- input: str
11
- output: str
12
-
13
-
14
- class Batch(BaseModel):
15
- id: str
16
- size: int
17
-
18
- @staticmethod
19
- def create():
20
- return Batch(id=str(uuid.uuid4()), size=1)
21
-
22
-
23
- class Problem(BaseModel):
24
- name: str
25
- group: str = ''
26
- url: str = ''
27
- interactive: bool = False
28
- memoryLimit: int
29
- timeLimit: int
30
- tests: List[Testcase] = []
31
- testType: str = 'single'
32
- batch: Batch
33
-
34
- def get_code(self):
35
- return self.get_normalized_name()
36
-
37
- def get_normalized_name(self) -> str:
38
- return utils.normalize_with_underscores(self.name)
39
-
40
-
41
- class DumpedProblem(Problem):
42
- code: str
43
- aliases: List[str]
44
- checker: Optional[str] = None
45
-
46
- @staticmethod
47
- def from_problem(problem: Problem, **kwargs) -> 'DumpedProblem':
48
- return DumpedProblem(**problem.model_dump(), **kwargs)
49
-
50
- def pretty_name(self) -> str:
51
- if self.name == self.code:
52
- return self.name
53
- return f'{self.name} ({self.code})'
54
-
55
- def get_vars(self) -> Dict[str, str]:
56
- return {
57
- 'problem_name': self.name,
58
- 'problem_code': self.code,
59
- 'problem_url': self.url,
60
- 'problem_contest': self.group,
61
- 'problem_time_limit': f'{self.timeLimit}ms',
62
- 'problem_memory_limit': f'{self.memoryLimit}MB',
63
- 'problem_test_type': self.testType,
64
- }
rbx/submit.py DELETED
@@ -1,61 +0,0 @@
1
- import atexit
2
- from pathlib import PosixPath
3
- from typing import Optional
4
-
5
- from rbx import annotations, grading_utils, metadata, submitors, utils
6
- from rbx.config import get_config
7
- from rbx.console import console
8
- from rbx.grading import steps
9
- from rbx.grading.judge.sandboxes import stupid_sandbox
10
-
11
-
12
- def main(
13
- problem: annotations.Problem,
14
- language: Optional[annotations.LanguageWithDefault] = None,
15
- keep_sandbox: bool = False,
16
- ):
17
- dumped_problem = metadata.find_problem_by_anything(problem)
18
- if not dumped_problem:
19
- console.print(
20
- f'[error]Problem with identifier [item]{problem}[/item] not found.[/error]'
21
- )
22
- return
23
-
24
- lang = get_config().get_language(language)
25
- if not lang:
26
- console.print(
27
- f'[error]Language {language or get_config().defaultLanguage} not found in config. Please check your configuration.[/error]'
28
- )
29
- return
30
-
31
- box = stupid_sandbox.StupidSandbox()
32
- atexit.register(lambda: box.cleanup(delete=not keep_sandbox))
33
-
34
- with console.status(
35
- f'Preprocessing problem [item]{dumped_problem.pretty_name()}[/item]...'
36
- ):
37
- preprocess_cmds = grading_utils.build_preprocess_commands(dumped_problem, lang)
38
- sandbox_params = grading_utils.build_preprocess_sandbox_params()
39
- artifacts = grading_utils.build_compile_grading_artifacts(dumped_problem, lang)
40
- if not steps.compile(preprocess_cmds, sandbox_params, box, artifacts):
41
- console.print(
42
- f'[error]Failed to preprocess problem [item]{dumped_problem.pretty_name()}[/item].[/error]'
43
- )
44
- return
45
-
46
- submit_file = PosixPath(lang.get_submit_file(dumped_problem.code))
47
- console.print(
48
- f'Problem to be submitted: [item]{dumped_problem.pretty_name()}[/item]'
49
- )
50
- console.print(f'Submission file: {submit_file.absolute()}')
51
-
52
- if not utils.confirm_on_status(
53
- None, 'Do you want to submit this problem?', default=False
54
- ):
55
- console.print('Skipping submission.')
56
- return
57
-
58
- if submitors.handle_submit(submit_file, dumped_problem, lang):
59
- console.print('[green]Submission successful.[/green]')
60
- else:
61
- console.print('[error]Submission failed.[/error]')