rbx.cp 0.5.15__tar.gz → 0.5.17__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.15 → rbx_cp-0.5.17}/PKG-INFO +1 -1
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/pyproject.toml +1 -1
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/builder.py +2 -2
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/cd.py +12 -2
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/checkers.py +38 -4
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/code.py +126 -18
- rbx_cp-0.5.17/rbx/box/compile.py +82 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/contest/build_contest_statements.py +5 -3
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/contest/contest_package.py +2 -1
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/contest/main.py +2 -2
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/contest/statements.py +3 -3
- rbx_cp-0.5.17/rbx/box/deferred.py +26 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/extensions.py +0 -8
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/generators.py +7 -8
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/main.py +185 -16
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/package.py +2 -2
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/packaging/contest_main.py +3 -3
- rbx_cp-0.5.17/rbx/box/sanitizers/warning_stack.py +90 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/schema.py +15 -1
- rbx_cp-0.5.17/rbx/box/setter_config.py +132 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/solutions.py +237 -149
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/solutions_test.py +2 -1
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/stresses.py +5 -3
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/validators.py +5 -5
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/config.py +3 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/caching.py +4 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/judge/sandboxes/stupid_sandbox.py +2 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/steps.py +125 -15
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/steps_with_caching.py +2 -0
- rbx_cp-0.5.17/rbx/resources/default_setter_config.mac.yml +31 -0
- rbx_cp-0.5.17/rbx/resources/default_setter_config.yml +29 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/utils.py +1 -1
- rbx_cp-0.5.15/rbx/box/compile.py +0 -50
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/LICENSE +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/README.md +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/__init__.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/annotations.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/autoenum.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/__init__.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/conftest.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/contest/__init__.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/contest/contest_utils.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/contest/schema.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/creation.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/download.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/environment.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/generators_test.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/packaging/boca/extension.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/packaging/boca/packager.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/packaging/main.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/packaging/packager.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/packaging/polygon/packager.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/packaging/polygon/test.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/packaging/polygon/xml_schema.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/presets/__init__.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/presets/fetch.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/presets/lock_schema.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/presets/schema.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/statements/__init__.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/statements/build_statements.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/statements/builders.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/statements/joiners.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/statements/latex.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/statements/latex_jinja.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/statements/schema.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/stressing/__init__.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/stressing/finder_parser.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/stressing/generator_parser.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/testcases.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/ui/__init__.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/ui/captured_log.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/ui/css/app.tcss +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/ui/main.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/ui/run.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/box/validators_test.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/checker.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/clone.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/conftest.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/console.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/create.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/edit.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/__init__.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/conftest.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/judge/__init__.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/judge/cacher.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/judge/digester.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/judge/sandbox.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/judge/sandboxes/__init__.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/judge/sandboxes/isolate.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/judge/sandboxes/timeit.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/judge/storage.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/judge/test.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/judge/testiso.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading/steps_with_caching_run_test.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/grading_utils.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/hydration.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/main.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/metadata.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/providers/__init__.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/providers/codeforces.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/providers/provider.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/checkers/boilerplate.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/default_config.json +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/envs/default.rbx.yml +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/envs/isolate.rbx.yml +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/checker.sh +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/compare +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/compile/c +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/compile/cc +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/compile/cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/compile/java +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/compile/kt +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/compile/pas +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/compile/py2 +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/compile/py3 +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/run/c +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/run/cc +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/run/cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/run/java +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/run/kt +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/run/py2 +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/packagers/boca/run/py3 +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/contest/contest.rbx.yml +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/contest/statement/contest.rbx.tex +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/contest/statement/olymp.sty +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/contest/statement/template.rbx.tex +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/preset.rbx.yml +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/.gitignore +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/gen.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/problem.rbx.yml +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/random.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/random.txt +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/sols/main.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/sols/slow.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/sols/wa.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/statement/olymp.sty +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/statement/projecao.png +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/statement/statement.rbx.tex +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/statement/template.rbx.tex +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/tests/samples/000.in +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/tests/samples/001.in +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/validator.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/presets/default/problem/wcmp.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/resources/templates/template.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/run.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/schema.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/submit.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/submitors/__init__.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/submitors/codeforces.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/submitors/submitor.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/test.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testcase.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testcase_rendering.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/box1/gen1.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/box1/gen2.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/box1/genScript.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/box1/hard-tle.sol.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/box1/ole.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/box1/problem.rbx.yml +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/box1/re.sol.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/box1/sol.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/box1/tests/1.in +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/box1/tle-and-incorrect.sol.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/box1/tle.sol.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/box1/validator.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/box1/wa.sol.cpp +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/caching/executable.py +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testdata/compatible +0 -0
- {rbx_cp-0.5.15 → rbx_cp-0.5.17}/rbx/testing_utils.py +0 -0
@@ -76,7 +76,7 @@ def build(
|
|
76
76
|
return True
|
77
77
|
|
78
78
|
|
79
|
-
def verify(verification: environment.VerificationParam) -> bool:
|
79
|
+
async def verify(verification: environment.VerificationParam) -> bool:
|
80
80
|
if not build(verification=verification):
|
81
81
|
return False
|
82
82
|
|
@@ -100,7 +100,7 @@ def verify(verification: environment.VerificationParam) -> bool:
|
|
100
100
|
|
101
101
|
console.console.print()
|
102
102
|
console.console.rule('[status]Run report[/status]', style='status')
|
103
|
-
return print_run_report(
|
103
|
+
return await print_run_report(
|
104
104
|
solution_result,
|
105
105
|
console.console,
|
106
106
|
verification,
|
@@ -1,10 +1,13 @@
|
|
1
|
+
import contextlib
|
1
2
|
import functools
|
2
3
|
import pathlib
|
3
4
|
from typing import Optional
|
4
5
|
|
5
6
|
import typer
|
6
7
|
|
7
|
-
from rbx import console
|
8
|
+
from rbx import console
|
9
|
+
from rbx.box.sanitizers import warning_stack
|
10
|
+
from rbx.utils import new_cd
|
8
11
|
|
9
12
|
|
10
13
|
def find_package(root: pathlib.Path = pathlib.Path()) -> Optional[pathlib.Path]:
|
@@ -30,7 +33,14 @@ def within_closest_package(func):
|
|
30
33
|
console.console.print('[error]No rbx package found.[/error]')
|
31
34
|
raise typer.Exit(1)
|
32
35
|
# Get deepest package.
|
33
|
-
with
|
36
|
+
with new_package_cd(package):
|
34
37
|
return func(*args, **kwargs)
|
35
38
|
|
36
39
|
return wrapper
|
40
|
+
|
41
|
+
|
42
|
+
@contextlib.contextmanager
|
43
|
+
def new_package_cd(x: pathlib.Path):
|
44
|
+
with new_cd(x):
|
45
|
+
yield
|
46
|
+
warning_stack.print_warning_stack_report()
|
@@ -5,7 +5,7 @@ import typer
|
|
5
5
|
|
6
6
|
from rbx import console
|
7
7
|
from rbx.box import package
|
8
|
-
from rbx.box.code import compile_item, run_item
|
8
|
+
from rbx.box.code import SanitizationLevel, compile_item, run_item
|
9
9
|
from rbx.box.schema import Testcase
|
10
10
|
from rbx.grading.judge.sandbox import SandboxBase
|
11
11
|
from rbx.grading.steps import (
|
@@ -23,7 +23,7 @@ def compile_checker() -> str:
|
|
23
23
|
checker = package.get_checker()
|
24
24
|
|
25
25
|
try:
|
26
|
-
digest = compile_item(checker)
|
26
|
+
digest = compile_item(checker, sanitized=SanitizationLevel.PREFER)
|
27
27
|
except Exception as e:
|
28
28
|
console.console.print('[error]Failed compiling checker.[/error]')
|
29
29
|
raise typer.Exit(1) from e
|
@@ -33,11 +33,21 @@ def compile_checker() -> str:
|
|
33
33
|
def _check_pre_output(run_log: Optional[RunLog]) -> CheckerResult:
|
34
34
|
pkg = package.find_problem_package_or_die()
|
35
35
|
|
36
|
+
is_sanitized = (
|
37
|
+
run_log is not None
|
38
|
+
and run_log.metadata is not None
|
39
|
+
and run_log.metadata.is_sanitized
|
40
|
+
)
|
41
|
+
|
36
42
|
if run_log is None:
|
37
43
|
return CheckerResult(outcome=Outcome.INTERNAL_ERROR)
|
38
44
|
|
39
45
|
timelimit = pkg.timelimit_for_language(run_log.get_run_language())
|
40
|
-
if
|
46
|
+
if (
|
47
|
+
run_log.time is not None
|
48
|
+
and run_log.time * 1000 > timelimit * 2
|
49
|
+
and not is_sanitized
|
50
|
+
):
|
41
51
|
return CheckerResult(outcome=Outcome.TIME_LIMIT_EXCEEDED)
|
42
52
|
|
43
53
|
if run_log.exitstatus in [SandboxBase.EXIT_SIGNAL, SandboxBase.EXIT_NONZERO_RETURN]:
|
@@ -58,11 +68,17 @@ def _convert_tle(result: CheckerResult, run_log: Optional[RunLog]) -> CheckerRes
|
|
58
68
|
# This already is a TLE outcome.
|
59
69
|
return result
|
60
70
|
pkg = package.find_problem_package_or_die()
|
71
|
+
is_sanitized = (
|
72
|
+
run_log is not None
|
73
|
+
and run_log.metadata is not None
|
74
|
+
and run_log.metadata.is_sanitized
|
75
|
+
)
|
61
76
|
if (
|
62
77
|
run_log is not None
|
63
78
|
and run_log.time is not None
|
64
79
|
and run_log.time * 1000
|
65
80
|
>= pkg.timelimit_for_language(run_log.get_run_language())
|
81
|
+
and not is_sanitized
|
66
82
|
):
|
67
83
|
# Soft TLE.
|
68
84
|
result.no_tle_outcome = result.outcome
|
@@ -75,7 +91,7 @@ def check_with_no_output(run_log: Optional[RunLog]) -> CheckerResult:
|
|
75
91
|
return _convert_tle(result, run_log)
|
76
92
|
|
77
93
|
|
78
|
-
def
|
94
|
+
def _check(
|
79
95
|
checker_digest: str,
|
80
96
|
run_log: Optional[RunLog],
|
81
97
|
testcase: Testcase,
|
@@ -157,3 +173,21 @@ def check(
|
|
157
173
|
if skip_run_log:
|
158
174
|
return result
|
159
175
|
return _convert_tle(result, run_log)
|
176
|
+
|
177
|
+
|
178
|
+
def _check_sanitizer_warnings(run_log: Optional[RunLog]) -> bool:
|
179
|
+
if run_log is None:
|
180
|
+
return False
|
181
|
+
return run_log.warnings
|
182
|
+
|
183
|
+
|
184
|
+
def check(
|
185
|
+
checker_digest: str,
|
186
|
+
run_log: Optional[RunLog],
|
187
|
+
testcase: Testcase,
|
188
|
+
program_output: pathlib.Path,
|
189
|
+
skip_run_log: bool = False,
|
190
|
+
) -> CheckerResult:
|
191
|
+
result = _check(checker_digest, run_log, testcase, program_output, skip_run_log)
|
192
|
+
result.sanitizer_warnings = _check_sanitizer_warnings(run_log)
|
193
|
+
return result
|
@@ -1,17 +1,19 @@
|
|
1
1
|
import pathlib
|
2
2
|
import shlex
|
3
|
-
import
|
3
|
+
from enum import Enum
|
4
4
|
from pathlib import PosixPath
|
5
5
|
from typing import List, Optional
|
6
6
|
|
7
|
+
import rich
|
8
|
+
import rich.text
|
7
9
|
import typer
|
8
10
|
|
9
|
-
from rbx
|
11
|
+
from rbx import console
|
12
|
+
from rbx.box import download, package, setter_config
|
10
13
|
from rbx.box.environment import (
|
11
14
|
ExecutionConfig,
|
12
15
|
get_compilation_config,
|
13
16
|
get_execution_config,
|
14
|
-
get_extension_or_default,
|
15
17
|
get_file_mapping,
|
16
18
|
get_language,
|
17
19
|
get_mapped_command,
|
@@ -19,7 +21,7 @@ from rbx.box.environment import (
|
|
19
21
|
get_sandbox_params_from_config,
|
20
22
|
merge_execution_configs,
|
21
23
|
)
|
22
|
-
from rbx.box.
|
24
|
+
from rbx.box.sanitizers import warning_stack
|
23
25
|
from rbx.box.schema import CodeItem
|
24
26
|
from rbx.grading import steps_with_caching
|
25
27
|
from rbx.grading.steps import (
|
@@ -31,17 +33,25 @@ from rbx.grading.steps import (
|
|
31
33
|
GradingFileOutput,
|
32
34
|
RunLog,
|
33
35
|
RunLogMetadata,
|
36
|
+
is_cxx_command,
|
34
37
|
)
|
35
38
|
|
36
39
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
return command
|
42
|
-
return command.replace('g++', extension.gpp_alternative)
|
40
|
+
class SanitizationLevel(Enum):
|
41
|
+
NONE = 0
|
42
|
+
PREFER = 1
|
43
|
+
FORCE = 2
|
43
44
|
|
44
|
-
|
45
|
+
def should_sanitize(self) -> bool:
|
46
|
+
cfg = setter_config.get_setter_config()
|
47
|
+
if cfg.sanitizers.enabled:
|
48
|
+
return self.value >= SanitizationLevel.PREFER.value
|
49
|
+
return self.value >= SanitizationLevel.FORCE.value
|
50
|
+
|
51
|
+
|
52
|
+
def substitute_commands(commands: List[str], sanitized: bool = False) -> List[str]:
|
53
|
+
cfg = setter_config.get_setter_config()
|
54
|
+
return [cfg.substitute_command(command, sanitized) for command in commands]
|
45
55
|
|
46
56
|
|
47
57
|
def get_extension(code: CodeItem) -> str:
|
@@ -55,8 +65,46 @@ def find_language_name(code: CodeItem) -> str:
|
|
55
65
|
return get_language(get_extension(code)).name
|
56
66
|
|
57
67
|
|
68
|
+
def is_executable_sanitized(executable: DigestOrSource) -> bool:
|
69
|
+
if executable.digest is None:
|
70
|
+
return False
|
71
|
+
storage = package.get_cache_storage()
|
72
|
+
return storage.exists(f'{executable.digest.value}.san')
|
73
|
+
|
74
|
+
|
75
|
+
def add_sanitizer_flags_to_command(command: str) -> str:
|
76
|
+
if is_cxx_command(command):
|
77
|
+
return command + ' -fsanitize=address,undefined -fno-omit-frame-pointer'
|
78
|
+
return command
|
79
|
+
|
80
|
+
|
81
|
+
def add_sanitizer_flags(commands: List[str]) -> List[str]:
|
82
|
+
return [add_sanitizer_flags_to_command(command) for command in commands]
|
83
|
+
|
84
|
+
|
85
|
+
def add_warning_flags_to_command(command: str) -> str:
|
86
|
+
if is_cxx_command(command):
|
87
|
+
return (
|
88
|
+
command
|
89
|
+
+ ' -Wall -Wshadow -Wno-unused-result -Wno-sign-compare -Wno-char-subscripts'
|
90
|
+
)
|
91
|
+
return command
|
92
|
+
|
93
|
+
|
94
|
+
def add_warning_flags(commands: List[str], force_warnings: bool) -> List[str]:
|
95
|
+
cfg = setter_config.get_setter_config()
|
96
|
+
if cfg.warnings.enabled or force_warnings:
|
97
|
+
return [add_warning_flags_to_command(command) for command in commands]
|
98
|
+
return commands
|
99
|
+
|
100
|
+
|
58
101
|
# Compile code item and return its digest in the storage.
|
59
|
-
def compile_item(
|
102
|
+
def compile_item(
|
103
|
+
code: CodeItem,
|
104
|
+
sanitized: SanitizationLevel = SanitizationLevel.PREFER,
|
105
|
+
force_warnings: bool = False,
|
106
|
+
verbose: bool = False,
|
107
|
+
) -> str:
|
60
108
|
generator_path = PosixPath(code.path)
|
61
109
|
language = find_language_name(code)
|
62
110
|
compilation_options = get_compilation_config(language)
|
@@ -69,10 +117,12 @@ def compile_item(code: CodeItem) -> str:
|
|
69
117
|
# Language is not compiled.
|
70
118
|
return sandbox.file_cacher.put_file_from_path(generator_path)
|
71
119
|
|
72
|
-
# Compile the generator
|
73
120
|
commands = get_mapped_commands(compilation_options.commands, file_mapping)
|
74
|
-
|
75
|
-
|
121
|
+
commands = add_warning_flags(commands, force_warnings)
|
122
|
+
commands = substitute_commands(commands, sanitized=sanitized.should_sanitize())
|
123
|
+
|
124
|
+
if sanitized.should_sanitize():
|
125
|
+
commands = add_sanitizer_flags(commands)
|
76
126
|
|
77
127
|
compiled_digest = DigestHolder()
|
78
128
|
|
@@ -104,6 +154,33 @@ def compile_item(code: CodeItem) -> str:
|
|
104
154
|
raise typer.Exit(1)
|
105
155
|
|
106
156
|
assert compiled_digest.value is not None
|
157
|
+
|
158
|
+
if verbose and artifacts.logs is not None and artifacts.logs.preprocess is not None:
|
159
|
+
for log in artifacts.logs.preprocess:
|
160
|
+
console.console.print(f'[status]Command:[/status] {log.get_command()}')
|
161
|
+
console.console.print(f'[status]Summary:[/status] {log.get_summary()}')
|
162
|
+
console.console.print(rich.text.Text.from_ansi(log.log), style='default')
|
163
|
+
|
164
|
+
# Write compiler warnings.
|
165
|
+
cfg = setter_config.get_setter_config()
|
166
|
+
if (
|
167
|
+
(cfg.warnings.enabled or force_warnings)
|
168
|
+
and artifacts.logs is not None
|
169
|
+
and artifacts.logs.preprocess is not None
|
170
|
+
):
|
171
|
+
any_warning = any(log.warnings for log in artifacts.logs.preprocess)
|
172
|
+
if any_warning:
|
173
|
+
warning_stack.get_warning_stack().add_warning(code)
|
174
|
+
|
175
|
+
# Create sentinel to indicate this executable is sanitized.
|
176
|
+
storage = package.get_cache_storage()
|
177
|
+
if sanitized.should_sanitize():
|
178
|
+
pf = storage.create_file(f'{compiled_digest.value}.san')
|
179
|
+
if pf is not None:
|
180
|
+
storage.commit_file(pf)
|
181
|
+
elif storage.exists(f'{compiled_digest.value}.san'):
|
182
|
+
storage.delete(f'{compiled_digest.value}.san')
|
183
|
+
|
107
184
|
return compiled_digest.value
|
108
185
|
|
109
186
|
|
@@ -127,14 +204,35 @@ def run_item(
|
|
127
204
|
sandbox = package.get_singleton_sandbox()
|
128
205
|
sandbox_params = get_sandbox_params_from_config(execution_options.sandbox)
|
129
206
|
|
207
|
+
# Sanitization parameters.
|
208
|
+
sanitized = False
|
209
|
+
if is_executable_sanitized(executable):
|
210
|
+
# Remove any memory constraints for a sanitized executable.
|
211
|
+
# Sanitizers are known to be memory-hungry.
|
212
|
+
sandbox_params.address_space = None
|
213
|
+
|
214
|
+
# Reset timeout configs since sanitizers are known to be time-hungry.
|
215
|
+
sandbox_params.timeout = None
|
216
|
+
sandbox_params.wallclock_timeout = None
|
217
|
+
orig_execution_config = get_execution_config(language)
|
218
|
+
if orig_execution_config.sandbox is not None:
|
219
|
+
sandbox_params.timeout = orig_execution_config.sandbox.timeLimit
|
220
|
+
sandbox_params.wallclock_timeout = (
|
221
|
+
orig_execution_config.sandbox.wallTimeLimit
|
222
|
+
)
|
223
|
+
sanitized = True
|
224
|
+
|
130
225
|
sandbox_params.set_stdall(
|
131
226
|
stdin=PosixPath(file_mapping.input) if stdin is not None else None,
|
132
227
|
stdout=PosixPath(file_mapping.output) if stdout is not None else None,
|
133
|
-
stderr=PosixPath(file_mapping.error)
|
228
|
+
stderr=PosixPath(file_mapping.error)
|
229
|
+
if stderr is not None or sanitized
|
230
|
+
else None,
|
134
231
|
)
|
135
232
|
|
136
233
|
assert execution_options.command
|
137
234
|
command = get_mapped_command(execution_options.command, file_mapping)
|
235
|
+
command = substitute_commands([command], sanitized=sanitized)[0]
|
138
236
|
|
139
237
|
if extra_args is not None:
|
140
238
|
splitted_command = shlex.split(command)
|
@@ -175,11 +273,21 @@ def run_item(
|
|
175
273
|
if outputs:
|
176
274
|
artifacts.outputs.extend(outputs)
|
177
275
|
|
178
|
-
|
276
|
+
run_log = steps_with_caching.run(
|
179
277
|
command,
|
180
278
|
params=sandbox_params,
|
181
279
|
sandbox=sandbox,
|
182
280
|
artifacts=artifacts,
|
183
281
|
dependency_cache=dependency_cache,
|
184
|
-
metadata=RunLogMetadata(language=code.language),
|
282
|
+
metadata=RunLogMetadata(language=code.language, is_sanitized=sanitized),
|
185
283
|
)
|
284
|
+
|
285
|
+
# Find sanitizer logs.
|
286
|
+
if run_log is not None and run_log.warnings:
|
287
|
+
assert sandbox_params.stderr_file is not None
|
288
|
+
stderr_output = artifacts.get_output_file_for_src(sandbox_params.stderr_file)
|
289
|
+
if stderr_output is not None:
|
290
|
+
warning_stack.get_warning_stack().add_sanitizer_warning(
|
291
|
+
package.get_cache_storage(), code, stderr_output
|
292
|
+
)
|
293
|
+
return run_log
|
@@ -0,0 +1,82 @@
|
|
1
|
+
import pathlib
|
2
|
+
|
3
|
+
import typer
|
4
|
+
|
5
|
+
from rbx import annotations, console
|
6
|
+
from rbx.box import code, package
|
7
|
+
from rbx.box.code import SanitizationLevel
|
8
|
+
from rbx.box.sanitizers import warning_stack
|
9
|
+
from rbx.box.schema import CodeItem
|
10
|
+
|
11
|
+
app = typer.Typer(no_args_is_help=True, cls=annotations.AliasGroup)
|
12
|
+
|
13
|
+
|
14
|
+
def _compile_out():
|
15
|
+
return package.get_build_path() / 'exe'
|
16
|
+
|
17
|
+
|
18
|
+
def _compile(item: CodeItem, sanitized: SanitizationLevel, warnings: bool):
|
19
|
+
console.console.print(f'Compiling [item]{item.path}[/item]...')
|
20
|
+
digest = code.compile_item(item, sanitized, force_warnings=warnings, verbose=True)
|
21
|
+
cacher = package.get_file_cacher()
|
22
|
+
out_path = _compile_out()
|
23
|
+
cacher.get_file_to_path(digest, out_path)
|
24
|
+
out_path.chmod(0o755)
|
25
|
+
|
26
|
+
# Clear the warning stack as we don't really worry about it when running
|
27
|
+
# `rbx compile`.
|
28
|
+
warning_stack.get_warning_stack().clear()
|
29
|
+
|
30
|
+
console.console.print(
|
31
|
+
f'[success]Compiled file written at [item]{out_path}[/item][/success]'
|
32
|
+
)
|
33
|
+
|
34
|
+
|
35
|
+
def any(path: str, sanitized: bool = False, warnings: bool = False):
|
36
|
+
pkg = package.find_problem_package_or_die()
|
37
|
+
|
38
|
+
solution = package.get_solution_or_nil(path)
|
39
|
+
if solution is not None:
|
40
|
+
_compile(
|
41
|
+
solution,
|
42
|
+
sanitized=SanitizationLevel.FORCE if sanitized else SanitizationLevel.NONE,
|
43
|
+
warnings=warnings,
|
44
|
+
)
|
45
|
+
return
|
46
|
+
|
47
|
+
for generator in pkg.generators:
|
48
|
+
if generator.path == pathlib.Path(path) or generator.name == path:
|
49
|
+
_compile(
|
50
|
+
generator,
|
51
|
+
sanitized=SanitizationLevel.FORCE
|
52
|
+
if sanitized
|
53
|
+
else SanitizationLevel.PREFER,
|
54
|
+
warnings=warnings,
|
55
|
+
)
|
56
|
+
return
|
57
|
+
|
58
|
+
if pkg.checker is not None and pkg.checker.path == pathlib.Path(path):
|
59
|
+
_compile(
|
60
|
+
pkg.checker,
|
61
|
+
sanitized=SanitizationLevel.FORCE
|
62
|
+
if sanitized
|
63
|
+
else SanitizationLevel.PREFER,
|
64
|
+
warnings=warnings,
|
65
|
+
)
|
66
|
+
return
|
67
|
+
|
68
|
+
if pkg.validator is not None and pkg.validator.path == pathlib.Path(path):
|
69
|
+
_compile(
|
70
|
+
pkg.validator,
|
71
|
+
sanitized=SanitizationLevel.FORCE
|
72
|
+
if sanitized
|
73
|
+
else SanitizationLevel.PREFER,
|
74
|
+
warnings=warnings,
|
75
|
+
)
|
76
|
+
return
|
77
|
+
|
78
|
+
_compile(
|
79
|
+
CodeItem(path=pathlib.Path(path)),
|
80
|
+
sanitized=SanitizationLevel.FORCE if sanitized else SanitizationLevel.NONE,
|
81
|
+
warnings=warnings,
|
82
|
+
)
|
@@ -6,7 +6,8 @@ from typing import List, Optional, Tuple
|
|
6
6
|
|
7
7
|
import typer
|
8
8
|
|
9
|
-
from rbx import console, testing_utils
|
9
|
+
from rbx import console, testing_utils
|
10
|
+
from rbx.box import cd
|
10
11
|
from rbx.box.contest import contest_utils
|
11
12
|
from rbx.box.contest.contest_package import get_problems
|
12
13
|
from rbx.box.contest.schema import Contest, ContestProblem, ContestStatement
|
@@ -58,7 +59,7 @@ class ExtractedProblem:
|
|
58
59
|
|
59
60
|
|
60
61
|
def _get_samples(problem: ContestProblem) -> List[Testcase]:
|
61
|
-
with
|
62
|
+
with cd.new_package_cd(problem.get_path()):
|
62
63
|
contest_utils.clear_package_cache()
|
63
64
|
return get_samples()
|
64
65
|
|
@@ -156,7 +157,7 @@ def _build_problem_statements(
|
|
156
157
|
console.console.print(
|
157
158
|
f'Building statement for problem {extracted_problem.problem.short_name}...'
|
158
159
|
)
|
159
|
-
with
|
160
|
+
with cd.new_package_cd(extracted_problem.problem.get_path()):
|
160
161
|
contest_utils.clear_package_cache()
|
161
162
|
# TODO: respect steps override
|
162
163
|
content, _ = build_statements.build_statement_bytes(
|
@@ -282,6 +283,7 @@ def build_statement_rooted(
|
|
282
283
|
|
283
284
|
if joiner is None:
|
284
285
|
return last_content, last_output
|
286
|
+
assert statement.joiner is not None
|
285
287
|
|
286
288
|
# Join statements.
|
287
289
|
console.console.print('Joining statements...')
|
@@ -6,6 +6,7 @@ import typer
|
|
6
6
|
from pydantic import ValidationError
|
7
7
|
|
8
8
|
from rbx import console, utils
|
9
|
+
from rbx.box import cd
|
9
10
|
from rbx.box.contest.schema import Contest
|
10
11
|
from rbx.box.package import find_problem_package_or_die, warn_preset_deactivated
|
11
12
|
from rbx.box.schema import Package
|
@@ -58,7 +59,7 @@ def find_contest(root: pathlib.Path = pathlib.Path()) -> pathlib.Path:
|
|
58
59
|
def within_contest(func):
|
59
60
|
@functools.wraps(func)
|
60
61
|
def wrapper(*args, **kwargs):
|
61
|
-
with
|
62
|
+
with cd.new_package_cd(find_contest()):
|
62
63
|
return func(*args, **kwargs)
|
63
64
|
|
64
65
|
return wrapper
|
@@ -7,7 +7,7 @@ import rich.prompt
|
|
7
7
|
import typer
|
8
8
|
|
9
9
|
from rbx import annotations, console, utils
|
10
|
-
from rbx.box import creation, presets
|
10
|
+
from rbx.box import cd, creation, presets
|
11
11
|
from rbx.box.contest import contest_utils, statements
|
12
12
|
from rbx.box.contest.contest_package import (
|
13
13
|
find_contest,
|
@@ -111,7 +111,7 @@ def create(
|
|
111
111
|
if local:
|
112
112
|
shutil.copytree(str(preset_path), str(dest_path / '.local.rbx'))
|
113
113
|
|
114
|
-
with
|
114
|
+
with cd.new_package_cd(dest_path):
|
115
115
|
contest_utils.clear_all_caches()
|
116
116
|
presets.generate_lock(preset if not local else presets.LOCAL)
|
117
117
|
|
@@ -2,8 +2,8 @@ from typing import Annotated, List, Optional
|
|
2
2
|
|
3
3
|
import typer
|
4
4
|
|
5
|
-
from rbx import annotations, console
|
6
|
-
from rbx.box import builder, environment
|
5
|
+
from rbx import annotations, console
|
6
|
+
from rbx.box import builder, cd, environment
|
7
7
|
from rbx.box.contest import contest_utils
|
8
8
|
from rbx.box.contest.build_contest_statements import build_statement
|
9
9
|
from rbx.box.contest.contest_package import (
|
@@ -49,7 +49,7 @@ def build(
|
|
49
49
|
console.console.print(
|
50
50
|
f'Processing problem [item]{problem.short_name}[/item]...'
|
51
51
|
)
|
52
|
-
with
|
52
|
+
with cd.new_package_cd(problem.get_path()):
|
53
53
|
contest_utils.clear_package_cache()
|
54
54
|
|
55
55
|
if not builder.build(
|
@@ -0,0 +1,26 @@
|
|
1
|
+
from typing import Awaitable, Callable, Generic, Optional, TypeVar
|
2
|
+
|
3
|
+
T = TypeVar('T')
|
4
|
+
U = TypeVar('U')
|
5
|
+
|
6
|
+
|
7
|
+
class Deferred(Generic[T]):
|
8
|
+
def __init__(self, func: Callable[[], Awaitable[T]]):
|
9
|
+
self.func = func
|
10
|
+
self.cache: Optional[T] = None
|
11
|
+
|
12
|
+
def __call__(self) -> Awaitable[T]:
|
13
|
+
async def async_wrapper():
|
14
|
+
if self.cache is None:
|
15
|
+
self.cache = await self.func()
|
16
|
+
return self.cache
|
17
|
+
|
18
|
+
return async_wrapper()
|
19
|
+
|
20
|
+
def peek(self) -> Optional[T]:
|
21
|
+
return self.cache
|
22
|
+
|
23
|
+
def wrap_with(
|
24
|
+
self, wrapper: Callable[[Awaitable[T]], Awaitable[U]]
|
25
|
+
) -> 'Deferred[U]':
|
26
|
+
return Deferred(lambda: wrapper(self()))
|
@@ -5,16 +5,8 @@ from pydantic import BaseModel, Field
|
|
5
5
|
from rbx.box.packaging.boca.extension import BocaExtension, BocaLanguageExtension
|
6
6
|
|
7
7
|
|
8
|
-
# List of extensions defined in-place.
|
9
|
-
class MacExtension(BaseModel):
|
10
|
-
gpp_alternative: Optional[str] = None
|
11
|
-
|
12
|
-
|
13
8
|
# Extension abstractions.
|
14
9
|
class Extensions(BaseModel):
|
15
|
-
mac: Optional[MacExtension] = Field(
|
16
|
-
None, description='Extension for setting mac-only configuration.'
|
17
|
-
)
|
18
10
|
boca: Optional[BocaExtension] = Field(
|
19
11
|
None, description='Environment-level extensions for BOCA packaging.'
|
20
12
|
)
|
@@ -8,7 +8,7 @@ import typer
|
|
8
8
|
|
9
9
|
from rbx import console
|
10
10
|
from rbx.box import checkers, package, testcases, validators
|
11
|
-
from rbx.box.code import compile_item, run_item
|
11
|
+
from rbx.box.code import SanitizationLevel, compile_item, run_item
|
12
12
|
from rbx.box.environment import (
|
13
13
|
EnvironmentSandbox,
|
14
14
|
ExecutionConfig,
|
@@ -32,7 +32,7 @@ from rbx.utils import StatusProgress
|
|
32
32
|
|
33
33
|
|
34
34
|
def _compile_generator(generator: CodeItem) -> str:
|
35
|
-
return compile_item(generator)
|
35
|
+
return compile_item(generator, sanitized=SanitizationLevel.PREFER)
|
36
36
|
|
37
37
|
|
38
38
|
def _get_group_input(
|
@@ -114,11 +114,8 @@ def generate_output_for_testcase(
|
|
114
114
|
if main_solution is None:
|
115
115
|
return
|
116
116
|
|
117
|
-
|
117
|
+
# Obey no limits when generating testcases.
|
118
118
|
sandbox = EnvironmentSandbox()
|
119
|
-
sandbox.timeLimit = timelimit * 3
|
120
|
-
sandbox.wallTimeLimit = timelimit * 3
|
121
|
-
sandbox.memoryLimit = pkg.memorylimit_for_language(main_solution.language)
|
122
119
|
sandbox.fileSizeLimit = pkg.outputLimit
|
123
120
|
extra_config = ExecutionConfig(sandbox=sandbox)
|
124
121
|
|
@@ -325,7 +322,7 @@ def generate_standalone(
|
|
325
322
|
# Get generator item
|
326
323
|
generator = package.get_generator(call.name)
|
327
324
|
if generator_digest is None:
|
328
|
-
generator_digest =
|
325
|
+
generator_digest = _compile_generator(generator)
|
329
326
|
|
330
327
|
generation_log = run_item(
|
331
328
|
generator,
|
@@ -354,7 +351,9 @@ def generate_standalone(
|
|
354
351
|
# Run validator, if it is available.
|
355
352
|
if validator is not None and validate:
|
356
353
|
if validator_digest is None:
|
357
|
-
|
354
|
+
validator_tp = validators.compile_main_validator()
|
355
|
+
assert validator_tp is not None
|
356
|
+
_, validator_digest = validator_tp
|
358
357
|
ok, message, *_ = validators.validate_test(output, validator, validator_digest)
|
359
358
|
if not ok:
|
360
359
|
console.console.print(
|