rbx.cp 0.13.3__tar.gz → 0.13.4__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.13.3 → rbx_cp-0.13.4}/PKG-INFO +2 -1
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/pyproject.toml +3 -1
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/annotations.py +5 -5
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/checkers.py +24 -13
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/cli.py +1 -4
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/contest/build_contest_statements.py +16 -3
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/contest/schema.py +1 -2
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/fields.py +25 -1
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/generators.py +5 -2
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/global_package.py +5 -1
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/header.py +19 -11
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/package.py +3 -1
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/presets/__init__.py +2 -2
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/schema.py +4 -25
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/statements/build_statements.py +5 -1
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/statements/builders.py +7 -7
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/statements/schema.py +11 -2
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/testcase_utils.py +2 -0
- rbx_cp-0.13.4/rbx/box/testing/testing_package.py +241 -0
- rbx_cp-0.13.4/rbx/box/testing/testing_preset.py +36 -0
- rbx_cp-0.13.4/rbx/box/testing/testing_shared.py +81 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/validators.py +2 -1
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/caching.py +3 -2
- rbx_cp-0.13.4/rbx/grading/judge/sandboxes/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/shared/contest_template.rbx.tex +1 -1
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/shared/problem_template.rbx.tex +5 -1
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/testing_utils.py +1 -1
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/utils.py +8 -0
- rbx_cp-0.13.3/rbx/box/conftest.py +0 -42
- rbx_cp-0.13.3/rbx/box/generators_test.py +0 -67
- rbx_cp-0.13.3/rbx/box/lazy_importing_test.py +0 -25
- rbx_cp-0.13.3/rbx/box/solutions_test.py +0 -47
- rbx_cp-0.13.3/rbx/box/validators_test.py +0 -15
- rbx_cp-0.13.3/rbx/checker.py +0 -128
- rbx_cp-0.13.3/rbx/clone.py +0 -197
- rbx_cp-0.13.3/rbx/conftest.py +0 -38
- rbx_cp-0.13.3/rbx/create.py +0 -37
- rbx_cp-0.13.3/rbx/edit.py +0 -24
- rbx_cp-0.13.3/rbx/grading/conftest.py +0 -33
- rbx_cp-0.13.3/rbx/grading/steps_with_caching_run_test.py +0 -707
- rbx_cp-0.13.3/rbx/grading_utils.py +0 -148
- rbx_cp-0.13.3/rbx/hydration.py +0 -101
- rbx_cp-0.13.3/rbx/main.py +0 -118
- rbx_cp-0.13.3/rbx/metadata.py +0 -105
- rbx_cp-0.13.3/rbx/run.py +0 -45
- rbx_cp-0.13.3/rbx/schema.py +0 -64
- rbx_cp-0.13.3/rbx/submit.py +0 -61
- rbx_cp-0.13.3/rbx/test.py +0 -349
- rbx_cp-0.13.3/rbx/testcase.py +0 -70
- rbx_cp-0.13.3/rbx/testcase_rendering.py +0 -79
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/LICENSE +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/README.md +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/autoenum.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/builder.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/cd.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/code.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/compile.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/contest/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/contest/contest_package.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/contest/contest_utils.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/contest/main.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/contest/statements.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/creation.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/deferred.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/download.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/dump_schemas.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/environment.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/extensions.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/formatting.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/git_utils.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/lang.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/lazy_importing_main.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/linting.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/main.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/naming.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/boca/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/boca/extension.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/boca/packager.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/contest_main.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/importer.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/main.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/moj/packager.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/packager.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/pkg/packager.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/polygon/importer.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/polygon/packager.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/polygon/polygon_api.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/polygon/test.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/polygon/upload.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/packaging/polygon/xml_schema.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/presets/fetch.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/presets/lock_schema.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/presets/schema.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/remote.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/retries.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/sanitizers/warning_stack.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/setter_config.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/solutions.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/state.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/statements/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/statements/expander.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/statements/joiners.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/statements/latex.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/statements/latex_jinja.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/stats.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/stresses.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/stressing/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/stressing/finder_parser.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/stressing/generator_parser.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/tasks.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/testcase_extractors.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/testcases/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/testcases/main.py +0 -0
- {rbx_cp-0.13.3/rbx/box/tooling → rbx_cp-0.13.4/rbx/box/testing}/__init__.py +0 -0
- {rbx_cp-0.13.3/rbx/box/tooling/boca → rbx_cp-0.13.4/rbx/box/tooling}/__init__.py +0 -0
- {rbx_cp-0.13.3/rbx/box/ui → rbx_cp-0.13.4/rbx/box/tooling/boca}/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/tooling/boca/main.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/tooling/boca/scrape.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/tooling/boca/scraper.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/tooling/converter.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/tooling/main.py +0 -0
- {rbx_cp-0.13.3/rbx/box/ui/screens → rbx_cp-0.13.4/rbx/box/ui}/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/captured_log.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/css/app.tcss +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/main.py +0 -0
- {rbx_cp-0.13.3/rbx/box/ui/utils → rbx_cp-0.13.4/rbx/box/ui/screens}/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/screens/build.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/screens/command.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/screens/differ.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/screens/error.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/screens/rich_log_modal.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/screens/run.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/screens/run_explorer.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/screens/run_test_explorer.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/screens/selector.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/screens/test_explorer.py +0 -0
- {rbx_cp-0.13.3/rbx/box/ui/widgets → rbx_cp-0.13.4/rbx/box/ui/utils}/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/utils/run_ui.py +0 -0
- {rbx_cp-0.13.3/rbx/grading → rbx_cp-0.13.4/rbx/box/ui/widgets}/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/widgets/diff_box.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/widgets/file_log.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/widgets/interaction_box.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/widgets/rich_log_box.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/widgets/test_output_box.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/ui/widgets/two_sided_test_output_box.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/box/unit.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/config.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/console.py +0 -0
- {rbx_cp-0.13.3/rbx/grading/judge → rbx_cp-0.13.4/rbx/grading}/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/debug_context.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/grading_context.py +0 -0
- {rbx_cp-0.13.3/rbx/grading/judge/sandboxes → rbx_cp-0.13.4/rbx/grading/judge}/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/judge/cacher.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/judge/digester.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/judge/sandbox.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/judge/sandboxes/isolate.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/judge/sandboxes/stupid_sandbox.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/judge/sandboxes/timeit.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/judge/storage.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/judge/test.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/judge/testiso.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/limits.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/processing_context.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/profiling.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/steps.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/grading/steps_with_caching.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/providers/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/providers/codeforces.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/providers/provider.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/checkers/boilerplate.cpp +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/checkers/noop.cpp +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/default_config.json +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/default_setter_config.mac.yml +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/default_setter_config.yml +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/envs/default.rbx.yml +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/envs/isolate.rbx.yml +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/checker.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/compare.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/compile/c +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/compile/cc +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/compile/cpp +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/compile/java +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/compile/kt +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/compile/py2 +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/compile/py3 +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/interactive/c +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/interactive/cc +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/interactive/cpp +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/interactive/java +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/interactive/kt +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/interactive/py2 +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/interactive/py3 +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/interactor_compile.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/interactor_run.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/run/bkp +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/run/c +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/run/cc +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/run/cpp +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/run/java +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/run/kt +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/run/py2 +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/run/py3 +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/safeexec.c +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/boca/safeexec_compile.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/c/compile.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/c/prep.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/c/run.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/compare.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/cpp/compile.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/cpp/prep.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/cpp/run.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/interactor_prep.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/interactor_run.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/java/compile.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/java/prep.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/java/run.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/py2/compile.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/py2/prep.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/py2/run.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/py3/compile.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/py3/prep.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/packagers/moj/scripts/py3/run.sh +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/contest/.gitignore +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/contest/contest.rbx.yml +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/contest/statement/contest.rbx.tex +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/contest/statement/instructions.tex +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/contest/statement/logo.png +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/env.rbx.yml +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/preset.rbx.yml +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/problem/.gitignore +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/problem/gens/gen.cpp +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/problem/manual_tests/samples/000.in +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/problem/manual_tests/samples/001.in +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/problem/problem.rbx.yml +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/problem/rbx.h +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/problem/sols/main.cpp +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/problem/sols/slow.cpp +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/problem/sols/wa.cpp +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/problem/statement/statement.rbx.tex +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/problem/testplan/random.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/problem/testplan/random.txt +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/problem/validator.cpp +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/problem/wcmp.cpp +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/presets/default/shared/icpc.sty +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/templates/rbx.h +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/resources/templates/template.cpp +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/submitors/__init__.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/submitors/codeforces.py +0 -0
- {rbx_cp-0.13.3 → rbx_cp-0.13.4}/rbx/submitors/submitor.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: rbx.cp
|
3
|
-
Version: 0.13.
|
3
|
+
Version: 0.13.4
|
4
4
|
Summary:
|
5
5
|
Author: Roberto Sales
|
6
6
|
Requires-Python: >=3.9.1,<4.0.0
|
@@ -40,6 +40,7 @@ Requires-Dist: requests (>=2.32.3,<3.0.0)
|
|
40
40
|
Requires-Dist: rich (>=13.9.4,<14.0.0)
|
41
41
|
Requires-Dist: ruamel-yaml (>=0.18.14,<0.19.0)
|
42
42
|
Requires-Dist: ruyaml (>=0.91.0,<0.92.0)
|
43
|
+
Requires-Dist: sqlitedict (>=2.1.0,<3.0.0)
|
43
44
|
Requires-Dist: syncer (>=2.0.3,<3.0.0)
|
44
45
|
Requires-Dist: textual (>=3.1.1,<4.0.0)
|
45
46
|
Requires-Dist: textual-serve (>=1.1.2,<2.0.0)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "rbx.cp"
|
3
|
-
version = "0.13.
|
3
|
+
version = "0.13.4"
|
4
4
|
description = ""
|
5
5
|
packages = [
|
6
6
|
{include = "rbx"}
|
@@ -49,6 +49,7 @@ ordered-set = "^4.1.0"
|
|
49
49
|
gitignore-parser = "^0.1.12"
|
50
50
|
pypandoc = "^1.15"
|
51
51
|
iso639-lang = "^2.6.1"
|
52
|
+
sqlitedict = "^2.1.0"
|
52
53
|
|
53
54
|
[tool.poetry.scripts]
|
54
55
|
rbc = "rbx.main:app"
|
@@ -70,6 +71,7 @@ textual-dev = "^1.6.1"
|
|
70
71
|
pytest-asyncio = "^0.26.0"
|
71
72
|
mkdocs-gen-files = "^0.5.0"
|
72
73
|
markdown-grid-tables = "^0.5.0"
|
74
|
+
pytest-xdist = "^3.8.0"
|
73
75
|
|
74
76
|
|
75
77
|
[tool.commitizen]
|
@@ -7,7 +7,7 @@ import typer
|
|
7
7
|
import typer.core
|
8
8
|
from typing_extensions import Annotated
|
9
9
|
|
10
|
-
from rbx import config
|
10
|
+
from rbx import config
|
11
11
|
from rbx.config import get_config
|
12
12
|
|
13
13
|
|
@@ -21,10 +21,10 @@ def _get_language_default():
|
|
21
21
|
|
22
22
|
def _get_problem_options():
|
23
23
|
options = set()
|
24
|
-
all_problems = metadata.find_problems()
|
25
|
-
for problem in all_problems:
|
26
|
-
|
27
|
-
|
24
|
+
# all_problems = metadata.find_problems()
|
25
|
+
# for problem in all_problems:
|
26
|
+
# options.add(problem.code)
|
27
|
+
# options.update(problem.aliases)
|
28
28
|
return sorted(options)
|
29
29
|
|
30
30
|
|
@@ -5,8 +5,7 @@ from typing import List, Optional
|
|
5
5
|
import typer
|
6
6
|
|
7
7
|
from rbx import console
|
8
|
-
from rbx.box import package
|
9
|
-
from rbx.box.code import SanitizationLevel, compile_item, run_item
|
8
|
+
from rbx.box import code, package
|
10
9
|
from rbx.box.schema import Testcase
|
11
10
|
from rbx.grading.judge.sandbox import SandboxBase
|
12
11
|
from rbx.grading.steps import (
|
@@ -28,7 +27,7 @@ def compile_checker(progress: Optional[StatusProgress] = None) -> str:
|
|
28
27
|
progress.update('Compiling checker...')
|
29
28
|
|
30
29
|
try:
|
31
|
-
digest = compile_item(checker, sanitized=SanitizationLevel.PREFER)
|
30
|
+
digest = code.compile_item(checker, sanitized=code.SanitizationLevel.PREFER)
|
32
31
|
except Exception as e:
|
33
32
|
console.console.print('[error]Failed compiling checker[/error]')
|
34
33
|
raise typer.Exit(1) from e
|
@@ -46,7 +45,7 @@ def compile_interactor(progress: Optional[StatusProgress] = None) -> str:
|
|
46
45
|
progress.update('Compiling interactor...')
|
47
46
|
|
48
47
|
try:
|
49
|
-
digest = compile_item(interactor, sanitized=SanitizationLevel.PREFER)
|
48
|
+
digest = code.compile_item(interactor, sanitized=code.SanitizationLevel.PREFER)
|
50
49
|
except Exception as e:
|
51
50
|
console.console.print('[error]Failed compiling interactor.[/error]')
|
52
51
|
raise typer.Exit(1) from e
|
@@ -164,6 +163,14 @@ def process_checker_run_log(
|
|
164
163
|
|
165
164
|
if checker_run_log is None:
|
166
165
|
return CheckerResult(outcome=Outcome.INTERNAL_ERROR)
|
166
|
+
if checker_run_log.exitstatus not in [
|
167
|
+
SandboxBase.EXIT_OK,
|
168
|
+
SandboxBase.EXIT_NONZERO_RETURN,
|
169
|
+
]:
|
170
|
+
return CheckerResult(
|
171
|
+
outcome=Outcome.JUDGE_FAILED,
|
172
|
+
message=f'checker failed with exit status {checker_run_log.exitstatus}: {message}',
|
173
|
+
)
|
167
174
|
if not _is_checker_exitcode(checker_run_log.exitcode):
|
168
175
|
return CheckerResult(
|
169
176
|
outcome=Outcome.JUDGE_FAILED,
|
@@ -196,13 +203,17 @@ async def _check(
|
|
196
203
|
if result.outcome != Outcome.ACCEPTED:
|
197
204
|
return _convert_tle(result, run_log)
|
198
205
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
+
if (
|
207
|
+
run_log is not None
|
208
|
+
and run_log.metadata is not None
|
209
|
+
and run_log.metadata.limits.output is not None
|
210
|
+
):
|
211
|
+
output_size = program_output.stat().st_size
|
212
|
+
if output_size > run_log.metadata.limits.output * 1024:
|
213
|
+
return CheckerResult(
|
214
|
+
outcome=Outcome.OUTPUT_LIMIT_EXCEEDED,
|
215
|
+
message=f'Output size {run_log.metadata.limits.output}kb, limit is {output_size // 1024}kb.',
|
216
|
+
)
|
206
217
|
|
207
218
|
error = DigestHolder()
|
208
219
|
inputs = [
|
@@ -219,14 +230,14 @@ async def _check(
|
|
219
230
|
dest=pathlib.PosixPath('output.txt'),
|
220
231
|
),
|
221
232
|
]
|
222
|
-
checker_run_log = await run_item(
|
233
|
+
checker_run_log = await code.run_item(
|
223
234
|
package.get_checker(),
|
224
235
|
DigestOrSource.create(checker_digest),
|
225
236
|
stderr=DigestOrDest.create(error),
|
226
237
|
inputs=inputs,
|
227
238
|
extra_args='input.txt output.txt expected.txt',
|
228
239
|
)
|
229
|
-
message = package.get_digest_as_string(error.value
|
240
|
+
message = package.get_digest_as_string(error.value) or ''
|
230
241
|
|
231
242
|
processed_checker_result = process_checker_run_log(checker_run_log, message)
|
232
243
|
if processed_checker_result.outcome == Outcome.INTERNAL_ERROR:
|
@@ -128,7 +128,6 @@ def main(
|
|
128
128
|
capture: bool = typer.Option(
|
129
129
|
True,
|
130
130
|
'--nocapture',
|
131
|
-
flag_value=False,
|
132
131
|
help='Whether to save extra logs and outputs from interactive solutions.',
|
133
132
|
),
|
134
133
|
profile: bool = typer.Option(
|
@@ -259,7 +258,6 @@ async def run(
|
|
259
258
|
check: bool = typer.Option(
|
260
259
|
True,
|
261
260
|
'--nocheck',
|
262
|
-
flag_value=False,
|
263
261
|
help='Whether to not build outputs for tests and run checker.',
|
264
262
|
),
|
265
263
|
detailed: bool = typer.Option(
|
@@ -288,6 +286,7 @@ async def run(
|
|
288
286
|
help='Whether to pick solutions interactively.',
|
289
287
|
),
|
290
288
|
):
|
289
|
+
console.console.log(check)
|
291
290
|
main_solution = package.get_main_solution()
|
292
291
|
if check and main_solution is None:
|
293
292
|
console.console.print(
|
@@ -432,7 +431,6 @@ async def time(
|
|
432
431
|
check: bool = typer.Option(
|
433
432
|
True,
|
434
433
|
'--nocheck',
|
435
|
-
flag_value=False,
|
436
434
|
help='Whether to not build outputs for tests and run checker.',
|
437
435
|
),
|
438
436
|
detailed: bool = typer.Option(
|
@@ -488,7 +486,6 @@ async def irun(
|
|
488
486
|
check: bool = typer.Option(
|
489
487
|
True,
|
490
488
|
'--nocheck',
|
491
|
-
flag_value=False,
|
492
489
|
help='Whether to not build outputs for tests and run checker.',
|
493
490
|
),
|
494
491
|
generator: Optional[str] = typer.Option(
|
@@ -10,6 +10,7 @@ from rbx import console, testing_utils, utils
|
|
10
10
|
from rbx.box import cd, package
|
11
11
|
from rbx.box.contest.contest_package import get_problems
|
12
12
|
from rbx.box.contest.schema import Contest, ContestProblem, ContestStatement
|
13
|
+
from rbx.box.fields import Primitive
|
13
14
|
from rbx.box.formatting import href
|
14
15
|
from rbx.box.schema import Package, Testcase
|
15
16
|
from rbx.box.statements import build_statements, latex
|
@@ -72,14 +73,21 @@ def get_statement_builder_problems(
|
|
72
73
|
|
73
74
|
|
74
75
|
def get_statement_builder_contest(
|
76
|
+
contest: Contest,
|
75
77
|
statement: ContestStatement,
|
76
78
|
extracted_problems: List[ExtractedProblem],
|
79
|
+
custom_vars: Optional[Dict[str, Primitive]] = None,
|
77
80
|
) -> StatementBuilderContest:
|
78
81
|
return StatementBuilderContest(
|
79
82
|
title=statement.title,
|
80
83
|
location=statement.location,
|
81
84
|
date=statement.date,
|
82
85
|
problems=get_statement_builder_problems(extracted_problems),
|
86
|
+
vars={
|
87
|
+
**contest.expanded_vars,
|
88
|
+
**statement.expanded_vars,
|
89
|
+
**(custom_vars or {}),
|
90
|
+
},
|
83
91
|
)
|
84
92
|
|
85
93
|
|
@@ -241,10 +249,13 @@ def build_contest_only(
|
|
241
249
|
languages=get_environment_languages_for_statement(),
|
242
250
|
params=params,
|
243
251
|
root=pathlib.Path(td),
|
252
|
+
),
|
253
|
+
item=get_statement_builder_contest(
|
254
|
+
contest,
|
255
|
+
statement,
|
256
|
+
extracted_problems,
|
244
257
|
custom_vars=custom_vars,
|
245
|
-
vars={**contest.expanded_vars, **statement.expanded_vars},
|
246
258
|
),
|
247
|
-
item=get_statement_builder_contest(statement, extracted_problems),
|
248
259
|
verbose=False,
|
249
260
|
)
|
250
261
|
|
@@ -326,7 +337,9 @@ def build_statement_rooted(
|
|
326
337
|
last_content = joiner.build(
|
327
338
|
last_content,
|
328
339
|
context=joiner_context,
|
329
|
-
contest=get_statement_builder_contest(
|
340
|
+
contest=get_statement_builder_contest(
|
341
|
+
contest, statement, extracted_problems, custom_vars=custom_vars
|
342
|
+
),
|
330
343
|
)
|
331
344
|
last_output = joiner.output_type()
|
332
345
|
|
@@ -3,8 +3,7 @@ from typing import Annotated, Dict, List, Optional
|
|
3
3
|
|
4
4
|
from pydantic import AfterValidator, BaseModel, ConfigDict, Field, model_validator
|
5
5
|
|
6
|
-
from rbx.box.fields import FNameField, NameField
|
7
|
-
from rbx.box.schema import Primitive, expand_var
|
6
|
+
from rbx.box.fields import FNameField, NameField, Primitive, expand_var
|
8
7
|
from rbx.box.statements.expander import expand_statements
|
9
8
|
from rbx.box.statements.schema import (
|
10
9
|
ConversionStep,
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import TypeVar
|
1
|
+
from typing import Dict, TypeVar, Union
|
2
2
|
|
3
3
|
from deepmerge import always_merger
|
4
4
|
from pydantic import BaseModel, Field
|
@@ -33,3 +33,27 @@ def merge_pydantic_models(base: T, nxt: T) -> T:
|
|
33
33
|
nxt_dict = nxt.model_dump(exclude_unset=True)
|
34
34
|
merged_dict = always_merger.merge(base_dict, nxt_dict)
|
35
35
|
return base.model_validate(merged_dict)
|
36
|
+
|
37
|
+
|
38
|
+
Primitive = Union[str, int, float, bool]
|
39
|
+
|
40
|
+
|
41
|
+
def expand_var(value: Primitive) -> Primitive:
|
42
|
+
if not isinstance(value, str):
|
43
|
+
return value
|
44
|
+
if value.startswith('\\'):
|
45
|
+
return value[1:]
|
46
|
+
if not value.startswith('py`') or not value.endswith('`'):
|
47
|
+
return value
|
48
|
+
res = eval(value[3:-1])
|
49
|
+
for supported_type in [str, int, float, bool]:
|
50
|
+
if isinstance(res, supported_type):
|
51
|
+
return res
|
52
|
+
|
53
|
+
raise TypeError(
|
54
|
+
f'Variable with backticks should evaluate to a primitive Python type: {value}'
|
55
|
+
)
|
56
|
+
|
57
|
+
|
58
|
+
def expand_vars(vars: Dict[str, Primitive]) -> Dict[str, Primitive]:
|
59
|
+
return {key: expand_var(value) for key, value in vars.items()}
|
@@ -63,13 +63,16 @@ def _warn_about_crlf(path: pathlib.Path):
|
|
63
63
|
|
64
64
|
|
65
65
|
def _check_crlf(path: pathlib.Path):
|
66
|
+
should_fix = False
|
66
67
|
with open(path, 'rb') as f:
|
67
68
|
for line in f:
|
68
|
-
if line.endswith(b'\r\n')
|
69
|
+
if line.endswith(b'\r\n'):
|
69
70
|
_warn_about_crlf(path)
|
71
|
+
should_fix = True
|
70
72
|
break
|
71
73
|
|
72
|
-
|
74
|
+
if should_fix:
|
75
|
+
path.write_text('\n'.join(path.read_text().splitlines()) + '\n')
|
73
76
|
|
74
77
|
|
75
78
|
def _copy_testcase_over(
|
@@ -29,9 +29,13 @@ def is_cache_valid(cache_dir: pathlib.Path) -> bool:
|
|
29
29
|
return True
|
30
30
|
|
31
31
|
|
32
|
+
def get_global_cache_dir_path() -> pathlib.Path:
|
33
|
+
return get_app_path() / '.box'
|
34
|
+
|
35
|
+
|
32
36
|
@functools.cache
|
33
37
|
def get_global_cache_dir() -> pathlib.Path:
|
34
|
-
cache_dir =
|
38
|
+
cache_dir = get_global_cache_dir_path()
|
35
39
|
cache_dir.mkdir(parents=True, exist_ok=True)
|
36
40
|
fingerprint_file = cache_dir / 'fingerprint'
|
37
41
|
if not fingerprint_file.is_file():
|
@@ -1,11 +1,12 @@
|
|
1
1
|
import functools
|
2
2
|
import importlib
|
3
3
|
import importlib.resources
|
4
|
+
import json
|
4
5
|
import pathlib
|
5
6
|
from typing import Callable, Dict, Type
|
6
7
|
|
7
8
|
from rbx.box import package
|
8
|
-
from rbx.box.
|
9
|
+
from rbx.box.fields import Primitive
|
9
10
|
|
10
11
|
|
11
12
|
@functools.cache
|
@@ -40,12 +41,21 @@ def _preprocess_header(header: str) -> str:
|
|
40
41
|
)
|
41
42
|
|
42
43
|
|
44
|
+
def _string_repr(s):
|
45
|
+
return json.dumps(s)
|
46
|
+
|
47
|
+
|
43
48
|
def _get_string_var_block() -> str:
|
44
|
-
return _get_var_block(_get_vars_of_type(str,
|
49
|
+
return _get_var_block(_get_vars_of_type(str, _string_repr))
|
45
50
|
|
46
51
|
|
47
52
|
def _get_int_var_block() -> str:
|
48
|
-
|
53
|
+
def _transform(x: Primitive) -> str:
|
54
|
+
if isinstance(x, bool):
|
55
|
+
return str(int(x))
|
56
|
+
return str(x)
|
57
|
+
|
58
|
+
return _get_var_block(_get_vars_of_type(int, _transform))
|
49
59
|
|
50
60
|
|
51
61
|
def _get_float_var_block() -> str:
|
@@ -56,16 +66,14 @@ def _get_bool_var_block() -> str:
|
|
56
66
|
return _get_var_block(_get_vars_of_type(bool, lambda x: 'true' if x else 'false'))
|
57
67
|
|
58
68
|
|
59
|
-
def _get_vars_of_type(
|
60
|
-
type: Type, transform: Callable[[Primitive], str]
|
61
|
-
) -> Dict[str, str]:
|
69
|
+
def _get_vars_of_type(t: Type, transform: Callable[[Primitive], str]) -> Dict[str, str]:
|
62
70
|
pkg = package.find_problem_package_or_die()
|
63
71
|
vars = pkg.expanded_vars
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
}
|
72
|
+
|
73
|
+
def is_valid(value: Primitive) -> bool:
|
74
|
+
return isinstance(value, t)
|
75
|
+
|
76
|
+
return {name: transform(value) for name, value in vars.items() if is_valid(value)}
|
69
77
|
|
70
78
|
|
71
79
|
def _get_var_block(mappings: Dict[str, str]) -> str:
|
@@ -181,8 +181,10 @@ def get_file_cacher(root: pathlib.Path = pathlib.Path()) -> FileCacher:
|
|
181
181
|
|
182
182
|
@functools.cache
|
183
183
|
def get_digest_as_string(
|
184
|
-
digest: str, root: pathlib.Path = pathlib.Path()
|
184
|
+
digest: Optional[str], root: pathlib.Path = pathlib.Path()
|
185
185
|
) -> Optional[str]:
|
186
|
+
if not digest:
|
187
|
+
return None
|
186
188
|
cacher = get_file_cacher(root)
|
187
189
|
try:
|
188
190
|
content = cacher.get_file_content(digest)
|
@@ -339,9 +339,9 @@ def _copy_preset_file(
|
|
339
339
|
|
340
340
|
# The symlink points somewhere inside the preset folder, fix the symlink.
|
341
341
|
dst_absolute_path = utils.abspath(dst)
|
342
|
-
fixed_target_relative_path =
|
342
|
+
fixed_target_relative_path = utils.relpath(
|
343
|
+
target_absolute_path,
|
343
344
|
dst_absolute_path.parent,
|
344
|
-
walk_up=True,
|
345
345
|
)
|
346
346
|
dst.symlink_to(fixed_target_relative_path)
|
347
347
|
|
@@ -3,19 +3,17 @@ from __future__ import annotations
|
|
3
3
|
import os
|
4
4
|
import pathlib
|
5
5
|
import re
|
6
|
-
from typing import Annotated, Any, Dict, List, Optional
|
6
|
+
from typing import Annotated, Any, Dict, List, Optional
|
7
7
|
|
8
8
|
from pydantic import AfterValidator, BaseModel, ConfigDict, Field, model_validator
|
9
9
|
from pydantic_core import PydanticCustomError
|
10
10
|
|
11
11
|
from rbx.autoenum import AutoEnum, alias
|
12
|
-
from rbx.box.fields import NameField
|
12
|
+
from rbx.box.fields import NameField, Primitive, expand_vars
|
13
13
|
from rbx.box.statements.expander import expand_statements
|
14
14
|
from rbx.box.statements.schema import Statement
|
15
15
|
from rbx.grading.steps import Outcome
|
16
16
|
|
17
|
-
Primitive = Union[str, int, float, bool]
|
18
|
-
|
19
17
|
|
20
18
|
def _check_oneof(model_obj: BaseModel, fields: List[str]):
|
21
19
|
has = []
|
@@ -30,27 +28,6 @@ def _check_oneof(model_obj: BaseModel, fields: List[str]):
|
|
30
28
|
)
|
31
29
|
|
32
30
|
|
33
|
-
def expand_var(value: Primitive) -> Primitive:
|
34
|
-
if not isinstance(value, str):
|
35
|
-
return value
|
36
|
-
if value.startswith('\\'):
|
37
|
-
return value[1:]
|
38
|
-
if not value.startswith('py`') or not value.endswith('`'):
|
39
|
-
return value
|
40
|
-
res = eval(value[3:-1])
|
41
|
-
for supported_type in [str, int, float, bool]:
|
42
|
-
if isinstance(res, supported_type):
|
43
|
-
return res
|
44
|
-
|
45
|
-
raise TypeError(
|
46
|
-
f'Variable with backticks should evaluate to a primitive Python type: {value}'
|
47
|
-
)
|
48
|
-
|
49
|
-
|
50
|
-
def expand_vars(vars: Dict[str, Primitive]) -> Dict[str, Primitive]:
|
51
|
-
return {key: expand_var(value) for key, value in vars.items()}
|
52
|
-
|
53
|
-
|
54
31
|
def _represents_int(s: str) -> bool:
|
55
32
|
return re.match(r'[-+]?\d+$', s.strip()) is not None
|
56
33
|
|
@@ -245,6 +222,8 @@ Whether this interactor is a legacy interactor and needs a checker to be specifi
|
|
245
222
|
|
246
223
|
|
247
224
|
class Testcase(BaseModel):
|
225
|
+
__test__ = False
|
226
|
+
|
248
227
|
model_config = ConfigDict(extra='forbid')
|
249
228
|
|
250
229
|
inputPath: pathlib.Path = Field(description="""The path of the input file.""")
|
@@ -262,7 +262,6 @@ def build_statement_bytes(
|
|
262
262
|
languages=get_environment_languages_for_statement(),
|
263
263
|
params=params,
|
264
264
|
root=pathlib.Path(td),
|
265
|
-
custom_vars=custom_vars,
|
266
265
|
),
|
267
266
|
item=StatementBuilderProblem(
|
268
267
|
package=pkg,
|
@@ -271,6 +270,11 @@ def build_statement_bytes(
|
|
271
270
|
get_samples() if use_samples else []
|
272
271
|
),
|
273
272
|
short_name=short_name,
|
273
|
+
vars={
|
274
|
+
**pkg.expanded_vars,
|
275
|
+
**statement.expanded_vars,
|
276
|
+
**(custom_vars or {}),
|
277
|
+
},
|
274
278
|
),
|
275
279
|
verbose=False,
|
276
280
|
)
|
@@ -11,7 +11,8 @@ import typer
|
|
11
11
|
from pydantic import BaseModel
|
12
12
|
|
13
13
|
from rbx import console, utils
|
14
|
-
from rbx.box.
|
14
|
+
from rbx.box.fields import Primitive
|
15
|
+
from rbx.box.schema import Package, Testcase
|
15
16
|
from rbx.box.statements.latex_jinja import (
|
16
17
|
JinjaDictWrapper,
|
17
18
|
render_latex_template,
|
@@ -48,8 +49,6 @@ class StatementBuilderContext:
|
|
48
49
|
languages: List[StatementCodeLanguage]
|
49
50
|
params: ConversionStep
|
50
51
|
root: pathlib.Path
|
51
|
-
custom_vars: Optional[Dict[str, Any]] = None
|
52
|
-
vars: Optional[Dict[str, Primitive]] = None
|
53
52
|
|
54
53
|
def build_jinja_kwargs(self) -> Dict[str, Any]:
|
55
54
|
res = {
|
@@ -57,9 +56,6 @@ class StatementBuilderContext:
|
|
57
56
|
'languages': self.languages,
|
58
57
|
'keyed_languages': {lang.id: lang for lang in self.languages},
|
59
58
|
}
|
60
|
-
if self.vars is not None or self.custom_vars is not None:
|
61
|
-
res['vars'] = self.vars or {}
|
62
|
-
res['vars'].update(self.custom_vars or {})
|
63
59
|
return res
|
64
60
|
|
65
61
|
|
@@ -125,12 +121,14 @@ class StatementBuilderProblem(StatementBuilderItem):
|
|
125
121
|
# Will only be filled by contests.
|
126
122
|
io_path: Optional[pathlib.Path] = None
|
127
123
|
|
124
|
+
vars: Optional[Dict[str, Primitive]] = None
|
125
|
+
|
128
126
|
def build_inner_jinja_kwargs(self) -> Dict[str, Any]:
|
129
127
|
kwargs = {
|
130
128
|
'package': self.package,
|
131
129
|
'statement': self.statement,
|
132
130
|
'samples': self.samples,
|
133
|
-
'vars': JinjaDictWrapper(self.
|
131
|
+
'vars': JinjaDictWrapper(self.vars or {}, key='vars'),
|
134
132
|
'title': self.statement.title or self.package.name,
|
135
133
|
}
|
136
134
|
if self.short_name is not None:
|
@@ -152,6 +150,7 @@ class StatementBuilderContest(StatementBuilderItem):
|
|
152
150
|
location: Optional[str] = None
|
153
151
|
date: Optional[str] = None
|
154
152
|
problems: List[StatementBuilderProblem] = dataclasses.field(default_factory=list)
|
153
|
+
vars: Optional[Dict[str, Primitive]] = None
|
155
154
|
|
156
155
|
def build_inner_jinja_kwargs(self) -> Dict[str, Any]:
|
157
156
|
res = {'title': self.title}
|
@@ -167,6 +166,7 @@ class StatementBuilderContest(StatementBuilderItem):
|
|
167
166
|
'problems': [
|
168
167
|
problem.build_inner_jinja_kwargs() for problem in self.problems
|
169
168
|
],
|
169
|
+
'vars': JinjaDictWrapper(self.vars or {}, key='vars'),
|
170
170
|
}
|
171
171
|
return res
|
172
172
|
|
@@ -2,12 +2,12 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import pathlib
|
4
4
|
from enum import Enum
|
5
|
-
from typing import Annotated, List, Literal, Optional, Union
|
5
|
+
from typing import Annotated, Dict, List, Literal, Optional, Union
|
6
6
|
|
7
7
|
from pydantic import AfterValidator, BaseModel, ConfigDict, Field
|
8
8
|
|
9
9
|
from rbx.autoenum import AutoEnum, alias
|
10
|
-
from rbx.box.fields import FNameField
|
10
|
+
from rbx.box.fields import FNameField, Primitive, expand_var
|
11
11
|
from rbx.box.lang import is_valid_lang_code
|
12
12
|
|
13
13
|
|
@@ -175,3 +175,12 @@ the statement. Files will be included in the same folder as the statement file,
|
|
175
175
|
their relativeness. Can be glob pattern as well, such as `imgs/*.png`.
|
176
176
|
""",
|
177
177
|
)
|
178
|
+
|
179
|
+
vars: Dict[str, Primitive] = Field(
|
180
|
+
default={},
|
181
|
+
description='Variables to be used in the statement.',
|
182
|
+
)
|
183
|
+
|
184
|
+
@property
|
185
|
+
def expanded_vars(self) -> Dict[str, Primitive]:
|
186
|
+
return {key: expand_var(value) for key, value in self.vars.items()}
|