rbx.cp 0.5.27__tar.gz → 0.5.28__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.27 → rbx_cp-0.5.28}/PKG-INFO +1 -1
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/pyproject.toml +1 -1
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/code.py +2 -0
- rbx_cp-0.5.28/rbx/box/retries.py +143 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/setter_config.py +22 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/solutions.py +59 -51
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/stresses.py +51 -29
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/stressing/finder_parser.py +2 -2
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/steps.py +1 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/steps_with_caching.py +5 -3
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/default_setter_config.mac.yml +8 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/default_setter_config.yml +8 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/LICENSE +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/README.md +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/__init__.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/annotations.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/autoenum.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/__init__.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/builder.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/cd.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/checkers.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/compile.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/conftest.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/contest/__init__.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/contest/build_contest_statements.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/contest/contest_package.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/contest/contest_utils.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/contest/main.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/contest/schema.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/contest/statements.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/creation.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/deferred.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/download.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/environment.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/extensions.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/generators.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/generators_test.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/main.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/package.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/packaging/boca/extension.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/packaging/boca/packager.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/packaging/contest_main.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/packaging/main.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/packaging/packager.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/packaging/polygon/packager.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/packaging/polygon/test.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/packaging/polygon/xml_schema.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/presets/__init__.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/presets/fetch.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/presets/lock_schema.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/presets/schema.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/sanitizers/warning_stack.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/schema.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/solutions_test.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/statements/__init__.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/statements/build_statements.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/statements/builders.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/statements/joiners.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/statements/latex.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/statements/latex_jinja.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/statements/schema.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/stressing/__init__.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/stressing/generator_parser.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/testcases.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/ui/__init__.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/ui/captured_log.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/ui/css/app.tcss +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/ui/main.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/ui/run.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/validators.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/box/validators_test.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/checker.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/clone.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/config.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/conftest.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/console.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/create.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/edit.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/__init__.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/caching.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/conftest.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/judge/__init__.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/judge/cacher.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/judge/digester.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/judge/sandbox.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/judge/sandboxes/__init__.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/judge/sandboxes/isolate.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/judge/sandboxes/stupid_sandbox.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/judge/sandboxes/timeit.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/judge/storage.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/judge/test.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/judge/testiso.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading/steps_with_caching_run_test.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/grading_utils.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/hydration.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/main.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/metadata.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/providers/__init__.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/providers/codeforces.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/providers/provider.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/checkers/boilerplate.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/default_config.json +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/envs/default.rbx.yml +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/envs/isolate.rbx.yml +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/checker.sh +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/compare +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/compile/c +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/compile/cc +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/compile/cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/compile/java +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/compile/kt +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/compile/pas +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/compile/py2 +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/compile/py3 +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/run/c +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/run/cc +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/run/cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/run/java +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/run/kt +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/run/py2 +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/packagers/boca/run/py3 +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/contest/contest.rbx.yml +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/contest/statement/contest.rbx.tex +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/contest/statement/olymp.sty +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/contest/statement/template.rbx.tex +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/preset.rbx.yml +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/.gitignore +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/gen.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/problem.rbx.yml +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/random.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/random.txt +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/sols/main.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/sols/slow.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/sols/wa.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/statement/olymp.sty +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/statement/projecao.png +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/statement/statement.rbx.tex +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/statement/template.rbx.tex +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/tests/samples/000.in +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/tests/samples/001.in +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/validator.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/wcmp.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/templates/template.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/run.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/schema.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/submit.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/submitors/__init__.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/submitors/codeforces.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/submitors/submitor.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/test.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testcase.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testcase_rendering.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/box1/gen1.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/box1/gen2.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/box1/genScript.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/box1/hard-tle.sol.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/box1/ole.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/box1/problem.rbx.yml +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/box1/re.sol.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/box1/sol.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/box1/tests/1.in +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/box1/tle-and-incorrect.sol.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/box1/tle.sol.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/box1/validator.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/box1/wa.sol.cpp +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/caching/executable.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testdata/compatible +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/testing_utils.py +0 -0
- {rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/utils.py +0 -0
@@ -266,6 +266,7 @@ def run_item(
|
|
266
266
|
outputs: Optional[List[GradingFileOutput]] = None,
|
267
267
|
extra_args: Optional[str] = None,
|
268
268
|
extra_config: Optional[ExecutionConfig] = None,
|
269
|
+
retry_index: Optional[int] = None,
|
269
270
|
) -> Optional[RunLog]:
|
270
271
|
language = find_language_name(code)
|
271
272
|
execution_options = get_execution_config(language)
|
@@ -350,6 +351,7 @@ def run_item(
|
|
350
351
|
is_sanitized=sanitized,
|
351
352
|
timeLimit=sandbox_params.timeout,
|
352
353
|
memoryLimit=sandbox_params.address_space,
|
354
|
+
retryIndex=retry_index,
|
353
355
|
),
|
354
356
|
)
|
355
357
|
|
@@ -0,0 +1,143 @@
|
|
1
|
+
import dataclasses
|
2
|
+
import pathlib
|
3
|
+
import shutil
|
4
|
+
import tempfile
|
5
|
+
from contextlib import contextmanager
|
6
|
+
from typing import Callable, List, Optional
|
7
|
+
|
8
|
+
from rbx.box import package
|
9
|
+
from rbx.box.setter_config import RepeatsConfig, get_setter_config
|
10
|
+
from rbx.grading.steps import Evaluation, Outcome
|
11
|
+
|
12
|
+
|
13
|
+
def _both_accepted(eval_a: Evaluation, eval_b: Evaluation) -> bool:
|
14
|
+
return (
|
15
|
+
eval_a.result.outcome == Outcome.ACCEPTED
|
16
|
+
and eval_b.result.outcome == Outcome.ACCEPTED
|
17
|
+
)
|
18
|
+
|
19
|
+
|
20
|
+
def _any_tle(eval_a: Evaluation, eval_b: Evaluation) -> bool:
|
21
|
+
return (
|
22
|
+
eval_a.result.outcome == Outcome.TIME_LIMIT_EXCEEDED
|
23
|
+
or eval_b.result.outcome == Outcome.TIME_LIMIT_EXCEEDED
|
24
|
+
)
|
25
|
+
|
26
|
+
|
27
|
+
def _get_faster(eval_a: Evaluation, eval_b: Evaluation) -> Evaluation:
|
28
|
+
if eval_a.log.time is None:
|
29
|
+
return eval_b
|
30
|
+
if eval_b.log.time is None:
|
31
|
+
return eval_a
|
32
|
+
if eval_a.log.time < eval_b.log.time:
|
33
|
+
return eval_a
|
34
|
+
return eval_b
|
35
|
+
|
36
|
+
|
37
|
+
def _merge_evaluations(eval_a: Evaluation, eval_b: Evaluation) -> Evaluation:
|
38
|
+
if _both_accepted(eval_a, eval_b) or _any_tle(eval_a, eval_b):
|
39
|
+
return _get_faster(eval_a, eval_b)
|
40
|
+
if eval_a.result.outcome != Outcome.ACCEPTED:
|
41
|
+
return eval_a
|
42
|
+
if eval_b.result.outcome != Outcome.ACCEPTED:
|
43
|
+
return eval_b
|
44
|
+
return _get_faster(eval_a, eval_b)
|
45
|
+
|
46
|
+
|
47
|
+
@contextmanager
|
48
|
+
def _temp_retry_dir():
|
49
|
+
"""Create a temporary directory for retry artifacts."""
|
50
|
+
temp_dir = tempfile.mkdtemp(prefix='rbx_retry_')
|
51
|
+
try:
|
52
|
+
yield pathlib.Path(temp_dir)
|
53
|
+
finally:
|
54
|
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
55
|
+
|
56
|
+
|
57
|
+
@dataclasses.dataclass
|
58
|
+
class FileToRecover:
|
59
|
+
from_path: pathlib.Path
|
60
|
+
to_path: pathlib.Path
|
61
|
+
|
62
|
+
|
63
|
+
def _move_to_temp_dir(path: pathlib.Path, temp_dir: pathlib.Path) -> FileToRecover:
|
64
|
+
problem_path = package.find_problem()
|
65
|
+
path = path.resolve()
|
66
|
+
temp_dir = temp_dir.resolve()
|
67
|
+
relative = path.relative_to(problem_path)
|
68
|
+
|
69
|
+
temp_path = temp_dir / relative
|
70
|
+
temp_path.parent.mkdir(parents=True, exist_ok=True)
|
71
|
+
shutil.move(path, temp_path)
|
72
|
+
return FileToRecover(temp_path, path)
|
73
|
+
|
74
|
+
|
75
|
+
def _move_logs_to_temp_dir(
|
76
|
+
eval: Evaluation, temp_dir: pathlib.Path
|
77
|
+
) -> List[FileToRecover]:
|
78
|
+
recover = []
|
79
|
+
if (
|
80
|
+
eval.log.stdout_absolute_path is not None
|
81
|
+
and eval.log.stdout_absolute_path.exists()
|
82
|
+
):
|
83
|
+
recover.append(_move_to_temp_dir(eval.log.stdout_absolute_path, temp_dir))
|
84
|
+
if (
|
85
|
+
eval.log.stderr_absolute_path is not None
|
86
|
+
and eval.log.stderr_absolute_path.exists()
|
87
|
+
):
|
88
|
+
recover.append(_move_to_temp_dir(eval.log.stderr_absolute_path, temp_dir))
|
89
|
+
if eval.log.log_absolute_path is not None and eval.log.log_absolute_path.exists():
|
90
|
+
recover.append(_move_to_temp_dir(eval.log.log_absolute_path, temp_dir))
|
91
|
+
return recover
|
92
|
+
|
93
|
+
|
94
|
+
class Retrier:
|
95
|
+
def __init__(self, config: Optional[RepeatsConfig] = None, is_stress: bool = False):
|
96
|
+
self.config = config or get_setter_config().repeats
|
97
|
+
self.is_stress = is_stress
|
98
|
+
|
99
|
+
self.reset()
|
100
|
+
|
101
|
+
def reset(self):
|
102
|
+
self.reps = self.config.reps - 1
|
103
|
+
self.retries = self.config.retries
|
104
|
+
self.retries_for_stress = self.config.retries_for_stress
|
105
|
+
self.retry_index = 0
|
106
|
+
|
107
|
+
def repeat(
|
108
|
+
self,
|
109
|
+
func: Callable[[int], Evaluation],
|
110
|
+
) -> Evaluation:
|
111
|
+
self.retry_index += 1
|
112
|
+
eval = func(self.retry_index)
|
113
|
+
if self.should_repeat(eval):
|
114
|
+
with _temp_retry_dir() as temp_dir:
|
115
|
+
# Move files to temp dir to open run for repeat.
|
116
|
+
recover = _move_logs_to_temp_dir(eval, temp_dir)
|
117
|
+
# Actually repeat and choose the best evaluation.
|
118
|
+
next_eval = self.repeat(func)
|
119
|
+
chosen_eval = _merge_evaluations(eval, next_eval)
|
120
|
+
|
121
|
+
if id(chosen_eval) == id(eval):
|
122
|
+
# Must recover originally moved files.
|
123
|
+
for file in recover:
|
124
|
+
file.to_path.parent.mkdir(parents=True, exist_ok=True)
|
125
|
+
shutil.move(file.from_path, file.to_path)
|
126
|
+
return chosen_eval
|
127
|
+
return eval
|
128
|
+
|
129
|
+
def should_repeat(self, eval: Evaluation) -> bool:
|
130
|
+
if self.is_stress:
|
131
|
+
if (
|
132
|
+
eval.result.outcome == Outcome.TIME_LIMIT_EXCEEDED
|
133
|
+
and self.retries_for_stress > 0
|
134
|
+
):
|
135
|
+
self.retries_for_stress -= 1
|
136
|
+
return True
|
137
|
+
if eval.result.outcome == Outcome.TIME_LIMIT_EXCEEDED and self.retries > 0:
|
138
|
+
self.retries -= 1
|
139
|
+
return True
|
140
|
+
if self.reps > 0:
|
141
|
+
self.reps -= 1
|
142
|
+
return True
|
143
|
+
return False
|
@@ -36,6 +36,23 @@ class WarningsConfig(BaseModel):
|
|
36
36
|
)
|
37
37
|
|
38
38
|
|
39
|
+
class RepeatsConfig(BaseModel):
|
40
|
+
reps: int = Field(
|
41
|
+
1,
|
42
|
+
description='Number of times to repeat the solution.',
|
43
|
+
)
|
44
|
+
|
45
|
+
retries: int = Field(
|
46
|
+
0,
|
47
|
+
description='Number of times to retry if the solution TLs.',
|
48
|
+
)
|
49
|
+
|
50
|
+
retries_for_stress: int = Field(
|
51
|
+
0,
|
52
|
+
description='Number of times to retry in stress mode if the solution TLs.',
|
53
|
+
)
|
54
|
+
|
55
|
+
|
39
56
|
class SetterConfig(BaseModel):
|
40
57
|
sanitizers: SanitizersConfig = Field(
|
41
58
|
default_factory=SanitizersConfig, # type: ignore
|
@@ -46,6 +63,11 @@ class SetterConfig(BaseModel):
|
|
46
63
|
description='Configuration for warnings.',
|
47
64
|
)
|
48
65
|
|
66
|
+
repeats: RepeatsConfig = Field(
|
67
|
+
default_factory=RepeatsConfig, # type: ignore
|
68
|
+
description='Configuration for repeats.',
|
69
|
+
)
|
70
|
+
|
49
71
|
command_substitutions: Dict[str, str] = Field(
|
50
72
|
{},
|
51
73
|
description='Substitutions to apply to commands before running them.',
|
@@ -26,6 +26,7 @@ from rbx.box.environment import (
|
|
26
26
|
VerificationLevel,
|
27
27
|
)
|
28
28
|
from rbx.box.generators import generate_output_for_testcase, generate_standalone
|
29
|
+
from rbx.box.retries import Retrier
|
29
30
|
from rbx.box.schema import (
|
30
31
|
ExpectedOutcome,
|
31
32
|
GeneratorCall,
|
@@ -169,63 +170,70 @@ def _run_solution_on_testcase(
|
|
169
170
|
verification: VerificationLevel = VerificationLevel.NONE,
|
170
171
|
timelimit_override: Optional[int] = None,
|
171
172
|
) -> Evaluation:
|
172
|
-
|
173
|
+
def run_fn(retry_index: int) -> Evaluation:
|
174
|
+
actual_sandbox = package.get_singleton_sandbox()
|
173
175
|
|
174
|
-
|
175
|
-
|
176
|
-
|
176
|
+
limits = get_limits_for_language(
|
177
|
+
solution.language, verification, timelimit_override
|
178
|
+
)
|
177
179
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
180
|
+
sandbox = EnvironmentSandbox()
|
181
|
+
sandbox.timeLimit = limits.time
|
182
|
+
if limits.isDoubleTL and sandbox.timeLimit is not None:
|
183
|
+
# Double TL.
|
184
|
+
sandbox.timeLimit = sandbox.timeLimit * 2
|
185
|
+
sandbox.wallTimeLimit = sandbox.timeLimit
|
186
|
+
if sandbox.timeLimit is not None and actual_sandbox.use_soft_timeout():
|
187
|
+
sandbox.wallTimeLimit = sandbox.timeLimit * 2
|
188
|
+
sandbox.memoryLimit = limits.memory
|
189
|
+
sandbox.fileSizeLimit = limits.output
|
190
|
+
extra_config = ExecutionConfig(sandbox=sandbox)
|
191
|
+
|
192
|
+
output_path = output_dir / testcase.inputPath.with_suffix('.out').name
|
193
|
+
error_path = output_path.with_suffix('.err')
|
194
|
+
log_path = output_path.with_suffix('.log')
|
195
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
196
|
+
|
197
|
+
run_log = run_item(
|
198
|
+
solution,
|
199
|
+
DigestOrSource.create(compiled_digest),
|
200
|
+
stdin=DigestOrSource.create(testcase.inputPath),
|
201
|
+
stdout=DigestOrDest.create(output_path),
|
202
|
+
stderr=DigestOrDest.create(error_path),
|
203
|
+
extra_config=extra_config,
|
204
|
+
retry_index=retry_index,
|
205
|
+
)
|
203
206
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
207
|
+
if checker_digest is not None:
|
208
|
+
checker_result = checkers.check(
|
209
|
+
checker_digest,
|
210
|
+
run_log,
|
211
|
+
testcase,
|
212
|
+
program_output=output_path,
|
213
|
+
)
|
214
|
+
else:
|
215
|
+
checker_result = checkers.check_with_no_output(run_log)
|
216
|
+
|
217
|
+
eval = Evaluation(
|
218
|
+
result=checker_result,
|
219
|
+
testcase=TestcaseIO(
|
220
|
+
index=testcase_index,
|
221
|
+
input=testcase.inputPath,
|
222
|
+
output=testcase.outputPath,
|
223
|
+
),
|
224
|
+
log=TestcaseLog(
|
225
|
+
**(run_log.model_dump() if run_log is not None else {}),
|
226
|
+
stdout_absolute_path=output_path.absolute(),
|
227
|
+
stderr_absolute_path=error_path.absolute(),
|
228
|
+
log_absolute_path=log_path.absolute(),
|
229
|
+
),
|
210
230
|
)
|
211
|
-
else:
|
212
|
-
checker_result = checkers.check_with_no_output(run_log)
|
213
231
|
|
214
|
-
|
215
|
-
|
216
|
-
testcase=TestcaseIO(
|
217
|
-
index=testcase_index, input=testcase.inputPath, output=testcase.outputPath
|
218
|
-
),
|
219
|
-
log=TestcaseLog(
|
220
|
-
**(run_log.model_dump() if run_log is not None else {}),
|
221
|
-
stdout_absolute_path=output_path.absolute(),
|
222
|
-
stderr_absolute_path=error_path.absolute(),
|
223
|
-
log_absolute_path=log_path.absolute(),
|
224
|
-
),
|
225
|
-
)
|
232
|
+
log_path.write_text(model_to_yaml(eval))
|
233
|
+
return eval
|
226
234
|
|
227
|
-
|
228
|
-
return
|
235
|
+
retrier = Retrier()
|
236
|
+
return retrier.repeat(run_fn)
|
229
237
|
|
230
238
|
|
231
239
|
def _run_solution(
|
@@ -10,13 +10,17 @@ from rbx import console
|
|
10
10
|
from rbx.box import checkers, package, validators
|
11
11
|
from rbx.box.code import SanitizationLevel, compile_item, run_item
|
12
12
|
from rbx.box.generators import generate_standalone
|
13
|
+
from rbx.box.retries import Retrier
|
13
14
|
from rbx.box.schema import CodeItem, GeneratorCall, Stress, Testcase
|
14
15
|
from rbx.box.solutions import compile_solutions, get_outcome_style_verdict
|
15
16
|
from rbx.box.stressing import finder_parser
|
16
17
|
from rbx.grading.steps import (
|
17
18
|
DigestOrDest,
|
18
19
|
DigestOrSource,
|
20
|
+
Evaluation,
|
19
21
|
Outcome,
|
22
|
+
TestcaseIO,
|
23
|
+
TestcaseLog,
|
20
24
|
)
|
21
25
|
from rbx.utils import StatusProgress
|
22
26
|
|
@@ -131,8 +135,9 @@ def run_stress(
|
|
131
135
|
@functools.cache
|
132
136
|
def run_solution_fn(
|
133
137
|
solution: str,
|
138
|
+
retry_index: Optional[int] = None,
|
134
139
|
input_path=input_path,
|
135
|
-
) ->
|
140
|
+
) -> TestcaseLog:
|
136
141
|
index = solution_indices[solution]
|
137
142
|
sol = solutions[index]
|
138
143
|
output_path = input_path.with_stem(f'{index}').with_suffix('.out')
|
@@ -144,29 +149,30 @@ def run_stress(
|
|
144
149
|
stdin=DigestOrSource.create(input_path),
|
145
150
|
stdout=DigestOrDest.create(output_path),
|
146
151
|
stderr=DigestOrDest.create(stderr_path),
|
152
|
+
retry_index=retry_index,
|
147
153
|
)
|
148
154
|
|
149
|
-
return
|
150
|
-
|
151
|
-
|
152
|
-
|
155
|
+
return TestcaseLog(
|
156
|
+
**(run_log.model_dump() if run_log is not None else {}),
|
157
|
+
stdout_absolute_path=output_path.absolute(),
|
158
|
+
stderr_absolute_path=stderr_path.absolute(),
|
153
159
|
)
|
154
160
|
|
155
161
|
# Get main solution output.
|
156
162
|
expected_output_path = empty_path
|
157
163
|
if needs_expected_output:
|
158
|
-
|
159
|
-
main_checker_result = checkers.check_with_no_output(
|
164
|
+
main_testcase_log = run_solution_fn(str(solutions[0].path))
|
165
|
+
main_checker_result = checkers.check_with_no_output(main_testcase_log)
|
160
166
|
if main_checker_result.outcome != Outcome.ACCEPTED:
|
161
167
|
console.console.print(
|
162
168
|
'[error]Error while generating main solution output.[/error]'
|
163
169
|
)
|
164
170
|
console.console.print(f'Input written at [item]{input_path}[/item]')
|
165
171
|
console.console.print(
|
166
|
-
f'Output written at [item]{
|
172
|
+
f'Output written at [item]{main_testcase_log.stdout_absolute_path}[/item]'
|
167
173
|
)
|
168
174
|
console.console.print(
|
169
|
-
f'Stderr written at [item]{
|
175
|
+
f'Stderr written at [item]{main_testcase_log.stderr_absolute_path}[/item]'
|
170
176
|
)
|
171
177
|
console.console.print()
|
172
178
|
console.console.print(
|
@@ -174,7 +180,7 @@ def run_stress(
|
|
174
180
|
"use the two-way modifier in your finder expression (':2')."
|
175
181
|
)
|
176
182
|
raise typer.Exit(1)
|
177
|
-
expected_output_path =
|
183
|
+
expected_output_path = main_testcase_log.stdout_absolute_path
|
178
184
|
|
179
185
|
@functools.cache
|
180
186
|
def run_solution_and_checker_fn(
|
@@ -182,27 +188,43 @@ def run_stress(
|
|
182
188
|
input_path=input_path,
|
183
189
|
expected_output_path=expected_output_path,
|
184
190
|
) -> finder_parser.FinderResult:
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
checker_digest
|
196
|
-
|
197
|
-
|
198
|
-
|
191
|
+
def run_fn(retry_index: int) -> Evaluation:
|
192
|
+
solution = call.solution
|
193
|
+
checker = call.checker
|
194
|
+
|
195
|
+
testcase_log = run_solution_fn(solution, retry_index=retry_index)
|
196
|
+
assert testcase_log.stdout_absolute_path is not None
|
197
|
+
|
198
|
+
if checker is None:
|
199
|
+
checker_result = checkers.check_with_no_output(testcase_log)
|
200
|
+
else:
|
201
|
+
checker_digest = finders_digest[checker.path]
|
202
|
+
checker_result = checkers.check(
|
203
|
+
checker_digest,
|
204
|
+
testcase_log,
|
205
|
+
Testcase(inputPath=input_path, outputPath=expected_output_path),
|
206
|
+
program_output=testcase_log.stdout_absolute_path,
|
207
|
+
)
|
208
|
+
|
209
|
+
return Evaluation(
|
210
|
+
result=checker_result,
|
211
|
+
testcase=TestcaseIO(
|
212
|
+
index=0,
|
213
|
+
input=input_path,
|
214
|
+
output=expected_output_path,
|
215
|
+
),
|
216
|
+
log=testcase_log,
|
199
217
|
)
|
218
|
+
|
219
|
+
retrier = Retrier(is_stress=True)
|
220
|
+
eval = retrier.repeat(run_fn)
|
221
|
+
|
200
222
|
return finder_parser.FinderResult(
|
201
|
-
solution=solution,
|
202
|
-
outcome=
|
203
|
-
checker=checker,
|
204
|
-
|
205
|
-
checker_result=
|
223
|
+
solution=call.solution,
|
224
|
+
outcome=eval.result.outcome,
|
225
|
+
checker=call.checker,
|
226
|
+
solution_log=eval.log,
|
227
|
+
checker_result=eval.result,
|
206
228
|
)
|
207
229
|
|
208
230
|
runner = finder_parser.FinderTreeRunner(runner=run_solution_and_checker_fn)
|
@@ -10,7 +10,7 @@ import typer
|
|
10
10
|
from rbx import console
|
11
11
|
from rbx.box import package
|
12
12
|
from rbx.box.schema import CodeItem, ExpectedOutcome
|
13
|
-
from rbx.grading.steps import CheckerResult, Outcome, RunLog
|
13
|
+
from rbx.grading.steps import CheckerResult, Outcome, RunLog, TestcaseLog
|
14
14
|
|
15
15
|
LARK_GRAMMAR = r"""
|
16
16
|
// A bunch of words
|
@@ -102,7 +102,7 @@ class FinderResult:
|
|
102
102
|
checker: Optional[FinderChecker]
|
103
103
|
|
104
104
|
# Auxiliary information.
|
105
|
-
|
105
|
+
solution_log: Optional[TestcaseLog] = None
|
106
106
|
checker_result: Optional[CheckerResult] = None
|
107
107
|
|
108
108
|
|
@@ -46,9 +46,11 @@ def run(
|
|
46
46
|
) -> Optional[RunLog]:
|
47
47
|
artifacts.logs = GradingLogsHolder()
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
cacheable_params = params.get_cacheable_params()
|
50
|
+
if metadata is not None and metadata.retryIndex is not None:
|
51
|
+
cacheable_params['__retry_index__'] = metadata.retryIndex
|
52
|
+
|
53
|
+
with dependency_cache([command], [artifacts], cacheable_params) as is_cached:
|
52
54
|
if not is_cached:
|
53
55
|
steps.run(
|
54
56
|
command=command,
|
@@ -14,6 +14,14 @@ command_substitutions:
|
|
14
14
|
python2: python2
|
15
15
|
python3: python3
|
16
16
|
|
17
|
+
repeats:
|
18
|
+
# Number of times to run the solution.
|
19
|
+
reps: 1
|
20
|
+
# Number of times to retry if the solution TLs.
|
21
|
+
retries: 0
|
22
|
+
# Number of times to retry in stress mode if the solution TLs.
|
23
|
+
retries_for_stress: 0
|
24
|
+
|
17
25
|
# Whether sanitizers will be enabled by default
|
18
26
|
# when running testlib components.
|
19
27
|
# This flag has no effect on running solutions with
|
@@ -14,6 +14,14 @@ command_substitutions:
|
|
14
14
|
python2: python2
|
15
15
|
python3: python3
|
16
16
|
|
17
|
+
repeats:
|
18
|
+
# Number of times to run the solution.
|
19
|
+
reps: 1
|
20
|
+
# Number of times to retry if the solution TLs.
|
21
|
+
retries: 0
|
22
|
+
# Number of times to retry in stress mode if the solution TLs.
|
23
|
+
retries_for_stress: 0
|
24
|
+
|
17
25
|
# Whether sanitizers will be enabled by default
|
18
26
|
# when running testlib components.
|
19
27
|
# This flag has no effect on running solutions with
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/contest/statement/contest.rbx.tex
RENAMED
File without changes
|
File without changes
|
{rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/contest/statement/template.rbx.tex
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/statement/projecao.png
RENAMED
File without changes
|
{rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/statement/statement.rbx.tex
RENAMED
File without changes
|
{rbx_cp-0.5.27 → rbx_cp-0.5.28}/rbx/resources/presets/default/problem/statement/template.rbx.tex
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|