rbx.cp 0.5.11__tar.gz → 0.5.13__tar.gz
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.
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/PKG-INFO +1 -1
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/pyproject.toml +1 -1
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/builder.py +43 -13
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/cd.py +1 -2
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/checkers.py +25 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/compile.py +17 -23
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/contest/contest_package.py +7 -1
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/contest/main.py +26 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/contest/statements.py +8 -1
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/environment.py +12 -6
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/generators.py +8 -4
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/main.py +92 -15
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/package.py +7 -1
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/presets/__init__.py +12 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/solutions.py +33 -9
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/statements/build_statements.py +9 -1
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/stresses.py +2 -1
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/validators.py +41 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/steps.py +60 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/LICENSE +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/README.md +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/__init__.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/annotations.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/autoenum.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/__init__.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/code.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/conftest.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/contest/__init__.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/contest/build_contest_statements.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/contest/contest_utils.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/contest/schema.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/creation.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/download.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/extensions.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/generators_test.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/packaging/boca/extension.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/packaging/boca/packager.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/packaging/contest_main.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/packaging/main.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/packaging/packager.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/packaging/polygon/packager.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/packaging/polygon/test.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/packaging/polygon/xml_schema.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/presets/fetch.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/presets/lock_schema.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/presets/schema.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/schema.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/solutions_test.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/statements/__init__.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/statements/builders.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/statements/joiners.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/statements/latex.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/statements/latex_jinja.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/statements/schema.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/stressing/__init__.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/stressing/finder_parser.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/stressing/generator_parser.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/testcases.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/ui/__init__.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/ui/captured_log.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/ui/css/app.tcss +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/ui/main.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/ui/run.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/box/validators_test.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/checker.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/clone.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/config.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/conftest.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/console.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/create.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/edit.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/__init__.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/caching.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/conftest.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/judge/__init__.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/judge/cacher.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/judge/digester.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/judge/sandbox.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/judge/sandboxes/__init__.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/judge/sandboxes/isolate.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/judge/sandboxes/stupid_sandbox.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/judge/sandboxes/timeit.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/judge/storage.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/judge/test.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/judge/testiso.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/steps_with_caching.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading/steps_with_caching_run_test.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/grading_utils.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/hydration.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/main.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/metadata.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/providers/__init__.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/providers/codeforces.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/providers/provider.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/checkers/boilerplate.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/default_config.json +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/envs/default.rbx.yml +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/envs/isolate.rbx.yml +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/checker.sh +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/compare +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/compile/c +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/compile/cc +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/compile/cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/compile/java +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/compile/kt +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/compile/pas +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/compile/py2 +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/compile/py3 +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/run/c +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/run/cc +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/run/cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/run/java +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/run/kt +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/run/py2 +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/packagers/boca/run/py3 +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/contest/contest.rbx.yml +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/contest/statement/contest.rbx.tex +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/contest/statement/olymp.sty +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/contest/statement/template.rbx.tex +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/preset.rbx.yml +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/.gitignore +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/gen.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/problem.rbx.yml +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/random.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/random.txt +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/sols/main.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/sols/slow.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/sols/wa.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/statement/olymp.sty +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/statement/projecao.png +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/statement/statement.rbx.tex +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/statement/template.rbx.tex +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/tests/samples/000.in +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/tests/samples/001.in +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/validator.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/presets/default/problem/wcmp.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/resources/templates/template.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/run.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/schema.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/submit.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/submitors/__init__.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/submitors/codeforces.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/submitors/submitor.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/test.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testcase.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testcase_rendering.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/box1/gen1.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/box1/gen2.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/box1/genScript.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/box1/hard-tle.sol.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/box1/ole.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/box1/problem.rbx.yml +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/box1/re.sol.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/box1/sol.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/box1/tests/1.in +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/box1/tle-and-incorrect.sol.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/box1/tle.sol.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/box1/validator.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/box1/wa.sol.cpp +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/caching/executable.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testdata/compatible +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/testing_utils.py +0 -0
- {rbx_cp-0.5.11 → rbx_cp-0.5.13}/rbx/utils.py +0 -0
@@ -9,14 +9,23 @@ from rbx.box.solutions import (
|
|
9
9
|
print_run_report,
|
10
10
|
run_solutions,
|
11
11
|
)
|
12
|
-
from rbx.box.validators import
|
12
|
+
from rbx.box.validators import (
|
13
|
+
has_validation_errors,
|
14
|
+
print_validation_report,
|
15
|
+
validate_testcases,
|
16
|
+
)
|
13
17
|
|
14
18
|
|
15
19
|
def build(
|
16
20
|
verification: environment.VerificationParam,
|
17
21
|
groups: Optional[Set[str]] = None,
|
18
|
-
output: bool = True,
|
19
|
-
) ->
|
22
|
+
output: Optional[bool] = True,
|
23
|
+
) -> bool:
|
24
|
+
no_main_solution_report = False
|
25
|
+
if output is None:
|
26
|
+
output = package.get_main_solution() is not None
|
27
|
+
no_main_solution_report = not output
|
28
|
+
|
20
29
|
with utils.StatusProgress(
|
21
30
|
'Building testcases...',
|
22
31
|
'Built [item]{processed}[/item] testcases...',
|
@@ -24,6 +33,28 @@ def build(
|
|
24
33
|
) as s:
|
25
34
|
generate_testcases(s, groups=groups)
|
26
35
|
|
36
|
+
if verification > 0:
|
37
|
+
validator = package.get_validator_or_nil()
|
38
|
+
if validator is None:
|
39
|
+
console.console.print(
|
40
|
+
'[warning]No validator found, skipping validation.[/warning]'
|
41
|
+
)
|
42
|
+
|
43
|
+
if validator is not None:
|
44
|
+
with utils.StatusProgress(
|
45
|
+
'Validating testcases...',
|
46
|
+
'Validated [item]{processed}[/item] testcases...',
|
47
|
+
keep=True,
|
48
|
+
) as s:
|
49
|
+
infos = validate_testcases(s, groups=groups)
|
50
|
+
print_validation_report(infos)
|
51
|
+
|
52
|
+
if has_validation_errors(infos):
|
53
|
+
console.console.print(
|
54
|
+
'[error]Validation failed, check the report above.[/error]'
|
55
|
+
)
|
56
|
+
return False
|
57
|
+
|
27
58
|
with utils.StatusProgress(
|
28
59
|
'Building outputs for testcases...',
|
29
60
|
'Built [item]{processed}[/item] outputs...',
|
@@ -32,23 +63,22 @@ def build(
|
|
32
63
|
if output:
|
33
64
|
generate_outputs_for_testcases(s, groups=groups)
|
34
65
|
|
35
|
-
if verification > 0:
|
36
|
-
with utils.StatusProgress(
|
37
|
-
'Validating testcases...',
|
38
|
-
'Validated [item]{processed}[/item] testcases...',
|
39
|
-
keep=True,
|
40
|
-
) as s:
|
41
|
-
infos = validate_testcases(s, groups=groups)
|
42
|
-
print_validation_report(infos)
|
43
|
-
|
44
66
|
console.console.print(
|
45
67
|
'[success]Problem built.[/success] '
|
46
68
|
'[warning]Check the output for verification errors![/warning]'
|
47
69
|
)
|
48
70
|
|
71
|
+
if no_main_solution_report:
|
72
|
+
console.console.print(
|
73
|
+
'[warning]No main solution found, skipping generating samples for the statement.[/warning]'
|
74
|
+
)
|
75
|
+
|
76
|
+
return True
|
77
|
+
|
49
78
|
|
50
79
|
def verify(verification: environment.VerificationParam) -> bool:
|
51
|
-
build(verification=verification)
|
80
|
+
if not build(verification=verification):
|
81
|
+
return False
|
52
82
|
|
53
83
|
if verification < VerificationLevel.FAST_SOLUTIONS.value:
|
54
84
|
return True
|
@@ -119,6 +119,31 @@ def check(
|
|
119
119
|
)
|
120
120
|
message = package.get_digest_as_string(error.value or '') or ''
|
121
121
|
|
122
|
+
if (
|
123
|
+
checker_run_log is not None
|
124
|
+
and checker_run_log.exitcode != 0
|
125
|
+
and (
|
126
|
+
checker_run_log.exitstatus != SandboxBase.EXIT_NONZERO_RETURN
|
127
|
+
or checker_run_log.exitcode not in [0, 1, 2, 3]
|
128
|
+
)
|
129
|
+
):
|
130
|
+
console.console.print(
|
131
|
+
f'[error]Checker [item]{package.get_checker().path}[/item] failed unexpectedly.[/error]'
|
132
|
+
)
|
133
|
+
console.console.print(
|
134
|
+
f'[error]Summary:[/error] {checker_run_log.get_summary()}'
|
135
|
+
)
|
136
|
+
console.console.print(
|
137
|
+
f'[error]Testcase input:[/error] [item]{testcase.inputPath}[/item]'
|
138
|
+
)
|
139
|
+
console.console.print(
|
140
|
+
f'[error]Testcase output:[/error] [item]{testcase.outputPath}[/item]'
|
141
|
+
)
|
142
|
+
console.console.print(
|
143
|
+
f'[error]Program output:[/error] [item]{program_output}[/item]'
|
144
|
+
)
|
145
|
+
raise typer.Exit(1)
|
146
|
+
|
122
147
|
if checker_run_log is None or checker_run_log.exitcode not in [0, 1, 2, 3]:
|
123
148
|
return CheckerResult(outcome=Outcome.INTERNAL_ERROR)
|
124
149
|
|
@@ -22,35 +22,29 @@ def _compile(item: CodeItem):
|
|
22
22
|
out_path.chmod(0o755)
|
23
23
|
|
24
24
|
console.console.print(
|
25
|
-
f'[success]Compiled file written at [item]{out_path}[/item]
|
25
|
+
f'[success]Compiled file written at [item]{out_path}[/item][/success]'
|
26
26
|
)
|
27
27
|
|
28
28
|
|
29
|
-
@app.command('any, a', help='Compile an asset given its path.')
|
30
|
-
@package.within_problem
|
31
29
|
def any(path: str):
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
@app.command('solution, s', help='Compile a solution given its path.')
|
36
|
-
@package.within_problem
|
37
|
-
def solution(path: str):
|
38
|
-
_compile(package.get_solution(path))
|
30
|
+
pkg = package.find_problem_package_or_die()
|
39
31
|
|
32
|
+
solution = package.get_solution_or_nil(path)
|
33
|
+
if solution is not None:
|
34
|
+
_compile(solution)
|
35
|
+
return
|
40
36
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
37
|
+
for generator in pkg.generators:
|
38
|
+
if generator.path == pathlib.Path(path) or generator.name == path:
|
39
|
+
_compile(generator)
|
40
|
+
return
|
45
41
|
|
42
|
+
if pkg.checker is not None and pkg.checker.path == pathlib.Path(path):
|
43
|
+
_compile(pkg.checker)
|
44
|
+
return
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
_compile(package.get_checker())
|
46
|
+
if pkg.validator is not None and pkg.validator.path == pathlib.Path(path):
|
47
|
+
_compile(pkg.validator)
|
48
|
+
return
|
51
49
|
|
52
|
-
|
53
|
-
@app.command('validator, v', help='Compile the main validator.')
|
54
|
-
@package.within_problem
|
55
|
-
def validator():
|
56
|
-
_compile(package.get_validator())
|
50
|
+
_compile(CodeItem(path=pathlib.Path(path)))
|
@@ -3,6 +3,7 @@ import pathlib
|
|
3
3
|
from typing import List, Optional
|
4
4
|
|
5
5
|
import typer
|
6
|
+
from pydantic import ValidationError
|
6
7
|
|
7
8
|
from rbx import console, utils
|
8
9
|
from rbx.box.contest.schema import Contest
|
@@ -30,7 +31,12 @@ def find_contest_package(root: pathlib.Path = pathlib.Path()) -> Optional[Contes
|
|
30
31
|
contest_yaml_path = find_contest_yaml(root)
|
31
32
|
if not contest_yaml_path:
|
32
33
|
return None
|
33
|
-
|
34
|
+
try:
|
35
|
+
return utils.model_from_yaml(Contest, contest_yaml_path.read_text())
|
36
|
+
except ValidationError as e:
|
37
|
+
console.console.print(e)
|
38
|
+
console.console.print('[error]Error parsing contest.rbx.yml.[/error]')
|
39
|
+
raise typer.Exit(1) from e
|
34
40
|
|
35
41
|
|
36
42
|
def find_contest_package_or_die(root: pathlib.Path = pathlib.Path()) -> Contest:
|
@@ -160,6 +160,32 @@ def add(path: str, short_name: str, preset: Optional[str] = None):
|
|
160
160
|
)
|
161
161
|
|
162
162
|
|
163
|
+
@app.command('remove, r', help='Remove problem from contest.')
|
164
|
+
@within_contest
|
165
|
+
def remove(path_or_short_name: str):
|
166
|
+
contest = find_contest_package_or_die()
|
167
|
+
|
168
|
+
kept_problems = []
|
169
|
+
removed_problems = []
|
170
|
+
for problem in contest.problems:
|
171
|
+
if (
|
172
|
+
problem.path == pathlib.Path(path_or_short_name)
|
173
|
+
or problem.short_name == path_or_short_name
|
174
|
+
):
|
175
|
+
removed_problems.append(problem)
|
176
|
+
else:
|
177
|
+
kept_problems.append(problem)
|
178
|
+
|
179
|
+
contest.problems = kept_problems
|
180
|
+
save_contest(contest)
|
181
|
+
|
182
|
+
for problem in removed_problems:
|
183
|
+
shutil.rmtree(str(problem.path), ignore_errors=True)
|
184
|
+
console.console.print(
|
185
|
+
f'Problem [item]{problem.short_name}[/item] removed from contest at [item]{problem.path}[/item].'
|
186
|
+
)
|
187
|
+
|
188
|
+
|
163
189
|
@app.command(
|
164
190
|
'each',
|
165
191
|
help='Run a command for each problem in the contest.',
|
@@ -51,7 +51,14 @@ def build(
|
|
51
51
|
)
|
52
52
|
with utils.new_cd(problem.get_path()):
|
53
53
|
contest_utils.clear_package_cache()
|
54
|
-
|
54
|
+
|
55
|
+
if not builder.build(
|
56
|
+
verification=verification, groups=set(['samples']), output=None
|
57
|
+
):
|
58
|
+
console.console.print(
|
59
|
+
'[error]Failed to build statements with samples, aborting.[/error]'
|
60
|
+
)
|
61
|
+
raise typer.Exit(1)
|
55
62
|
|
56
63
|
contest = find_contest_package_or_die()
|
57
64
|
candidate_languages = languages
|
@@ -4,7 +4,7 @@ from enum import Enum
|
|
4
4
|
from typing import Annotated, List, Optional, Type, TypeVar
|
5
5
|
|
6
6
|
import typer
|
7
|
-
from pydantic import BaseModel, ConfigDict
|
7
|
+
from pydantic import BaseModel, ConfigDict, ValidationError
|
8
8
|
|
9
9
|
from rbx import config, console, utils
|
10
10
|
from rbx.box.extensions import Extensions, LanguageExtensions
|
@@ -19,9 +19,8 @@ class VerificationLevel(Enum):
|
|
19
19
|
NONE = 0
|
20
20
|
VALIDATE = 1
|
21
21
|
FAST_SOLUTIONS = 2
|
22
|
-
|
23
|
-
|
24
|
-
FULL = 5
|
22
|
+
ALL_SOLUTIONS = 3
|
23
|
+
FULL = 4
|
25
24
|
|
26
25
|
|
27
26
|
VerificationParam = Annotated[
|
@@ -31,7 +30,7 @@ VerificationParam = Annotated[
|
|
31
30
|
'--verification',
|
32
31
|
'-v',
|
33
32
|
help='Verification level to use when building package.',
|
34
|
-
default_factory=lambda: VerificationLevel.
|
33
|
+
default_factory=lambda: VerificationLevel.FULL.value,
|
35
34
|
),
|
36
35
|
]
|
37
36
|
|
@@ -193,7 +192,14 @@ def get_environment(env: Optional[str] = None) -> Environment:
|
|
193
192
|
f'Environment file [item]{env_path}[/item] not found.', style='error'
|
194
193
|
)
|
195
194
|
raise typer.Exit()
|
196
|
-
|
195
|
+
try:
|
196
|
+
return utils.model_from_yaml(Environment, env_path.read_text())
|
197
|
+
except ValidationError as e:
|
198
|
+
console.console.print(e)
|
199
|
+
console.console.print(
|
200
|
+
f'[error]Error parsing environment file [item]{env_path}[/item].[/error]'
|
201
|
+
)
|
202
|
+
raise typer.Exit(1) from e
|
197
203
|
|
198
204
|
|
199
205
|
@functools.cache
|
@@ -82,6 +82,8 @@ def _run_generator(
|
|
82
82
|
console.console.print(
|
83
83
|
f'[error]Failed generating test {i} from group path {group_path}[/error]',
|
84
84
|
)
|
85
|
+
if run_log is not None:
|
86
|
+
console.console.print(f'[error]Summary:[/error] {run_log.get_summary()}')
|
85
87
|
if generation_stderr.value is not None:
|
86
88
|
console.console.print('[error]Stderr:[/error]')
|
87
89
|
console.console.print(
|
@@ -142,9 +144,7 @@ def generate_output_for_testcase(
|
|
142
144
|
f'[error]Failed generating output for [item]{testcase.inputPath}[/item][/error]',
|
143
145
|
)
|
144
146
|
if run_log is not None:
|
145
|
-
console.console.print(
|
146
|
-
f'[error]Main solution exited with code [item]{-run_log.exitcode}[/item][/error]',
|
147
|
-
)
|
147
|
+
console.console.print(f'[error]Summary:[/error] {run_log.get_summary()}')
|
148
148
|
checker_result = checkers.check_with_no_output(run_log)
|
149
149
|
console.console.print(
|
150
150
|
f'[warning]Time: [item]{run_log.time:.2f}s[/item][/warning]',
|
@@ -238,7 +238,7 @@ def _run_generator_script(testcase: TestcaseSubgroup, cacher: FileCacher) -> str
|
|
238
238
|
)
|
239
239
|
if run_log is not None:
|
240
240
|
console.console.print(
|
241
|
-
f'[error]
|
241
|
+
f'[error]Summary:[/error] {run_log.get_summary()}'
|
242
242
|
)
|
243
243
|
if run_stderr.value is not None:
|
244
244
|
console.console.print('[error]Stderr:[/error]')
|
@@ -341,6 +341,10 @@ def generate_standalone(
|
|
341
341
|
console.console.print(
|
342
342
|
f'[error]Failed generating test using generator call [info]{call.name} {expanded_args_str}[/info].[/error]',
|
343
343
|
)
|
344
|
+
if generation_log is not None:
|
345
|
+
console.console.print(
|
346
|
+
f'[error]Summary:[/error] {generation_log.get_summary()}'
|
347
|
+
)
|
344
348
|
if generation_stderr.value is not None:
|
345
349
|
console.console.print('[error]Stderr:[/error]')
|
346
350
|
console.console.print(
|
@@ -3,11 +3,12 @@ from gevent import monkey
|
|
3
3
|
|
4
4
|
monkey.patch_all()
|
5
5
|
|
6
|
+
import tempfile
|
6
7
|
import shlex
|
7
8
|
import sys
|
8
9
|
import typing
|
9
10
|
|
10
|
-
from rbx.box.schema import CodeItem, ExpectedOutcome
|
11
|
+
from rbx.box.schema import CodeItem, ExpectedOutcome, TestcaseGroup
|
11
12
|
|
12
13
|
|
13
14
|
import pathlib
|
@@ -31,6 +32,7 @@ from rbx.box import (
|
|
31
32
|
compile,
|
32
33
|
presets,
|
33
34
|
stresses,
|
35
|
+
validators,
|
34
36
|
)
|
35
37
|
from rbx.box.contest import main as contest
|
36
38
|
from rbx.box.environment import VerificationLevel, get_environment_path
|
@@ -69,9 +71,6 @@ app.add_typer(
|
|
69
71
|
app.add_typer(
|
70
72
|
contest.app, name='contest', cls=annotations.AliasGroup, help='Contest management.'
|
71
73
|
)
|
72
|
-
app.add_typer(
|
73
|
-
compile.app, name='compile', cls=annotations.AliasGroup, help='Compile assets.'
|
74
|
-
)
|
75
74
|
|
76
75
|
|
77
76
|
@app.command('ui', hidden=True)
|
@@ -96,13 +95,6 @@ def build(verification: environment.VerificationParam):
|
|
96
95
|
builder.build(verification=verification)
|
97
96
|
|
98
97
|
|
99
|
-
@app.command('verify, v', help='Build and verify all the tests for the problem.')
|
100
|
-
@package.within_problem
|
101
|
-
def verify(verification: environment.VerificationParam):
|
102
|
-
if not builder.verify(verification=verification):
|
103
|
-
console.console.print('[error]Verification failed, check the report.[/error]')
|
104
|
-
|
105
|
-
|
106
98
|
@app.command('run, r', help='Build and run solution(s).')
|
107
99
|
@package.within_problem
|
108
100
|
def run(
|
@@ -139,7 +131,14 @@ def run(
|
|
139
131
|
)
|
140
132
|
check = False
|
141
133
|
|
142
|
-
builder.build(verification=verification, output=check)
|
134
|
+
if not builder.build(verification=verification, output=check):
|
135
|
+
return
|
136
|
+
|
137
|
+
if verification <= VerificationLevel.VALIDATE.value:
|
138
|
+
console.console.print(
|
139
|
+
'[warning]Verification level is set to [item]validate (-v1)[/item], so rbx only build tests and validated them.[/warning]'
|
140
|
+
)
|
141
|
+
return
|
143
142
|
|
144
143
|
with utils.StatusProgress('Running solutions...') as s:
|
145
144
|
tracked_solutions = None
|
@@ -206,6 +205,12 @@ def irun(
|
|
206
205
|
console.console.print(
|
207
206
|
'[warning]Outputs will be written to files. If you wish to print them to the terminal, use the "-p" parameter.'
|
208
207
|
)
|
208
|
+
if verification < VerificationLevel.ALL_SOLUTIONS.value:
|
209
|
+
console.console.print(
|
210
|
+
'[warning]Verification level should be at least [item]all solutions (-v4)[/item] to run solutions interactively.'
|
211
|
+
)
|
212
|
+
return
|
213
|
+
|
209
214
|
main_solution = package.get_main_solution()
|
210
215
|
if check and main_solution is None:
|
211
216
|
console.console.print(
|
@@ -248,7 +253,13 @@ def create(
|
|
248
253
|
@app.command('stress', help='Run a stress test.')
|
249
254
|
@package.within_problem
|
250
255
|
def stress(
|
251
|
-
name:
|
256
|
+
name: Annotated[
|
257
|
+
str,
|
258
|
+
typer.Argument(
|
259
|
+
help='Name of the stress test to run (specified in problem.rbx.yml), '
|
260
|
+
'or the generator to run, in case -g is specified.'
|
261
|
+
),
|
262
|
+
],
|
252
263
|
generator_args: Annotated[
|
253
264
|
Optional[str],
|
254
265
|
typer.Option(
|
@@ -325,9 +336,27 @@ def stress(
|
|
325
336
|
|
326
337
|
testgroup = questionary.select(
|
327
338
|
'Choose the testgroup to add the tests to.\nOnly test groups that have a .txt generatorScript are shown below: ',
|
328
|
-
choices=list(groups_by_name) + ['(skip)'],
|
339
|
+
choices=list(groups_by_name) + ['(create new script)', '(skip)'],
|
329
340
|
).ask()
|
330
341
|
|
342
|
+
if testgroup == '(create new script)':
|
343
|
+
new_script_name = questionary.text(
|
344
|
+
'Enter the name of the new .txt generatorScript file: '
|
345
|
+
).ask()
|
346
|
+
new_script_path = pathlib.Path(new_script_name).with_suffix('.txt')
|
347
|
+
new_script_path.parent.mkdir(parents=True, exist_ok=True)
|
348
|
+
new_script_path.touch()
|
349
|
+
|
350
|
+
# Temporarily create a new testgroup with the new script.
|
351
|
+
testgroup = new_script_path.stem
|
352
|
+
groups_by_name[testgroup] = TestcaseGroup(
|
353
|
+
name=testgroup, generatorScript=CodeItem(path=new_script_path)
|
354
|
+
)
|
355
|
+
console.console.print(
|
356
|
+
f'[warning]A testgroup for [item]{new_script_path}[/item] will not be automatically added to the problem.rbx.yml file for you.\n'
|
357
|
+
'Please add it manually. [/warning]'
|
358
|
+
)
|
359
|
+
|
331
360
|
if testgroup not in groups_by_name:
|
332
361
|
break
|
333
362
|
try:
|
@@ -355,6 +384,47 @@ def stress(
|
|
355
384
|
break
|
356
385
|
|
357
386
|
|
387
|
+
@app.command('compile', help='Compile an asset given its path.')
|
388
|
+
@package.within_problem
|
389
|
+
def compile_command(
|
390
|
+
path: Annotated[str, typer.Argument(help='Path to the asset to compile.')],
|
391
|
+
):
|
392
|
+
compile.any(path)
|
393
|
+
|
394
|
+
|
395
|
+
@app.command('validate', help='Run the validator in a one-off fashion, interactively.')
|
396
|
+
@package.within_problem
|
397
|
+
def validate(
|
398
|
+
path: Annotated[
|
399
|
+
Optional[str],
|
400
|
+
typer.Option('--path', '-p', help='Path to the testcase to validate.'),
|
401
|
+
] = None,
|
402
|
+
):
|
403
|
+
validator_tuple = validators.compile_main_validator()
|
404
|
+
if validator_tuple is None:
|
405
|
+
console.console.print('[error]No validator found for this problem.[/error]')
|
406
|
+
raise typer.Exit(1)
|
407
|
+
|
408
|
+
validator, validator_digest = validator_tuple
|
409
|
+
|
410
|
+
input = console.multiline_prompt('Testcase input')
|
411
|
+
|
412
|
+
if path is None:
|
413
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
414
|
+
tmppath = pathlib.Path(tmpdir) / '000.in'
|
415
|
+
tmppath.write_text(input)
|
416
|
+
|
417
|
+
info = validators.validate_one_off(
|
418
|
+
pathlib.Path(tmppath), validator, validator_digest
|
419
|
+
)
|
420
|
+
else:
|
421
|
+
info = validators.validate_one_off(
|
422
|
+
pathlib.Path(path), validator, validator_digest
|
423
|
+
)
|
424
|
+
|
425
|
+
validators.print_validation_report([info])
|
426
|
+
|
427
|
+
|
358
428
|
@app.command('environment, env', help='Set or show the current box environment.')
|
359
429
|
def environment_command(
|
360
430
|
env: Annotated[Optional[str], typer.Argument()] = None,
|
@@ -417,10 +487,17 @@ def activate():
|
|
417
487
|
console.console.print(
|
418
488
|
'[error]Preset is not installed. Install it manually, or specify a URI in [item].preset-lock.yml[/item].[/error]'
|
419
489
|
)
|
420
|
-
raise
|
490
|
+
raise typer.Exit(1)
|
421
491
|
presets.install(preset_lock.uri)
|
422
492
|
|
423
493
|
preset = presets.get_installed_preset(preset_lock.preset_name)
|
494
|
+
|
495
|
+
# Install the environment from the preset if it's not already installed.
|
496
|
+
presets.optionally_install_environment_from_preset(
|
497
|
+
preset, root=presets.get_preset_installation_path(preset_lock.name)
|
498
|
+
)
|
499
|
+
|
500
|
+
# Activate the environment.
|
424
501
|
if preset.env is not None:
|
425
502
|
environment_command(preset.name)
|
426
503
|
|
@@ -3,6 +3,7 @@ import pathlib
|
|
3
3
|
from typing import Dict, List, Optional, Tuple
|
4
4
|
|
5
5
|
import typer
|
6
|
+
from pydantic import ValidationError
|
6
7
|
|
7
8
|
from rbx import config, console, utils
|
8
9
|
from rbx.box import environment
|
@@ -74,7 +75,12 @@ def find_problem_package(root: pathlib.Path = pathlib.Path()) -> Optional[Packag
|
|
74
75
|
problem_yaml_path = find_problem_yaml(root)
|
75
76
|
if not problem_yaml_path:
|
76
77
|
return None
|
77
|
-
|
78
|
+
try:
|
79
|
+
return utils.model_from_yaml(Package, problem_yaml_path.read_text())
|
80
|
+
except ValidationError as e:
|
81
|
+
console.console.print(e)
|
82
|
+
console.console.print('[error]Error parsing problem.rbx.yml.[/error]')
|
83
|
+
raise typer.Exit(1) from e
|
78
84
|
|
79
85
|
|
80
86
|
def find_problem_package_or_die(root: pathlib.Path = pathlib.Path()) -> Package:
|
@@ -294,6 +294,18 @@ def get_installed_preset(name: str, root: pathlib.Path = pathlib.Path()) -> Pres
|
|
294
294
|
return preset
|
295
295
|
|
296
296
|
|
297
|
+
def optionally_install_environment_from_preset(
|
298
|
+
preset: Preset, root: pathlib.Path = pathlib.Path()
|
299
|
+
):
|
300
|
+
if preset.env is None:
|
301
|
+
return
|
302
|
+
env_path = get_environment_path(preset.name)
|
303
|
+
if env_path.is_file():
|
304
|
+
return
|
305
|
+
env_path.parent.mkdir(parents=True, exist_ok=True)
|
306
|
+
shutil.copyfile(str(root / preset.env), env_path)
|
307
|
+
|
308
|
+
|
297
309
|
def _install(root: pathlib.Path = pathlib.Path(), force: bool = False):
|
298
310
|
preset = get_preset_yaml(root)
|
299
311
|
|
@@ -378,6 +378,7 @@ def _run_interactive_solutions(
|
|
378
378
|
shutil.rmtree(str(irun_dir), ignore_errors=True)
|
379
379
|
irun_dir.mkdir(parents=True, exist_ok=True)
|
380
380
|
inputs_dir = irun_dir / 'inputs'
|
381
|
+
inputs_dir.mkdir(parents=True, exist_ok=True)
|
381
382
|
input_path = inputs_dir / '000.in'
|
382
383
|
output_path = input_path.with_suffix('.out')
|
383
384
|
|
@@ -479,10 +480,14 @@ def get_testcase_markup_verdict(eval: Evaluation) -> str:
|
|
479
480
|
|
480
481
|
|
481
482
|
def _get_evals_time_in_ms(evals: List[Evaluation]) -> int:
|
483
|
+
if not evals:
|
484
|
+
return 0
|
482
485
|
return max(int((eval.log.time or 0.0) * 1000) for eval in evals)
|
483
486
|
|
484
487
|
|
485
488
|
def _get_evals_memory_in_mb(evals: List[Evaluation]) -> int:
|
489
|
+
if not evals:
|
490
|
+
return 0
|
486
491
|
return max(int(eval.log.memory or 0) // (1024 * 1024) for eval in evals)
|
487
492
|
|
488
493
|
|
@@ -504,6 +509,7 @@ def _print_solution_outcome(
|
|
504
509
|
) -> bool:
|
505
510
|
pkg = package.find_problem_package_or_die()
|
506
511
|
|
512
|
+
has_plain_tle = False
|
507
513
|
bad_verdicts = set()
|
508
514
|
no_tle_bad_verdicts = set()
|
509
515
|
for eval in evals:
|
@@ -514,6 +520,10 @@ def _print_solution_outcome(
|
|
514
520
|
and eval.result.no_tle_outcome != Outcome.ACCEPTED
|
515
521
|
):
|
516
522
|
no_tle_bad_verdicts.add(eval.result.no_tle_outcome)
|
523
|
+
has_plain_tle = has_plain_tle or (
|
524
|
+
eval.result.outcome == Outcome.TIME_LIMIT_EXCEEDED
|
525
|
+
and eval.result.no_tle_outcome is None
|
526
|
+
)
|
517
527
|
|
518
528
|
unmatched_bad_verdicts = set(
|
519
529
|
v for v in bad_verdicts if not solution.outcome.match(v)
|
@@ -542,16 +552,27 @@ def _print_solution_outcome(
|
|
542
552
|
verification.value >= VerificationLevel.FULL.value
|
543
553
|
# Solution expects a TLE.
|
544
554
|
and expected_outcome_is_tle
|
545
|
-
#
|
546
|
-
and
|
547
|
-
#
|
548
|
-
and
|
549
|
-
# The solution
|
555
|
+
# Solution does not have a plain TLE.
|
556
|
+
and not has_plain_tle
|
557
|
+
# A TLE has happened.
|
558
|
+
and Outcome.TIME_LIMIT_EXCEEDED in matched_bad_verdicts
|
559
|
+
# The solution runs in double TL.
|
550
560
|
and evals_time < pkg.timelimit_for_language(solution.language) * 2
|
551
561
|
):
|
552
|
-
|
553
|
-
|
554
|
-
|
562
|
+
other_verdicts = (bad_verdicts | no_tle_bad_verdicts) - {
|
563
|
+
Outcome.TIME_LIMIT_EXCEEDED
|
564
|
+
}
|
565
|
+
if not other_verdicts:
|
566
|
+
# The solution has no other bad verdicts except for TLEs in double TL.
|
567
|
+
console.print(
|
568
|
+
'[yellow]WARNING[/yellow] The solution still passed in double TL.'
|
569
|
+
)
|
570
|
+
elif not (bad_verdicts - {Outcome.TIME_LIMIT_EXCEEDED}):
|
571
|
+
# The solution has other bad soft TLE outcomes.
|
572
|
+
other_verdicts_names = ' '.join(v.name for v in other_verdicts)
|
573
|
+
console.print(
|
574
|
+
f'[yellow]WARNING[/yellow] The solution could still run under double TL, but failed with [item]{other_verdicts_names}[/item].'
|
575
|
+
)
|
555
576
|
console.print(f'Time: {get_evals_formatted_time(evals)}')
|
556
577
|
console.print(f'Memory: {get_evals_formatted_memory(evals)}')
|
557
578
|
return len(unmatched_bad_verdicts) == 0
|
@@ -787,6 +808,9 @@ def print_run_report(
|
|
787
808
|
print_last_solution()
|
788
809
|
|
789
810
|
items.seek(0)
|
790
|
-
|
811
|
+
structured_evaluations_list = list(structured_evaluations)
|
812
|
+
|
813
|
+
if structured_evaluations_list:
|
814
|
+
_print_timing(console, result.skeleton, structured_evaluations_list[-1])
|
791
815
|
|
792
816
|
return ok
|