rbx.cp 0.9.0__tar.gz → 0.9.1__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.9.0 → rbx_cp-0.9.1}/PKG-INFO +1 -1
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/pyproject.toml +1 -1
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/cli.py +3 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/environment.py +3 -3
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/setter_config.py +18 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/config.py +7 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/caching.py +24 -2
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/conftest.py +2 -2
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/grading_context.py +25 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/steps_with_caching_run_test.py +281 -5
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/default_setter_config.mac.yml +15 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/default_setter_config.yml +15 -0
- rbx_cp-0.9.1/rbx/resources/presets/default/env.rbx.yml +67 -0
- rbx_cp-0.9.0/rbx/resources/envs/default.rbx.yml +0 -36
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/LICENSE +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/README.md +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/annotations.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/autoenum.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/builder.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/cd.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/checkers.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/code.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/compile.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/conftest.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/contest/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/contest/build_contest_statements.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/contest/contest_package.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/contest/contest_utils.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/contest/main.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/contest/schema.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/contest/statements.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/creation.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/deferred.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/download.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/dump_schemas.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/extensions.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/fields.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/formatting.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/generators.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/generators_test.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/git_utils.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/global_package.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/header.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/lang.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/lazy_importing_main.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/lazy_importing_test.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/linting.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/main.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/naming.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/package.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/packaging/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/packaging/boca/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/packaging/boca/extension.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/packaging/boca/packager.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/packaging/contest_main.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/packaging/main.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/packaging/moj/packager.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/packaging/packager.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/packaging/pkg/packager.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/packaging/polygon/packager.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/packaging/polygon/polygon_api.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/packaging/polygon/test.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/packaging/polygon/upload.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/packaging/polygon/xml_schema.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/presets/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/presets/fetch.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/presets/lock_schema.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/presets/schema.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/remote.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/retries.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/sanitizers/warning_stack.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/schema.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/solutions.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/solutions_test.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/state.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/statements/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/statements/build_statements.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/statements/builders.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/statements/expander.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/statements/joiners.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/statements/latex.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/statements/latex_jinja.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/statements/schema.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/stats.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/stresses.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/stressing/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/stressing/finder_parser.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/stressing/generator_parser.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/tasks.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/testcase_extractors.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/testcase_utils.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/testcases/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/testcases/main.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/tooling/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/tooling/boca/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/tooling/boca/main.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/tooling/boca/scrape.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/tooling/boca/scraper.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/tooling/main.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/captured_log.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/css/app.tcss +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/main.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/screens/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/screens/build.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/screens/command.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/screens/differ.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/screens/error.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/screens/rich_log_modal.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/screens/run.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/screens/run_explorer.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/screens/run_test_explorer.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/screens/selector.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/screens/test_explorer.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/utils/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/utils/run_ui.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/widgets/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/widgets/diff_box.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/widgets/file_log.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/widgets/interaction_box.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/widgets/rich_log_box.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/widgets/test_output_box.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/ui/widgets/two_sided_test_output_box.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/unit.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/validators.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/box/validators_test.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/checker.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/clone.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/conftest.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/console.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/create.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/edit.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/debug_context.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/judge/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/judge/cacher.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/judge/digester.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/judge/sandbox.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/judge/sandboxes/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/judge/sandboxes/isolate.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/judge/sandboxes/stupid_sandbox.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/judge/sandboxes/timeit.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/judge/storage.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/judge/test.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/judge/testiso.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/limits.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/processing_context.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/profiling.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/steps.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading/steps_with_caching.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/grading_utils.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/hydration.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/main.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/metadata.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/providers/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/providers/codeforces.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/providers/provider.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/checkers/boilerplate.cpp +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/checkers/noop.cpp +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/default_config.json +0 -0
- /rbx_cp-0.9.0/rbx/resources/presets/default/env.rbx.yml → /rbx_cp-0.9.1/rbx/resources/envs/default.rbx.yml +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/envs/isolate.rbx.yml +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/checker.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/compare.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/compile/c +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/compile/cc +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/compile/cpp +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/compile/java +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/compile/kt +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/compile/py2 +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/compile/py3 +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/interactive/c +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/interactive/cc +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/interactive/cpp +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/interactive/java +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/interactive/kt +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/interactive/py2 +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/interactive/py3 +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/interactor_compile.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/interactor_run.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/run/bkp +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/run/c +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/run/cc +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/run/cpp +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/run/java +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/run/kt +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/run/py2 +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/run/py3 +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/safeexec.c +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/boca/safeexec_compile.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/c/compile.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/c/prep.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/c/run.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/compare.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/cpp/compile.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/cpp/prep.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/cpp/run.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/interactor_prep.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/interactor_run.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/java/compile.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/java/prep.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/java/run.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/py2/compile.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/py2/prep.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/py2/run.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/py3/compile.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/py3/prep.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/packagers/moj/scripts/py3/run.sh +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/contest/.gitignore +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/contest/contest.rbx.yml +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/contest/statement/contest.rbx.tex +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/contest/statement/instructions.tex +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/contest/statement/logo.png +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/preset.rbx.yml +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/problem/.gitignore +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/problem/gens/gen.cpp +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/problem/manual_tests/samples/000.in +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/problem/manual_tests/samples/001.in +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/problem/problem.rbx.yml +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/problem/rbx.h +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/problem/sols/main.cpp +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/problem/sols/slow.cpp +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/problem/sols/wa.cpp +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/problem/statement/statement.rbx.tex +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/problem/testplan/random.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/problem/testplan/random.txt +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/problem/validator.cpp +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/problem/wcmp.cpp +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/shared/contest_template.rbx.tex +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/shared/icpc.sty +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/presets/default/shared/problem_template.rbx.tex +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/templates/rbx.h +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/resources/templates/template.cpp +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/run.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/schema.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/submit.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/submitors/__init__.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/submitors/codeforces.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/submitors/submitor.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/test.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/testcase.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/testcase_rendering.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/testing_utils.py +0 -0
- {rbx_cp-0.9.0 → rbx_cp-0.9.1}/rbx/utils.py +0 -0
@@ -159,6 +159,9 @@ def main(
|
|
159
159
|
state.STATE.debug_logs = capture
|
160
160
|
|
161
161
|
grading_context.cache_level_var.set(grading_context.CacheLevel(cache))
|
162
|
+
grading_context.check_integrity_var.set(
|
163
|
+
setter_config.get_setter_config().caching.check_integrity
|
164
|
+
)
|
162
165
|
|
163
166
|
if profile:
|
164
167
|
from rbx.grading import profiling
|
@@ -247,13 +247,13 @@ execution config can be individually overridden in the language configuration.""
|
|
247
247
|
|
248
248
|
|
249
249
|
def get_app_environment_path(env: str) -> pathlib.Path:
|
250
|
-
return config.
|
250
|
+
return config.get_resources_file(pathlib.PosixPath('envs') / f'{env}.rbx.yml')
|
251
251
|
|
252
252
|
|
253
253
|
def get_active_environment_path() -> pathlib.Path:
|
254
254
|
env_path = presets.get_preset_environment_path()
|
255
255
|
if env_path is None:
|
256
|
-
env_path = get_app_environment_path(
|
256
|
+
env_path = get_app_environment_path('default')
|
257
257
|
return env_path
|
258
258
|
|
259
259
|
|
@@ -261,7 +261,7 @@ def get_active_environment_path() -> pathlib.Path:
|
|
261
261
|
def get_active_environment_description() -> str:
|
262
262
|
env_path = presets.get_preset_environment_path()
|
263
263
|
if env_path is None:
|
264
|
-
return
|
264
|
+
return 'default'
|
265
265
|
preset = presets.get_active_preset()
|
266
266
|
return f'preset - {preset.name}'
|
267
267
|
|
@@ -9,6 +9,7 @@ import typer
|
|
9
9
|
from pydantic import BaseModel, Field
|
10
10
|
|
11
11
|
from rbx import config, console, utils
|
12
|
+
from rbx.grading.grading_context import CacheLevel
|
12
13
|
|
13
14
|
app = typer.Typer(no_args_is_help=True)
|
14
15
|
|
@@ -52,6 +53,19 @@ class RepeatsConfig(BaseModel):
|
|
52
53
|
)
|
53
54
|
|
54
55
|
|
56
|
+
class CachingConfig(BaseModel):
|
57
|
+
level: CacheLevel = Field(
|
58
|
+
default=CacheLevel.CACHE_ALL,
|
59
|
+
description='Whether to enable caching and which caching level to use.',
|
60
|
+
)
|
61
|
+
|
62
|
+
check_integrity: bool = Field(
|
63
|
+
default=True,
|
64
|
+
description='Whether to check the integrity of the cached result, and evict it'
|
65
|
+
'if file has changed since it was cached.',
|
66
|
+
)
|
67
|
+
|
68
|
+
|
55
69
|
class SetterConfig(BaseModel):
|
56
70
|
sanitizers: SanitizersConfig = Field(
|
57
71
|
default_factory=SanitizersConfig, # type: ignore
|
@@ -75,6 +89,10 @@ class SetterConfig(BaseModel):
|
|
75
89
|
default=True,
|
76
90
|
description='Whether to use hyperlinks in the terminal output.',
|
77
91
|
)
|
92
|
+
caching: CachingConfig = Field(
|
93
|
+
default_factory=CachingConfig, # type: ignore
|
94
|
+
description='Configuration for caching.',
|
95
|
+
)
|
78
96
|
|
79
97
|
def substitute_command(self, command: str, sanitized: bool = False) -> str:
|
80
98
|
exe = shlex.split(command)[0]
|
@@ -90,6 +90,13 @@ def get_empty_app_persist_path() -> pathlib.Path:
|
|
90
90
|
return app_dir
|
91
91
|
|
92
92
|
|
93
|
+
def get_resources_file(path: pathlib.Path) -> pathlib.Path:
|
94
|
+
file_path = importlib.resources.files('rbx') / 'resources' / path # type: ignore
|
95
|
+
if file_path.is_file():
|
96
|
+
return file_path
|
97
|
+
raise FileNotFoundError(f'File {path} not found in {_RESOURCES_PKG}.')
|
98
|
+
|
99
|
+
|
93
100
|
def get_app_file(path: pathlib.Path) -> pathlib.Path:
|
94
101
|
file_path = get_app_path() / path
|
95
102
|
if file_path.is_file():
|
@@ -15,7 +15,12 @@ from rbx.grading.judge.cacher import FileCacher
|
|
15
15
|
from rbx.grading.judge.digester import digest_cooperatively
|
16
16
|
from rbx.grading.judge.storage import copyfileobj
|
17
17
|
from rbx.grading.profiling import Profiler
|
18
|
-
from rbx.grading.steps import
|
18
|
+
from rbx.grading.steps import (
|
19
|
+
DigestHolder,
|
20
|
+
GradingArtifacts,
|
21
|
+
GradingFileOutput,
|
22
|
+
GradingLogsHolder,
|
23
|
+
)
|
19
24
|
|
20
25
|
VERBOSE = False
|
21
26
|
|
@@ -109,10 +114,27 @@ def _build_fingerprint_list(
|
|
109
114
|
return fingerprints
|
110
115
|
|
111
116
|
|
117
|
+
def _maybe_check_integrity(output: GradingFileOutput):
|
118
|
+
if not grading_context.should_check_integrity():
|
119
|
+
return
|
120
|
+
if output.dest is None or not output.dest.is_symlink():
|
121
|
+
return
|
122
|
+
if output.digest is None or output.digest.value is None:
|
123
|
+
return
|
124
|
+
with output.dest.open('rb') as f:
|
125
|
+
fingerprint = digest_cooperatively(f)
|
126
|
+
if fingerprint != output.digest.value:
|
127
|
+
raise ValueError(
|
128
|
+
f'Cache was tampered with, file {output.dest} has changed since it was cached.\nPlease run `rbx clean` to reset the cache.'
|
129
|
+
)
|
130
|
+
|
131
|
+
|
112
132
|
def _build_output_fingerprint_list(artifacts_list: List[GradingArtifacts]) -> List[str]:
|
113
133
|
fingerprints = []
|
114
134
|
for artifacts in artifacts_list:
|
115
135
|
for output in artifacts.outputs:
|
136
|
+
if output.hash:
|
137
|
+
_maybe_check_integrity(output)
|
116
138
|
if output.dest is None or output.intermediate or output.hash:
|
117
139
|
continue
|
118
140
|
if not output.dest.is_file():
|
@@ -313,7 +335,7 @@ class DependencyCache:
|
|
313
335
|
self.cacher = cacher
|
314
336
|
self.db = shelve.open(self._cache_name())
|
315
337
|
tmp_dir = pathlib.Path(tempfile.mkdtemp())
|
316
|
-
self.transient_db = shelve.open(tmp_dir / '.cache_db')
|
338
|
+
self.transient_db = shelve.open(str(tmp_dir / '.cache_db'))
|
317
339
|
atexit.register(lambda: self.db.close())
|
318
340
|
atexit.register(lambda: self.transient_db.close())
|
319
341
|
atexit.register(lambda: shutil.rmtree(tmp_dir))
|
@@ -28,6 +28,6 @@ def sandbox(request, file_cacher: FileCacher) -> Iterator[SandboxBase]:
|
|
28
28
|
|
29
29
|
@pytest.fixture
|
30
30
|
def dependency_cache(
|
31
|
-
request, cleandir: pathlib.Path,
|
31
|
+
request, cleandir: pathlib.Path, file_cacher: FileCacher
|
32
32
|
) -> Iterator[DependencyCache]:
|
33
|
-
yield DependencyCache(cleandir / '.box',
|
33
|
+
yield DependencyCache(cleandir / '.box', file_cacher)
|
@@ -94,3 +94,28 @@ class compression(ConditionedContext):
|
|
94
94
|
if self.use_compression_token is not None:
|
95
95
|
use_compression_var.reset(self.use_compression_token)
|
96
96
|
return None
|
97
|
+
|
98
|
+
|
99
|
+
check_integrity_var = contextvars.ContextVar('check_integrity', default=True)
|
100
|
+
|
101
|
+
|
102
|
+
def should_check_integrity() -> bool:
|
103
|
+
return check_integrity_var.get()
|
104
|
+
|
105
|
+
|
106
|
+
class check_integrity(ConditionedContext):
|
107
|
+
def __init__(self, enabled: bool, when: Condition = True):
|
108
|
+
super().__init__(when)
|
109
|
+
self.enabled = enabled
|
110
|
+
self.token = None
|
111
|
+
|
112
|
+
def __enter__(self):
|
113
|
+
if not self.should_enter():
|
114
|
+
return self
|
115
|
+
self.token = check_integrity_var.set(self.enabled)
|
116
|
+
return self
|
117
|
+
|
118
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
119
|
+
if self.token is not None:
|
120
|
+
check_integrity_var.reset(self.token)
|
121
|
+
return None
|
@@ -2,9 +2,12 @@ import os
|
|
2
2
|
import pathlib
|
3
3
|
import sys
|
4
4
|
|
5
|
-
|
5
|
+
import pytest
|
6
|
+
|
7
|
+
from rbx.grading import grading_context, steps_with_caching
|
6
8
|
from rbx.grading.caching import DependencyCache
|
7
9
|
from rbx.grading.judge.cacher import FileCacher
|
10
|
+
from rbx.grading.judge.digester import digest_cooperatively
|
8
11
|
from rbx.grading.judge.sandbox import SandboxBase, SandboxParams
|
9
12
|
from rbx.grading.steps import (
|
10
13
|
DigestOrSource,
|
@@ -74,6 +77,124 @@ async def test_run_from_disk(
|
|
74
77
|
assert not artifacts.logs.cached
|
75
78
|
|
76
79
|
|
80
|
+
async def test_run_reruns_if_cache_disabled(
|
81
|
+
cleandir: pathlib.Path,
|
82
|
+
dependency_cache: DependencyCache,
|
83
|
+
sandbox: SandboxBase,
|
84
|
+
file_cacher: FileCacher,
|
85
|
+
):
|
86
|
+
async def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
|
87
|
+
executable = DigestOrSource.create(file_cacher.put_file_text('print(5)'))
|
88
|
+
artifacts = GradingArtifacts()
|
89
|
+
artifacts.inputs.append(
|
90
|
+
GradingFileInput(**executable.expand(), dest=pathlib.Path('executable.py'))
|
91
|
+
)
|
92
|
+
artifacts.outputs.append(
|
93
|
+
GradingFileOutput(src=pathlib.Path('box-out.txt'), dest=dest)
|
94
|
+
)
|
95
|
+
with grading_context.cache_level(grading_context.CacheLevel.NO_CACHE):
|
96
|
+
await steps_with_caching.run(
|
97
|
+
f'{sys.executable} executable.py',
|
98
|
+
params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
|
99
|
+
sandbox=sandbox,
|
100
|
+
artifacts=artifacts,
|
101
|
+
dependency_cache=dependency_cache,
|
102
|
+
)
|
103
|
+
return artifacts
|
104
|
+
|
105
|
+
artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
|
106
|
+
assert (cleandir / 'out.txt').read_text().strip() == '5'
|
107
|
+
assert artifacts.logs is not None
|
108
|
+
assert not artifacts.logs.cached
|
109
|
+
|
110
|
+
another_artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
|
111
|
+
assert (cleandir / 'out.txt').read_text().strip() == '5'
|
112
|
+
assert another_artifacts.logs is not None
|
113
|
+
assert not another_artifacts.logs.cached
|
114
|
+
|
115
|
+
|
116
|
+
async def test_run_reruns_if_first_run_cache_disabled(
|
117
|
+
cleandir: pathlib.Path,
|
118
|
+
dependency_cache: DependencyCache,
|
119
|
+
sandbox: SandboxBase,
|
120
|
+
file_cacher: FileCacher,
|
121
|
+
):
|
122
|
+
async def configure_and_run_with_dest(
|
123
|
+
dest: pathlib.Path, cache: bool = True
|
124
|
+
) -> GradingArtifacts:
|
125
|
+
executable = DigestOrSource.create(file_cacher.put_file_text('print(5)'))
|
126
|
+
artifacts = GradingArtifacts()
|
127
|
+
artifacts.inputs.append(
|
128
|
+
GradingFileInput(**executable.expand(), dest=pathlib.Path('executable.py'))
|
129
|
+
)
|
130
|
+
artifacts.outputs.append(
|
131
|
+
GradingFileOutput(src=pathlib.Path('box-out.txt'), dest=dest)
|
132
|
+
)
|
133
|
+
with grading_context.cache_level(
|
134
|
+
grading_context.CacheLevel.NO_CACHE, when=cache
|
135
|
+
):
|
136
|
+
await steps_with_caching.run(
|
137
|
+
f'{sys.executable} executable.py',
|
138
|
+
params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
|
139
|
+
sandbox=sandbox,
|
140
|
+
artifacts=artifacts,
|
141
|
+
dependency_cache=dependency_cache,
|
142
|
+
)
|
143
|
+
return artifacts
|
144
|
+
|
145
|
+
artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'), cache=False)
|
146
|
+
assert (cleandir / 'out.txt').read_text().strip() == '5'
|
147
|
+
assert artifacts.logs is not None
|
148
|
+
assert not artifacts.logs.cached
|
149
|
+
|
150
|
+
another_artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
|
151
|
+
assert (cleandir / 'out.txt').read_text().strip() == '5'
|
152
|
+
assert another_artifacts.logs is not None
|
153
|
+
assert not another_artifacts.logs.cached
|
154
|
+
|
155
|
+
|
156
|
+
async def test_run_reruns_if_second_run_cache_disabled(
|
157
|
+
cleandir: pathlib.Path,
|
158
|
+
dependency_cache: DependencyCache,
|
159
|
+
sandbox: SandboxBase,
|
160
|
+
file_cacher: FileCacher,
|
161
|
+
):
|
162
|
+
async def configure_and_run_with_dest(
|
163
|
+
dest: pathlib.Path, cache: bool = True
|
164
|
+
) -> GradingArtifacts:
|
165
|
+
executable = DigestOrSource.create(file_cacher.put_file_text('print(5)'))
|
166
|
+
artifacts = GradingArtifacts()
|
167
|
+
artifacts.inputs.append(
|
168
|
+
GradingFileInput(**executable.expand(), dest=pathlib.Path('executable.py'))
|
169
|
+
)
|
170
|
+
artifacts.outputs.append(
|
171
|
+
GradingFileOutput(src=pathlib.Path('box-out.txt'), dest=dest)
|
172
|
+
)
|
173
|
+
with grading_context.cache_level(
|
174
|
+
grading_context.CacheLevel.NO_CACHE, when=cache
|
175
|
+
):
|
176
|
+
await steps_with_caching.run(
|
177
|
+
f'{sys.executable} executable.py',
|
178
|
+
params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
|
179
|
+
sandbox=sandbox,
|
180
|
+
artifacts=artifacts,
|
181
|
+
dependency_cache=dependency_cache,
|
182
|
+
)
|
183
|
+
return artifacts
|
184
|
+
|
185
|
+
artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
|
186
|
+
assert (cleandir / 'out.txt').read_text().strip() == '5'
|
187
|
+
assert artifacts.logs is not None
|
188
|
+
assert not artifacts.logs.cached
|
189
|
+
|
190
|
+
another_artifacts = await configure_and_run_with_dest(
|
191
|
+
pathlib.Path('out.txt'), cache=False
|
192
|
+
)
|
193
|
+
assert (cleandir / 'out.txt').read_text().strip() == '5'
|
194
|
+
assert another_artifacts.logs is not None
|
195
|
+
assert not another_artifacts.logs.cached
|
196
|
+
|
197
|
+
|
77
198
|
async def test_run_caches_intermediate_digest_if_dest_changes(
|
78
199
|
cleandir: pathlib.Path,
|
79
200
|
dependency_cache: DependencyCache,
|
@@ -106,12 +227,127 @@ async def test_run_caches_intermediate_digest_if_dest_changes(
|
|
106
227
|
another_artifacts = await configure_and_run_with_dest(
|
107
228
|
pathlib.Path('another-out.txt')
|
108
229
|
)
|
230
|
+
assert (cleandir / 'another-out.txt').read_text().strip() == '5'
|
231
|
+
assert another_artifacts.logs is not None
|
232
|
+
assert another_artifacts.logs.cached
|
233
|
+
|
234
|
+
|
235
|
+
async def test_run_caches_intermediate_digest_if_dest_changes_and_cache_transient(
|
236
|
+
cleandir: pathlib.Path,
|
237
|
+
dependency_cache: DependencyCache,
|
238
|
+
sandbox: SandboxBase,
|
239
|
+
file_cacher: FileCacher,
|
240
|
+
):
|
241
|
+
async def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
|
242
|
+
executable = DigestOrSource.create(file_cacher.put_file_text('print(5)'))
|
243
|
+
artifacts = GradingArtifacts()
|
244
|
+
artifacts.inputs.append(
|
245
|
+
GradingFileInput(**executable.expand(), dest=pathlib.Path('executable.py'))
|
246
|
+
)
|
247
|
+
artifacts.outputs.append(
|
248
|
+
GradingFileOutput(src=pathlib.Path('box-out.txt'), dest=dest)
|
249
|
+
)
|
250
|
+
|
251
|
+
with grading_context.cache_level(grading_context.CacheLevel.CACHE_TRANSIENTLY):
|
252
|
+
await steps_with_caching.run(
|
253
|
+
f'{sys.executable} executable.py',
|
254
|
+
params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
|
255
|
+
sandbox=sandbox,
|
256
|
+
artifacts=artifacts,
|
257
|
+
dependency_cache=dependency_cache,
|
258
|
+
)
|
259
|
+
return artifacts
|
260
|
+
|
261
|
+
artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
|
262
|
+
assert (cleandir / 'out.txt').read_text().strip() == '5'
|
263
|
+
assert artifacts.logs is not None
|
264
|
+
assert not artifacts.logs.cached
|
265
|
+
|
266
|
+
another_artifacts = await configure_and_run_with_dest(
|
267
|
+
pathlib.Path('another-out.txt')
|
268
|
+
)
|
269
|
+
assert (cleandir / 'another-out.txt').read_text().strip() == '5'
|
270
|
+
assert another_artifacts.logs is not None
|
271
|
+
assert another_artifacts.logs.cached
|
272
|
+
|
273
|
+
|
274
|
+
async def test_run_overwrites_changed_file_when_storage_value_is_changed_and_cache_transient(
|
275
|
+
cleandir: pathlib.Path,
|
276
|
+
dependency_cache: DependencyCache,
|
277
|
+
sandbox: SandboxBase,
|
278
|
+
file_cacher: FileCacher,
|
279
|
+
):
|
280
|
+
async def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
|
281
|
+
executable = DigestOrSource.create(file_cacher.put_file_text('print(5)'))
|
282
|
+
artifacts = GradingArtifacts()
|
283
|
+
artifacts.inputs.append(
|
284
|
+
GradingFileInput(**executable.expand(), dest=pathlib.Path('executable.py'))
|
285
|
+
)
|
286
|
+
artifacts.outputs.append(
|
287
|
+
GradingFileOutput(src=pathlib.Path('box-out.txt'), dest=dest)
|
288
|
+
)
|
289
|
+
with grading_context.cache_level(grading_context.CacheLevel.CACHE_TRANSIENTLY):
|
290
|
+
await steps_with_caching.run(
|
291
|
+
f'{sys.executable} executable.py',
|
292
|
+
params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
|
293
|
+
sandbox=sandbox,
|
294
|
+
artifacts=artifacts,
|
295
|
+
dependency_cache=dependency_cache,
|
296
|
+
)
|
297
|
+
return artifacts
|
298
|
+
|
299
|
+
artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
|
300
|
+
assert (cleandir / 'out.txt').read_text().strip() == '5'
|
301
|
+
assert artifacts.logs is not None
|
302
|
+
assert not artifacts.logs.cached
|
303
|
+
|
304
|
+
pathlib.Path('out.txt').write_text('42')
|
305
|
+
|
306
|
+
another_artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
|
307
|
+
assert (cleandir / 'out.txt').read_text().strip() == '5'
|
308
|
+
assert another_artifacts.logs is not None
|
309
|
+
assert another_artifacts.logs.cached
|
310
|
+
|
311
|
+
|
312
|
+
async def test_run_overwrites_changed_file_when_file_deleted_and_cache_transient(
|
313
|
+
cleandir: pathlib.Path,
|
314
|
+
dependency_cache: DependencyCache,
|
315
|
+
sandbox: SandboxBase,
|
316
|
+
file_cacher: FileCacher,
|
317
|
+
):
|
318
|
+
async def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
|
319
|
+
executable = DigestOrSource.create(file_cacher.put_file_text('print(5)'))
|
320
|
+
artifacts = GradingArtifacts()
|
321
|
+
artifacts.inputs.append(
|
322
|
+
GradingFileInput(**executable.expand(), dest=pathlib.Path('executable.py'))
|
323
|
+
)
|
324
|
+
artifacts.outputs.append(
|
325
|
+
GradingFileOutput(src=pathlib.Path('box-out.txt'), dest=dest)
|
326
|
+
)
|
327
|
+
with grading_context.cache_level(grading_context.CacheLevel.CACHE_TRANSIENTLY):
|
328
|
+
await steps_with_caching.run(
|
329
|
+
f'{sys.executable} executable.py',
|
330
|
+
params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
|
331
|
+
sandbox=sandbox,
|
332
|
+
artifacts=artifacts,
|
333
|
+
dependency_cache=dependency_cache,
|
334
|
+
)
|
335
|
+
return artifacts
|
336
|
+
|
337
|
+
artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
|
338
|
+
assert (cleandir / 'out.txt').read_text().strip() == '5'
|
339
|
+
assert artifacts.logs is not None
|
340
|
+
assert not artifacts.logs.cached
|
341
|
+
|
342
|
+
pathlib.Path('out.txt').unlink()
|
343
|
+
|
344
|
+
another_artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
|
109
345
|
assert (cleandir / 'out.txt').read_text().strip() == '5'
|
110
346
|
assert another_artifacts.logs is not None
|
111
347
|
assert another_artifacts.logs.cached
|
112
348
|
|
113
349
|
|
114
|
-
async def
|
350
|
+
async def test_run_fails_when_storage_value_is_changed_and_integrity_check_is_enabled(
|
115
351
|
cleandir: pathlib.Path,
|
116
352
|
dependency_cache: DependencyCache,
|
117
353
|
sandbox: SandboxBase,
|
@@ -142,13 +378,50 @@ async def test_run_overwrite_changed_file_with_storage_value(
|
|
142
378
|
|
143
379
|
pathlib.Path('out.txt').write_text('42')
|
144
380
|
|
381
|
+
with pytest.raises(ValueError) as exc_info:
|
382
|
+
await configure_and_run_with_dest(pathlib.Path('out.txt'))
|
383
|
+
assert 'rbx clean' in str(exc_info.value)
|
384
|
+
assert (cleandir / 'out.txt').read_text().strip() == '42'
|
385
|
+
|
386
|
+
|
387
|
+
async def test_run_evicts_and_recreates_deleted_file_with_storage_value(
|
388
|
+
cleandir: pathlib.Path,
|
389
|
+
dependency_cache: DependencyCache,
|
390
|
+
sandbox: SandboxBase,
|
391
|
+
file_cacher: FileCacher,
|
392
|
+
):
|
393
|
+
async def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
|
394
|
+
executable = DigestOrSource.create(file_cacher.put_file_text('print(5)'))
|
395
|
+
artifacts = GradingArtifacts()
|
396
|
+
artifacts.inputs.append(
|
397
|
+
GradingFileInput(**executable.expand(), dest=pathlib.Path('executable.py'))
|
398
|
+
)
|
399
|
+
artifacts.outputs.append(
|
400
|
+
GradingFileOutput(src=pathlib.Path('box-out.txt'), dest=dest)
|
401
|
+
)
|
402
|
+
await steps_with_caching.run(
|
403
|
+
f'{sys.executable} executable.py',
|
404
|
+
params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
|
405
|
+
sandbox=sandbox,
|
406
|
+
artifacts=artifacts,
|
407
|
+
dependency_cache=dependency_cache,
|
408
|
+
)
|
409
|
+
return artifacts
|
410
|
+
|
411
|
+
artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
|
412
|
+
assert (cleandir / 'out.txt').read_text().strip() == '5'
|
413
|
+
assert artifacts.logs is not None
|
414
|
+
assert not artifacts.logs.cached
|
415
|
+
|
416
|
+
pathlib.Path('out.txt').unlink()
|
417
|
+
|
145
418
|
another_artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
|
146
419
|
assert (cleandir / 'out.txt').read_text().strip() == '5'
|
147
420
|
assert another_artifacts.logs is not None
|
148
421
|
assert another_artifacts.logs.cached
|
149
422
|
|
150
423
|
|
151
|
-
async def
|
424
|
+
async def test_run_evicts_when_storage_value_deleted(
|
152
425
|
cleandir: pathlib.Path,
|
153
426
|
dependency_cache: DependencyCache,
|
154
427
|
sandbox: SandboxBase,
|
@@ -177,12 +450,15 @@ async def test_run_recreates_deleted_file_with_storage_value(
|
|
177
450
|
assert artifacts.logs is not None
|
178
451
|
assert not artifacts.logs.cached
|
179
452
|
|
180
|
-
|
453
|
+
# Delete the file from the cache
|
454
|
+
with pathlib.Path('out.txt').open('rb') as f:
|
455
|
+
digest = digest_cooperatively(f)
|
456
|
+
file_cacher.delete(digest)
|
181
457
|
|
182
458
|
another_artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
|
183
459
|
assert (cleandir / 'out.txt').read_text().strip() == '5'
|
184
460
|
assert another_artifacts.logs is not None
|
185
|
-
assert another_artifacts.logs.cached
|
461
|
+
assert not another_artifacts.logs.cached
|
186
462
|
|
187
463
|
|
188
464
|
async def test_run_overwrite_exec_bit_when_changed(
|
@@ -14,6 +14,21 @@ command_substitutions:
|
|
14
14
|
python2: python2
|
15
15
|
python3: python3
|
16
16
|
|
17
|
+
caching:
|
18
|
+
# Set the caching level.
|
19
|
+
#
|
20
|
+
# CACHE_ALL: Cache everything.
|
21
|
+
# CACHE_COMPILATION: Cache only compilation.
|
22
|
+
# NO_CACHE: Do not cache anything.
|
23
|
+
level: CACHE_ALL
|
24
|
+
|
25
|
+
# Whether to check the integrity of the cached result, and evict it
|
26
|
+
# if file has changed since it was cached.
|
27
|
+
#
|
28
|
+
# Disable for more performance, but be careful to not modify any generated
|
29
|
+
# files.
|
30
|
+
check_integrity: true
|
31
|
+
|
17
32
|
repeats:
|
18
33
|
# Number of times to run the solution.
|
19
34
|
reps: 1
|
@@ -14,6 +14,21 @@ command_substitutions:
|
|
14
14
|
python2: python2
|
15
15
|
python3: python3
|
16
16
|
|
17
|
+
caching:
|
18
|
+
# Set the caching level.
|
19
|
+
#
|
20
|
+
# CACHE_ALL: Cache everything.
|
21
|
+
# CACHE_COMPILATION: Cache only compilation.
|
22
|
+
# NO_CACHE: Do not cache anything.
|
23
|
+
level: CACHE_ALL
|
24
|
+
|
25
|
+
# Whether to check the integrity of the cached result, and evict it
|
26
|
+
# if file has changed since it was cached.
|
27
|
+
#
|
28
|
+
# Disable for more performance, but be careful to not modify any generated
|
29
|
+
# files.
|
30
|
+
check_integrity: true
|
31
|
+
|
17
32
|
repeats:
|
18
33
|
# Number of times to run the solution.
|
19
34
|
reps: 1
|
@@ -0,0 +1,67 @@
|
|
1
|
+
---
|
2
|
+
sandbox: "stupid"
|
3
|
+
defaultCompilation:
|
4
|
+
sandbox:
|
5
|
+
maxProcesses: 1000
|
6
|
+
timeLimit: 50000 # 50 seconds
|
7
|
+
wallTimeLimit: 50000 # 50 seconds
|
8
|
+
memoryLimit: 1024 # 1gb
|
9
|
+
defaultExecution:
|
10
|
+
sandbox:
|
11
|
+
# Useful for checkers, validators, etc.
|
12
|
+
timeLimit: 50000 # 50 seconds
|
13
|
+
wallTimeLimit: 50000 # 50 seconds
|
14
|
+
memoryLimit: 1024 # 1gb
|
15
|
+
languages:
|
16
|
+
- name: "cpp"
|
17
|
+
readableName: "C++20"
|
18
|
+
extension: "cpp"
|
19
|
+
compilation:
|
20
|
+
commands: ["g++ -std=c++20 -O2 -o {executable} {compilable}"]
|
21
|
+
execution:
|
22
|
+
command: "./{executable}"
|
23
|
+
fileMapping:
|
24
|
+
compilable: "compilable.cpp"
|
25
|
+
extensions:
|
26
|
+
boca:
|
27
|
+
bocaLanguage: "cc"
|
28
|
+
- name: "c"
|
29
|
+
readableName: "C"
|
30
|
+
extension: "c"
|
31
|
+
compilation:
|
32
|
+
commands: ["gcc -std=gnu11 -O2 -lm -o {executable} {compilable}"]
|
33
|
+
execution:
|
34
|
+
command: "./{executable}"
|
35
|
+
fileMapping:
|
36
|
+
compilable: "compilable.c"
|
37
|
+
- name: "py"
|
38
|
+
readableName: "Python3"
|
39
|
+
extension: "py"
|
40
|
+
execution:
|
41
|
+
command: "python3 {executable}"
|
42
|
+
fileMapping:
|
43
|
+
executable: "executable.py"
|
44
|
+
extensions:
|
45
|
+
boca:
|
46
|
+
bocaLanguage: "py3"
|
47
|
+
- name: "java"
|
48
|
+
readableName: "Java"
|
49
|
+
extension: "java"
|
50
|
+
compilation:
|
51
|
+
commands:
|
52
|
+
- "javac -Xlint -encoding UTF-8 {compilable}"
|
53
|
+
- "jar cvf {executable} @glob:*.class"
|
54
|
+
execution:
|
55
|
+
command:
|
56
|
+
"java -Xss100m -Xmx{{memory}}m -Xms{{initialMemory}}m -cp {executable}
|
57
|
+
Main"
|
58
|
+
fileMapping:
|
59
|
+
compilable: "Main.java"
|
60
|
+
executable: "Main.jar"
|
61
|
+
extensions:
|
62
|
+
boca:
|
63
|
+
languages: ["c", "cc", "java", "py3"]
|
64
|
+
flags:
|
65
|
+
c: "-O2 -lm -static"
|
66
|
+
cc: "-std=c++20 -O2 -lm -static"
|
67
|
+
preferContestLetter: true
|
@@ -1,36 +0,0 @@
|
|
1
|
-
---
|
2
|
-
sandbox: "stupid"
|
3
|
-
defaultCompilation:
|
4
|
-
sandbox:
|
5
|
-
maxProcesses: 1000
|
6
|
-
timeLimit: 10000 # 10 seconds
|
7
|
-
wallTimeLimit: 10000 # 10 seconds
|
8
|
-
memoryLimit: 1024 # 1gb
|
9
|
-
preserveEnv: true
|
10
|
-
mirrorDirs:
|
11
|
-
- "/etc"
|
12
|
-
- "/usr"
|
13
|
-
defaultExecution:
|
14
|
-
sandbox:
|
15
|
-
# Useful for checkers, validators, etc.
|
16
|
-
timeLimit: 10000 # 10 seconds
|
17
|
-
wallTimeLimit: 10000 # 10 seconds
|
18
|
-
memoryLimit: 1024 # 1gb
|
19
|
-
languages:
|
20
|
-
- name: "cpp"
|
21
|
-
readableName: "C++17"
|
22
|
-
extension: "cpp"
|
23
|
-
compilation:
|
24
|
-
commands:
|
25
|
-
- "g++ -std=c++17 -O2 -o {executable} {compilable}"
|
26
|
-
execution:
|
27
|
-
command: "./{executable}"
|
28
|
-
fileMapping:
|
29
|
-
compilable: "compilable.cpp"
|
30
|
-
- name: "py"
|
31
|
-
readableName: "Python3"
|
32
|
-
extension: "py"
|
33
|
-
execution:
|
34
|
-
command: "python3 {executable}"
|
35
|
-
fileMapping:
|
36
|
-
executable: "executable.py"
|
File without changes
|