rbx.cp 0.11.2__tar.gz → 0.12.0__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.11.2 → rbx_cp-0.12.0}/PKG-INFO +1 -1
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/pyproject.toml +1 -1
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/builder.py +3 -3
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/contest/build_contest_statements.py +5 -6
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/contest/statements.py +0 -1
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/generators.py +54 -12
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/package.py +56 -4
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/packaging/polygon/upload.py +2 -3
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/schema.py +3 -3
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/solutions.py +8 -12
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/statements/build_statements.py +0 -1
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/statements/latex.py +11 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/caching.py +1 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/judge/sandbox.py +1 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/steps.py +1 -0
- rbx_cp-0.12.0/rbx/resources/presets/default/contest/.gitignore +21 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/contest/contest.rbx.yml +2 -2
- rbx_cp-0.12.0/rbx/resources/presets/default/problem/.gitignore +21 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/problem/validator.cpp +2 -1
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/shared/icpc.sty +1 -1
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/utils.py +13 -0
- rbx_cp-0.11.2/rbx/resources/presets/default/contest/.gitignore +0 -6
- rbx_cp-0.11.2/rbx/resources/presets/default/problem/.gitignore +0 -6
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/LICENSE +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/README.md +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/annotations.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/autoenum.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/cd.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/checkers.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/cli.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/code.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/compile.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/conftest.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/contest/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/contest/contest_package.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/contest/contest_utils.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/contest/main.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/contest/schema.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/creation.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/deferred.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/download.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/dump_schemas.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/environment.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/extensions.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/fields.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/formatting.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/generators_test.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/git_utils.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/global_package.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/header.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/lang.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/lazy_importing_main.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/lazy_importing_test.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/linting.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/main.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/naming.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/packaging/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/packaging/boca/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/packaging/boca/extension.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/packaging/boca/packager.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/packaging/contest_main.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/packaging/main.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/packaging/moj/packager.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/packaging/packager.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/packaging/pkg/packager.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/packaging/polygon/packager.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/packaging/polygon/polygon_api.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/packaging/polygon/test.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/packaging/polygon/xml_schema.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/presets/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/presets/fetch.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/presets/lock_schema.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/presets/schema.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/remote.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/retries.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/sanitizers/warning_stack.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/setter_config.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/solutions_test.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/state.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/statements/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/statements/builders.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/statements/expander.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/statements/joiners.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/statements/latex_jinja.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/statements/schema.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/stats.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/stresses.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/stressing/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/stressing/finder_parser.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/stressing/generator_parser.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/tasks.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/testcase_extractors.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/testcase_utils.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/testcases/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/testcases/main.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/tooling/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/tooling/boca/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/tooling/boca/main.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/tooling/boca/scrape.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/tooling/boca/scraper.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/tooling/main.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/captured_log.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/css/app.tcss +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/main.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/screens/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/screens/build.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/screens/command.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/screens/differ.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/screens/error.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/screens/rich_log_modal.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/screens/run.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/screens/run_explorer.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/screens/run_test_explorer.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/screens/selector.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/screens/test_explorer.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/utils/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/utils/run_ui.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/widgets/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/widgets/diff_box.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/widgets/file_log.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/widgets/interaction_box.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/widgets/rich_log_box.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/widgets/test_output_box.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/ui/widgets/two_sided_test_output_box.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/unit.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/validators.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/box/validators_test.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/checker.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/clone.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/config.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/conftest.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/console.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/create.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/edit.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/conftest.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/debug_context.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/grading_context.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/judge/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/judge/cacher.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/judge/digester.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/judge/sandboxes/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/judge/sandboxes/isolate.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/judge/sandboxes/stupid_sandbox.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/judge/sandboxes/timeit.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/judge/storage.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/judge/test.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/judge/testiso.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/limits.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/processing_context.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/profiling.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/steps_with_caching.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading/steps_with_caching_run_test.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/grading_utils.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/hydration.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/main.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/metadata.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/providers/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/providers/codeforces.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/providers/provider.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/checkers/boilerplate.cpp +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/checkers/noop.cpp +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/default_config.json +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/default_setter_config.mac.yml +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/default_setter_config.yml +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/envs/default.rbx.yml +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/envs/isolate.rbx.yml +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/checker.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/compare.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/compile/c +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/compile/cc +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/compile/cpp +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/compile/java +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/compile/kt +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/compile/py2 +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/compile/py3 +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/interactive/c +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/interactive/cc +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/interactive/cpp +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/interactive/java +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/interactive/kt +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/interactive/py2 +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/interactive/py3 +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/interactor_compile.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/interactor_run.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/run/bkp +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/run/c +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/run/cc +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/run/cpp +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/run/java +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/run/kt +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/run/py2 +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/run/py3 +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/safeexec.c +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/boca/safeexec_compile.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/c/compile.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/c/prep.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/c/run.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/compare.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/cpp/compile.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/cpp/prep.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/cpp/run.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/interactor_prep.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/interactor_run.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/java/compile.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/java/prep.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/java/run.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/py2/compile.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/py2/prep.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/py2/run.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/py3/compile.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/py3/prep.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/packagers/moj/scripts/py3/run.sh +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/contest/statement/contest.rbx.tex +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/contest/statement/instructions.tex +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/contest/statement/logo.png +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/env.rbx.yml +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/preset.rbx.yml +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/problem/gens/gen.cpp +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/problem/manual_tests/samples/000.in +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/problem/manual_tests/samples/001.in +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/problem/problem.rbx.yml +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/problem/rbx.h +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/problem/sols/main.cpp +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/problem/sols/slow.cpp +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/problem/sols/wa.cpp +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/problem/statement/statement.rbx.tex +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/problem/testplan/random.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/problem/testplan/random.txt +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/problem/wcmp.cpp +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/shared/contest_template.rbx.tex +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/presets/default/shared/problem_template.rbx.tex +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/templates/rbx.h +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/resources/templates/template.cpp +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/run.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/schema.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/submit.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/submitors/__init__.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/submitors/codeforces.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/submitors/submitor.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/test.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/testcase.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/testcase_rendering.py +0 -0
- {rbx_cp-0.11.2 → rbx_cp-0.12.0}/rbx/testing_utils.py +0 -0
@@ -96,10 +96,10 @@ async def verify(verification: environment.VerificationParam) -> bool:
|
|
96
96
|
|
97
97
|
tracked_solutions = None
|
98
98
|
if verification < VerificationLevel.ALL_SOLUTIONS.value:
|
99
|
-
pkg = package.find_problem_package_or_die()
|
100
|
-
|
101
99
|
tracked_solutions = {
|
102
|
-
str(solution.path)
|
100
|
+
str(solution.path)
|
101
|
+
for solution in package.get_solutions()
|
102
|
+
if is_fast(solution)
|
103
103
|
}
|
104
104
|
|
105
105
|
with utils.StatusProgress('Running solutions...') as s:
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import dataclasses
|
2
2
|
import pathlib
|
3
|
-
import subprocess
|
4
3
|
import tempfile
|
5
4
|
import typing
|
6
5
|
from typing import Any, Dict, List, Optional, Tuple
|
@@ -13,7 +12,7 @@ from rbx.box.contest.contest_package import get_problems
|
|
13
12
|
from rbx.box.contest.schema import Contest, ContestProblem, ContestStatement
|
14
13
|
from rbx.box.formatting import href
|
15
14
|
from rbx.box.schema import Package, Testcase
|
16
|
-
from rbx.box.statements import build_statements
|
15
|
+
from rbx.box.statements import build_statements, latex
|
17
16
|
from rbx.box.statements.build_statements import (
|
18
17
|
get_builders,
|
19
18
|
get_environment_languages_for_statement,
|
@@ -253,10 +252,10 @@ def build_contest_only(
|
|
253
252
|
console.console.log(
|
254
253
|
f'Installing LaTeX packages for [item]{statement.name} {statement.language}[/item]...'
|
255
254
|
)
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
255
|
+
tmp_file = pathlib.Path(td) / '__tmp_install__.tex'
|
256
|
+
tmp_file.write_bytes(output)
|
257
|
+
latex.install_tex_packages(tmp_file, pathlib.Path(td))
|
258
|
+
|
260
259
|
last_content = output
|
261
260
|
last_output = bdr.output_type()
|
262
261
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import functools
|
1
2
|
import pathlib
|
2
3
|
import shutil
|
3
4
|
from typing import Dict, List, Optional, Set
|
@@ -40,12 +41,44 @@ def _compile_generator(generator: CodeItem) -> str:
|
|
40
41
|
return compile_item(generator, sanitized=SanitizationLevel.PREFER)
|
41
42
|
|
42
43
|
|
44
|
+
@functools.cache
|
45
|
+
def _warn_once_about_crlf():
|
46
|
+
console.console.print(
|
47
|
+
'[warning]It seems a few files have CRLF (\\r\\n) line endings.[/warning]'
|
48
|
+
)
|
49
|
+
console.console.print(
|
50
|
+
'[warning]This usually happens when the file is created on Windows. Please convert the file to LF (\\n) line endings.[/warning]'
|
51
|
+
)
|
52
|
+
console.console.print(
|
53
|
+
'[warning]If you are in VSCode, you can make sure LF (\\n) line endings are used by changing the [item]"files.eol"[/item] setting.[/warning]'
|
54
|
+
)
|
55
|
+
|
56
|
+
|
57
|
+
@functools.cache
|
58
|
+
def _warn_about_crlf(path: pathlib.Path):
|
59
|
+
_warn_once_about_crlf()
|
60
|
+
console.console.print(
|
61
|
+
f'[warning]Testcase file [item]{path}[/item] has CRLF (\\r\\n) line endings, converting to LF (\\n).[/warning]'
|
62
|
+
)
|
63
|
+
|
64
|
+
|
65
|
+
def _check_crlf(path: pathlib.Path):
|
66
|
+
with open(path, 'rb') as f:
|
67
|
+
for line in f:
|
68
|
+
if line.endswith(b'\r\n') or line.endswith(b'\n\r'):
|
69
|
+
_warn_about_crlf(path)
|
70
|
+
break
|
71
|
+
|
72
|
+
path.write_text(path.read_text().replace('\r', ''))
|
73
|
+
|
74
|
+
|
43
75
|
def _copy_testcase_over(
|
44
76
|
testcase: Testcase,
|
45
77
|
dest: Testcase,
|
46
78
|
):
|
47
79
|
testcase = fill_output_for_defined_testcase(testcase)
|
48
80
|
dest.inputPath.parent.mkdir(parents=True, exist_ok=True)
|
81
|
+
_check_crlf(testcase.inputPath)
|
49
82
|
shutil.copy(
|
50
83
|
str(testcase.inputPath),
|
51
84
|
str(dest.inputPath),
|
@@ -55,6 +88,7 @@ def _copy_testcase_over(
|
|
55
88
|
and testcase.outputPath.is_file()
|
56
89
|
and dest.outputPath is not None
|
57
90
|
):
|
91
|
+
_check_crlf(testcase.outputPath)
|
58
92
|
dest.outputPath.parent.mkdir(parents=True, exist_ok=True)
|
59
93
|
shutil.copy(
|
60
94
|
str(testcase.outputPath),
|
@@ -71,6 +105,8 @@ def _copy_testcase_output_over(
|
|
71
105
|
if not src_path.is_file():
|
72
106
|
return False
|
73
107
|
|
108
|
+
_check_crlf(src_path)
|
109
|
+
|
74
110
|
shutil.copy(str(src_path), str(dest_output_path.with_suffix(suffix)))
|
75
111
|
return True
|
76
112
|
|
@@ -84,6 +120,7 @@ def _copy_testcase_outputs_over(
|
|
84
120
|
has_copied = False
|
85
121
|
|
86
122
|
if testcase.outputPath is not None and testcase.outputPath.is_file():
|
123
|
+
_check_crlf(testcase.outputPath)
|
87
124
|
shutil.copy(str(testcase.outputPath), str(dest.outputPath))
|
88
125
|
has_copied = True
|
89
126
|
|
@@ -120,35 +157,42 @@ def get_call_from_string(call_str: str) -> GeneratorCall:
|
|
120
157
|
async def _get_necessary_generators_for_groups(
|
121
158
|
groups: Optional[Set[str]] = None,
|
122
159
|
) -> Set[str]:
|
123
|
-
pkg = package.find_problem_package_or_die()
|
124
|
-
existing_generators = set(generator.name for generator in pkg.generators)
|
125
160
|
necessary_generators = set()
|
126
161
|
|
127
162
|
class NecessaryGeneratorsVisitor(TestcaseGroupVisitor):
|
128
163
|
async def visit(self, entry: GenerationTestcaseEntry):
|
129
164
|
if entry.metadata.generator_call is not None:
|
165
|
+
if (
|
166
|
+
package.get_generator_or_nil(entry.metadata.generator_call.name)
|
167
|
+
is None
|
168
|
+
):
|
169
|
+
console.console.print(
|
170
|
+
f'[error]Generator [item]{entry.metadata.generator_call.name}[/item] is not present in the package.[/error]'
|
171
|
+
)
|
172
|
+
if entry.metadata.generator_script is not None:
|
173
|
+
console.console.print(
|
174
|
+
f'[error]This generator is referenced from [item]{entry.metadata.generator_script}[/item].[/error]'
|
175
|
+
)
|
176
|
+
raise typer.Exit(1)
|
130
177
|
necessary_generators.add(entry.metadata.generator_call.name)
|
131
178
|
|
132
179
|
await run_testcase_visitor(NecessaryGeneratorsVisitor(groups))
|
133
180
|
|
134
|
-
return
|
181
|
+
return necessary_generators
|
135
182
|
|
136
183
|
|
137
184
|
def compile_generators(
|
185
|
+
tracked_generators: Set[str],
|
138
186
|
progress: Optional[StatusProgress] = None,
|
139
|
-
tracked_generators: Optional[Set[str]] = None,
|
140
187
|
) -> Dict[str, str]:
|
141
188
|
def update_status(text: str):
|
142
189
|
if progress is not None:
|
143
190
|
progress.update(text)
|
144
191
|
|
145
|
-
pkg = package.find_problem_package_or_die()
|
146
|
-
|
147
192
|
generator_to_compiled_digest = {}
|
148
193
|
|
149
|
-
for
|
150
|
-
|
151
|
-
continue
|
194
|
+
for generator_name in tracked_generators:
|
195
|
+
generator = package.get_generator(generator_name)
|
152
196
|
update_status(f'Compiling generator [item]{generator.name}[/item]')
|
153
197
|
try:
|
154
198
|
generator_to_compiled_digest[generator.name] = _compile_generator(generator)
|
@@ -267,9 +311,7 @@ async def generate_testcases(
|
|
267
311
|
|
268
312
|
compiled_generators = compile_generators(
|
269
313
|
progress=progress,
|
270
|
-
tracked_generators=await _get_necessary_generators_for_groups(groups)
|
271
|
-
if groups is not None
|
272
|
-
else None,
|
314
|
+
tracked_generators=await _get_necessary_generators_for_groups(groups),
|
273
315
|
)
|
274
316
|
|
275
317
|
testcase_utils.clear_built_testcases()
|
@@ -229,13 +229,45 @@ def get_build_testgroup_path(
|
|
229
229
|
|
230
230
|
|
231
231
|
@functools.cache
|
232
|
-
def
|
232
|
+
def get_generator_or_nil(
|
233
|
+
name: str, root: pathlib.Path = pathlib.Path()
|
234
|
+
) -> Optional[Generator]:
|
233
235
|
package = find_problem_package_or_die(root)
|
234
236
|
for generator in package.generators:
|
235
237
|
if generator.name == name:
|
236
238
|
return generator
|
237
|
-
|
238
|
-
|
239
|
+
|
240
|
+
path = pathlib.Path(root / name)
|
241
|
+
if path.is_file():
|
242
|
+
return Generator(name=name, path=path)
|
243
|
+
|
244
|
+
path_pattern = path.with_suffix('.*')
|
245
|
+
matching_files = list(
|
246
|
+
file.relative_to(root) for file in root.glob(str(path_pattern))
|
247
|
+
)
|
248
|
+
|
249
|
+
if len(matching_files) > 1:
|
250
|
+
console.console.print(
|
251
|
+
f'[error]Multiple candidate generators found for [item]{name}[/item]: {matching_files}[/error]'
|
252
|
+
)
|
253
|
+
console.console.print(
|
254
|
+
'[info]Please specify the generator path explicitly, including the extension, or rename the conflicting files.[/info]'
|
255
|
+
)
|
256
|
+
raise typer.Exit(1)
|
257
|
+
|
258
|
+
if matching_files:
|
259
|
+
return Generator(name=name, path=matching_files[0])
|
260
|
+
|
261
|
+
return None
|
262
|
+
|
263
|
+
|
264
|
+
@functools.cache
|
265
|
+
def get_generator(name: str, root: pathlib.Path = pathlib.Path()) -> Generator:
|
266
|
+
generator = get_generator_or_nil(name, root)
|
267
|
+
if generator is None:
|
268
|
+
console.console.print(f'[error]Generator [item]{name}[/item] not found[/error]')
|
269
|
+
raise typer.Exit(1)
|
270
|
+
return generator
|
239
271
|
|
240
272
|
|
241
273
|
@functools.cache
|
@@ -292,7 +324,27 @@ def get_interactor(root: pathlib.Path = pathlib.Path()) -> CodeItem:
|
|
292
324
|
@functools.cache
|
293
325
|
def get_solutions(root: pathlib.Path = pathlib.Path()) -> List[Solution]:
|
294
326
|
package = find_problem_package_or_die(root)
|
295
|
-
|
327
|
+
seen_paths = set()
|
328
|
+
res = []
|
329
|
+
|
330
|
+
def add_solution(entry: Solution):
|
331
|
+
if entry.path in seen_paths:
|
332
|
+
return
|
333
|
+
seen_paths.add(entry.path)
|
334
|
+
res.append(entry)
|
335
|
+
|
336
|
+
for entry in package.solutions:
|
337
|
+
if '*' in str(entry.path):
|
338
|
+
for file in root.glob(str(entry.path)):
|
339
|
+
relative_file = file.relative_to(root)
|
340
|
+
add_solution(
|
341
|
+
Solution.model_copy(
|
342
|
+
entry, update={'path': relative_file}, deep=True
|
343
|
+
)
|
344
|
+
)
|
345
|
+
continue
|
346
|
+
add_solution(entry)
|
347
|
+
return res
|
296
348
|
|
297
349
|
|
298
350
|
@functools.cache
|
@@ -214,8 +214,7 @@ def _upload_testcases(problem: api.Problem):
|
|
214
214
|
|
215
215
|
def _upload_solutions(problem: api.Problem):
|
216
216
|
console.console.print('Uploading main solution...')
|
217
|
-
|
218
|
-
main_solution = pkg.solutions[0]
|
217
|
+
main_solution = package.get_main_solution()
|
219
218
|
if main_solution is None or main_solution.outcome != ExpectedOutcome.ACCEPTED:
|
220
219
|
return
|
221
220
|
problem.save_solution(
|
@@ -225,7 +224,7 @@ def _upload_solutions(problem: api.Problem):
|
|
225
224
|
tag=api.SolutionTag.MA,
|
226
225
|
)
|
227
226
|
|
228
|
-
for i, solution in enumerate(
|
227
|
+
for i, solution in enumerate(package.get_solutions()):
|
229
228
|
console.console.print(
|
230
229
|
f'Uploading solution [item]{solution.path.name}[/item] (tag: [item]{_get_solution_tag(solution, is_first=i == 0)}[/item])...'
|
231
230
|
)
|
@@ -9,7 +9,7 @@ from pydantic import AfterValidator, BaseModel, ConfigDict, Field, model_validat
|
|
9
9
|
from pydantic_core import PydanticCustomError
|
10
10
|
|
11
11
|
from rbx.autoenum import AutoEnum, alias
|
12
|
-
from rbx.box.fields import
|
12
|
+
from rbx.box.fields import NameField
|
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
|
@@ -257,7 +257,7 @@ class Testcase(BaseModel):
|
|
257
257
|
class GeneratorCall(BaseModel):
|
258
258
|
model_config = ConfigDict(extra='forbid')
|
259
259
|
|
260
|
-
name: str =
|
260
|
+
name: str = Field(description='The name of the generator to call.')
|
261
261
|
|
262
262
|
args: Optional[str] = Field(
|
263
263
|
default=None, description='The arguments to pass to the generator.'
|
@@ -355,7 +355,7 @@ problems that have points.
|
|
355
355
|
class Generator(CodeItem):
|
356
356
|
model_config = ConfigDict(extra='forbid')
|
357
357
|
|
358
|
-
name: str =
|
358
|
+
name: str = Field(description="""The name of the generator.""")
|
359
359
|
|
360
360
|
|
361
361
|
class Solution(CodeItem):
|
@@ -158,12 +158,10 @@ def compile_solutions(
|
|
158
158
|
tracked_solutions: Optional[Set[str]] = None,
|
159
159
|
sanitized: bool = False,
|
160
160
|
) -> Dict[pathlib.Path, str]:
|
161
|
-
pkg = package.find_problem_package_or_die()
|
162
|
-
|
163
161
|
compiled_solutions = {}
|
164
162
|
|
165
163
|
if tracked_solutions is None:
|
166
|
-
tracked_solutions = set(str(sol.path) for sol in
|
164
|
+
tracked_solutions = set(str(sol.path) for sol in package.get_solutions())
|
167
165
|
|
168
166
|
for solution in expand_solutions(list(tracked_solutions)):
|
169
167
|
if progress:
|
@@ -232,9 +230,8 @@ async def convert_list_of_solution_evaluations_to_dict(
|
|
232
230
|
skeleton: SolutionReportSkeleton,
|
233
231
|
items: Iterable[EvaluationItem],
|
234
232
|
) -> List[Dict[str, List[Evaluation]]]:
|
235
|
-
pkg = package.find_problem_package_or_die()
|
236
233
|
res: List[Dict[str, List[Evaluation]]] = [
|
237
|
-
collections.defaultdict(list) for _ in
|
234
|
+
collections.defaultdict(list) for _ in package.get_solutions()
|
238
235
|
]
|
239
236
|
|
240
237
|
for item in items:
|
@@ -250,10 +247,9 @@ def _get_solutions_for_skeleton(
|
|
250
247
|
tracked_solutions: Optional[Iterable[str]] = None,
|
251
248
|
verification: VerificationLevel = VerificationLevel.NONE,
|
252
249
|
) -> List[Solution]:
|
253
|
-
pkg = package.find_problem_package_or_die()
|
254
250
|
solutions = [
|
255
251
|
sol
|
256
|
-
for sol in
|
252
|
+
for sol in package.get_solutions()
|
257
253
|
if verification.value >= VerificationLevel.ALL_SOLUTIONS.value or is_fast(sol)
|
258
254
|
]
|
259
255
|
if tracked_solutions is not None:
|
@@ -739,8 +735,7 @@ def _get_solution_repr(sol: Solution) -> List[Tuple[str, str]]:
|
|
739
735
|
|
740
736
|
|
741
737
|
def expand_solutions_with_source(sols: List[str]) -> List[Tuple[Solution, bool]]:
|
742
|
-
|
743
|
-
pkg_sols = {str(sol.path): sol for sol in pkg.solutions}
|
738
|
+
pkg_sols = {str(sol.path): sol for sol in package.get_solutions()}
|
744
739
|
|
745
740
|
# Download remote sols.
|
746
741
|
path_sols = remote.expand_files(sols)
|
@@ -777,20 +772,21 @@ async def pick_solutions(
|
|
777
772
|
tracked_solutions: Optional[OrderedSet[str]],
|
778
773
|
extra_solutions: Optional[List[str]] = None,
|
779
774
|
) -> List[str]:
|
780
|
-
pkg = package.find_problem_package_or_die()
|
781
775
|
# Store in a separate list to maintain order with the package declaration.
|
782
776
|
import questionary
|
783
777
|
|
778
|
+
solutions = package.get_solutions()
|
779
|
+
|
784
780
|
choices = [
|
785
781
|
questionary.Choice(
|
786
782
|
title=_get_solution_repr(sol),
|
787
783
|
value=str(sol.path),
|
788
784
|
checked=tracked_solutions is None or str(sol.path) in tracked_solutions,
|
789
785
|
)
|
790
|
-
for sol in
|
786
|
+
for sol in solutions
|
791
787
|
]
|
792
788
|
|
793
|
-
seen_sols = set(str(sol.path) for sol in
|
789
|
+
seen_sols = set(str(sol.path) for sol in solutions)
|
794
790
|
|
795
791
|
if extra_solutions is not None:
|
796
792
|
# Add only new solutions.
|
@@ -5,6 +5,8 @@ from typing import Optional
|
|
5
5
|
|
6
6
|
import chardet
|
7
7
|
|
8
|
+
from rbx.utils import command_exists
|
9
|
+
|
8
10
|
MAX_PDFLATEX_RUNS = 3
|
9
11
|
|
10
12
|
|
@@ -45,3 +47,12 @@ class Latex:
|
|
45
47
|
return LatexResult(result=completed, pdf=None)
|
46
48
|
|
47
49
|
return LatexResult(result=completed, pdf=output_path.read_bytes())
|
50
|
+
|
51
|
+
|
52
|
+
def install_tex_packages(path: pathlib.Path, cwd: pathlib.Path):
|
53
|
+
if not command_exists('texliveonfly'):
|
54
|
+
return
|
55
|
+
subprocess.run(
|
56
|
+
['texliveonfly', path],
|
57
|
+
cwd=cwd,
|
58
|
+
)
|
@@ -241,6 +241,7 @@ def _copy_hashed_files(artifact_list: List[GradingArtifacts], cacher: FileCacher
|
|
241
241
|
) is not None:
|
242
242
|
# Use a symlink to the file in the persistent cache, if available.
|
243
243
|
output.dest.unlink(missing_ok=True)
|
244
|
+
output.dest.parent.mkdir(parents=True, exist_ok=True)
|
244
245
|
output.dest.symlink_to(path_to_symlink)
|
245
246
|
else:
|
246
247
|
# Otherwise, copy it.
|
@@ -355,6 +355,7 @@ def _process_output_artifacts(
|
|
355
355
|
):
|
356
356
|
# File is in the persistent cache, store a symlink to it.
|
357
357
|
dst.unlink(missing_ok=True)
|
358
|
+
dst.parent.mkdir(parents=True, exist_ok=True)
|
358
359
|
dst.symlink_to(path_to_symlink)
|
359
360
|
else:
|
360
361
|
# File is not in the persistent cache, copy it.
|
@@ -1,13 +1,13 @@
|
|
1
1
|
---
|
2
2
|
# yaml-language-server: $schema=https://rsalesc.github.io/rbx/schemas/Contest.json
|
3
|
-
# Add problems by running `rbx contest add
|
3
|
+
# Add problems by running `rbx contest add`
|
4
4
|
name: "new-contest"
|
5
5
|
statements:
|
6
6
|
- name: "statement-en"
|
7
7
|
title: "New contest"
|
8
8
|
language: "en"
|
9
9
|
path: "statement/contest.rbx.tex"
|
10
|
-
type:
|
10
|
+
type: JinjaTeX
|
11
11
|
assets:
|
12
12
|
- "statement/icpc.sty"
|
13
13
|
- "statement/*.png"
|
@@ -1,3 +1,4 @@
|
|
1
|
+
#include "rbx.h"
|
1
2
|
#include "testlib.h"
|
2
3
|
|
3
4
|
using namespace std;
|
@@ -6,7 +7,7 @@ int main(int argc, char *argv[]) {
|
|
6
7
|
registerValidation(argc, argv);
|
7
8
|
prepareOpts(argc, argv);
|
8
9
|
|
9
|
-
int MAX_N =
|
10
|
+
int MAX_N = getVar<int>("MAX_N"); // Read from package vars.
|
10
11
|
|
11
12
|
inf.readInt(1, MAX_N, "A");
|
12
13
|
inf.readSpace();
|
@@ -6,6 +6,7 @@ import os
|
|
6
6
|
import os.path
|
7
7
|
import pathlib
|
8
8
|
import resource
|
9
|
+
import subprocess
|
9
10
|
from typing import Any, Optional, Type, TypeVar
|
10
11
|
|
11
12
|
import rich
|
@@ -145,6 +146,18 @@ def get_open_fds():
|
|
145
146
|
return fds
|
146
147
|
|
147
148
|
|
149
|
+
def command_exists(command):
|
150
|
+
try:
|
151
|
+
subprocess.run(
|
152
|
+
[command], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
153
|
+
)
|
154
|
+
return True
|
155
|
+
except FileNotFoundError:
|
156
|
+
return False
|
157
|
+
except subprocess.CalledProcessError:
|
158
|
+
return True
|
159
|
+
|
160
|
+
|
148
161
|
@contextlib.contextmanager
|
149
162
|
def new_cd(x: pathlib.Path):
|
150
163
|
d = os.getcwd()
|
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
|