rbx.cp 0.5.65__tar.gz → 0.5.66__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/PKG-INFO +1 -1
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/pyproject.toml +1 -1
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/cli.py +9 -3
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/package.py +13 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/packaging/boca/upload.py +39 -1
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/solutions.py +71 -25
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/css/app.tcss +14 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/main.py +21 -0
- rbx_cp-0.5.66/rbx/box/ui/screens/differ.py +29 -0
- rbx_cp-0.5.66/rbx/box/ui/widgets/diff_box.py +38 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/unit.py +0 -2
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/LICENSE +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/README.md +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/annotations.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/autoenum.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/builder.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/cd.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/checkers.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/code.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/compile.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/conftest.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/contest/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/contest/build_contest_statements.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/contest/contest_package.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/contest/contest_utils.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/contest/main.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/contest/schema.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/contest/statements.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/creation.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/deferred.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/download.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/dump_schemas.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/environment.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/extensions.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/formatting.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/generators.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/generators_test.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/git_utils.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/header.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/lazy_importing_main.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/lazy_importing_test.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/main.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/naming.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/packaging/boca/extension.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/packaging/boca/packager.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/packaging/contest_main.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/packaging/main.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/packaging/moj/packager.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/packaging/packager.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/packaging/polygon/packager.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/packaging/polygon/polygon_api.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/packaging/polygon/test.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/packaging/polygon/upload.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/packaging/polygon/xml_schema.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/presets/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/presets/fetch.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/presets/lock_schema.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/presets/schema.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/retries.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/sanitizers/warning_stack.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/schema.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/setter_config.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/solutions_test.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/state.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/statements/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/statements/build_statements.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/statements/builders.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/statements/joiners.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/statements/latex.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/statements/latex_jinja.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/statements/schema.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/stresses.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/stressing/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/stressing/finder_parser.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/stressing/generator_parser.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/tasks.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/testcase_extractors.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/testcase_utils.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/testcases/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/testcases/main.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/captured_log.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/screens/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/screens/build.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/screens/command.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/screens/error.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/screens/run.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/screens/run_explorer.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/screens/run_test_explorer.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/screens/selector.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/screens/test_explorer.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/utils/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/utils/run_ui.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/widgets/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/widgets/file_log.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/widgets/interaction_box.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/widgets/rich_log_box.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/widgets/test_output_box.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/ui/widgets/two_sided_test_output_box.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/validators.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/box/validators_test.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/checker.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/clone.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/config.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/conftest.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/console.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/create.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/edit.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/caching.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/conftest.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/judge/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/judge/cacher.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/judge/digester.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/judge/sandbox.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/judge/sandboxes/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/judge/sandboxes/isolate.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/judge/sandboxes/stupid_sandbox.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/judge/sandboxes/timeit.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/judge/storage.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/judge/test.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/judge/testiso.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/limits.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/processing_context.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/steps.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/steps_with_caching.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading/steps_with_caching_run_test.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/grading_utils.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/hydration.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/main.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/metadata.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/providers/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/providers/codeforces.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/providers/provider.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/checkers/boilerplate.cpp +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/default_config.json +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/default_setter_config.mac.yml +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/default_setter_config.yml +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/envs/default.rbx.yml +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/envs/isolate.rbx.yml +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/checker.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/compare.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/compile/c +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/compile/cc +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/compile/cpp +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/compile/java +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/compile/kt +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/compile/pas +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/compile/py2 +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/compile/py3 +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/interactive/c +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/interactive/cc +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/interactive/cpp +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/interactive/java +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/interactive/kt +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/interactive/py2 +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/interactive/py3 +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/interactor_compile.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/run/bkp +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/run/c +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/run/cc +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/run/cpp +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/run/java +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/run/kt +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/run/py2 +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/boca/run/py3 +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/c/compile.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/c/prep.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/c/run.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/compare.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/cpp/compile.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/cpp/prep.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/cpp/run.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/interactor_prep.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/interactor_run.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/java/compile.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/java/prep.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/java/run.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/py2/compile.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/py2/prep.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/py2/run.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/py3/compile.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/py3/prep.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/packagers/moj/scripts/py3/run.sh +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/contest/contest.rbx.yml +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/contest/statement/contest.rbx.tex +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/contest/statement/olymp.sty +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/contest/statement/template.rbx.tex +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/preset.rbx.yml +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/.gitignore +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/gen.cpp +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/problem.rbx.yml +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/random.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/random.txt +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/sols/main.cpp +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/sols/slow.cpp +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/sols/wa.cpp +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/statement/olymp.sty +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/statement/projecao.png +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/statement/statement.rbx.tex +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/statement/template.rbx.tex +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/tests/samples/000.in +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/tests/samples/001.in +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/validator.cpp +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/presets/default/problem/wcmp.cpp +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/templates/rbx.h +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/resources/templates/template.cpp +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/run.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/schema.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/submit.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/submitors/__init__.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/submitors/codeforces.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/submitors/submitor.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/test.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/testcase.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/testcase_rendering.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/testing_utils.py +0 -0
- {rbx_cp-0.5.65 → rbx_cp-0.5.66}/rbx/utils.py +0 -0
@@ -32,7 +32,6 @@ from rbx.box.packaging import main as packaging
|
|
32
32
|
from rbx.box.schema import CodeItem, ExpectedOutcome, TestcaseGroup
|
33
33
|
from rbx.box.solutions import (
|
34
34
|
estimate_time_limit,
|
35
|
-
expand_solutions,
|
36
35
|
get_exact_matching_solutions,
|
37
36
|
get_matching_solutions,
|
38
37
|
pick_solutions,
|
@@ -137,6 +136,13 @@ def ui():
|
|
137
136
|
ui_pkg.start()
|
138
137
|
|
139
138
|
|
139
|
+
@app.command('diff', hidden=True)
|
140
|
+
def diff(path1: pathlib.Path, path2: pathlib.Path):
|
141
|
+
from rbx.box.ui import main as ui_pkg
|
142
|
+
|
143
|
+
ui_pkg.start_differ(path1, path2)
|
144
|
+
|
145
|
+
|
140
146
|
@app.command('serve', hidden=True)
|
141
147
|
def serve():
|
142
148
|
from textual_serve.server import Server
|
@@ -243,7 +249,7 @@ async def run(
|
|
243
249
|
tracked_solutions = set(
|
244
250
|
await pick_solutions(
|
245
251
|
tracked_solutions,
|
246
|
-
extra_solutions=
|
252
|
+
extra_solutions=solutions,
|
247
253
|
)
|
248
254
|
)
|
249
255
|
if not tracked_solutions:
|
@@ -479,7 +485,7 @@ async def irun(
|
|
479
485
|
tracked_solutions = set(
|
480
486
|
await pick_solutions(
|
481
487
|
tracked_solutions,
|
482
|
-
extra_solutions=
|
488
|
+
extra_solutions=solutions,
|
483
489
|
)
|
484
490
|
)
|
485
491
|
if not tracked_solutions:
|
@@ -150,6 +150,19 @@ def get_problem_cache_dir(root: pathlib.Path = pathlib.Path()) -> pathlib.Path:
|
|
150
150
|
return cache_dir
|
151
151
|
|
152
152
|
|
153
|
+
@functools.cache
|
154
|
+
def get_problem_remote_dir(
|
155
|
+
platform: Optional[str] = None, root: pathlib.Path = pathlib.Path()
|
156
|
+
) -> pathlib.Path:
|
157
|
+
remote_dir = get_problem_cache_dir(root) / '.remote'
|
158
|
+
remote_dir.mkdir(parents=True, exist_ok=True)
|
159
|
+
|
160
|
+
if platform is not None:
|
161
|
+
remote_dir = remote_dir / platform
|
162
|
+
remote_dir.mkdir(parents=True, exist_ok=True)
|
163
|
+
return remote_dir
|
164
|
+
|
165
|
+
|
153
166
|
@functools.cache
|
154
167
|
def get_problem_storage_dir(root: pathlib.Path = pathlib.Path()) -> pathlib.Path:
|
155
168
|
storage_dir = get_problem_cache_dir(root) / '.storage'
|
@@ -4,6 +4,7 @@ import hashlib
|
|
4
4
|
import os
|
5
5
|
import pathlib
|
6
6
|
import re
|
7
|
+
import shutil
|
7
8
|
import typing
|
8
9
|
from typing import Any, NoReturn, Optional, Tuple
|
9
10
|
|
@@ -248,13 +249,50 @@ class BocaUploader:
|
|
248
249
|
'[error]Persistent error while uploading problem to BOCA website.[/error]'
|
249
250
|
)
|
250
251
|
console.console.print(
|
251
|
-
'[warning]This might be caused by PHP max upload size limit (which usually defaults to
|
252
|
+
'[warning]This might be caused by PHP max upload size limit (which usually defaults to 2MB).[/warning]'
|
252
253
|
)
|
253
254
|
console.console.print(
|
254
255
|
'[warning]Check [item]https://www.php.net/manual/en/ini.core.php#ini.sect.file-uploads[/item] for more information.[/warning]'
|
255
256
|
)
|
256
257
|
raise typer.Exit(1)
|
257
258
|
|
259
|
+
def download_run(self, run_number: int, site_number: int, into_dir: pathlib.Path):
|
260
|
+
url = f'{self.base_url}/admin/runedit.php?runnumber={run_number}&runsitenumber={site_number}'
|
261
|
+
_, html = self.open(
|
262
|
+
url,
|
263
|
+
error_msg=f'Error while downloading BOCA run [item]{run_number}-{site_number}[/item]',
|
264
|
+
)
|
265
|
+
|
266
|
+
soup = BeautifulSoup(html, 'html.parser')
|
267
|
+
rows = soup.select('tr')
|
268
|
+
|
269
|
+
href: Optional[str] = None
|
270
|
+
filename: Optional[pathlib.Path] = None
|
271
|
+
|
272
|
+
for row in rows:
|
273
|
+
row_text = row.select('td')[0].text.strip().lower()
|
274
|
+
if row_text != "team's code:":
|
275
|
+
continue
|
276
|
+
link_col = row.select_one('td:nth-of-type(2) a:nth-of-type(1)')
|
277
|
+
if link_col is None:
|
278
|
+
continue
|
279
|
+
href = str(link_col.attrs['href'])
|
280
|
+
filename = pathlib.Path(link_col.text.strip())
|
281
|
+
break
|
282
|
+
|
283
|
+
if href is None or filename is None:
|
284
|
+
self.raw_error(
|
285
|
+
"Error while downloading run:\nNo link to team's code found."
|
286
|
+
)
|
287
|
+
|
288
|
+
link = self.br.find_link(url=href)
|
289
|
+
tmp_file, _ = self.br.retrieve(link.absolute_url)
|
290
|
+
if tmp_file is None:
|
291
|
+
self.raw_error('Error while downloading run:\nDownloaded file is None.')
|
292
|
+
final_path = into_dir / filename.with_stem(f'{run_number}-{site_number}')
|
293
|
+
shutil.move(tmp_file, final_path)
|
294
|
+
return final_path
|
295
|
+
|
258
296
|
|
259
297
|
@functools.lru_cache
|
260
298
|
def get_boca_uploader(
|
@@ -159,12 +159,10 @@ def compile_solutions(
|
|
159
159
|
|
160
160
|
compiled_solutions = {}
|
161
161
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
):
|
167
|
-
continue
|
162
|
+
if tracked_solutions is None:
|
163
|
+
tracked_solutions = set(str(sol.path) for sol in pkg.solutions)
|
164
|
+
|
165
|
+
for solution in expand_solutions(list(tracked_solutions)):
|
168
166
|
if progress:
|
169
167
|
progress.update(f'Compiling solution {href(solution.path)}...')
|
170
168
|
try:
|
@@ -254,11 +252,7 @@ def _get_solutions_for_skeleton(
|
|
254
252
|
if verification.value >= VerificationLevel.ALL_SOLUTIONS.value or is_fast(sol)
|
255
253
|
]
|
256
254
|
if tracked_solutions is not None:
|
257
|
-
solutions =
|
258
|
-
solution
|
259
|
-
for solution in solutions
|
260
|
-
if str(solution.path) in tracked_solutions
|
261
|
-
]
|
255
|
+
solutions = expand_solutions(list(tracked_solutions))
|
262
256
|
return solutions
|
263
257
|
|
264
258
|
|
@@ -726,28 +720,78 @@ def _get_solution_repr(sol: Solution) -> List[Tuple[str, str]]:
|
|
726
720
|
]
|
727
721
|
|
728
722
|
|
729
|
-
|
723
|
+
# TODO: refactor this function
|
724
|
+
def _expand_remote_sol(sol: str) -> Optional[str]:
|
725
|
+
from rbx.box.packaging.boca import upload as boca_upload
|
726
|
+
|
727
|
+
# Only BOCA supported for now.
|
728
|
+
assert sol.startswith('@')
|
729
|
+
sol = sol[1:]
|
730
|
+
if '-' in sol:
|
731
|
+
run_number, site_number = sol.split('-', 1)
|
732
|
+
run_number = int(run_number)
|
733
|
+
site_number = int(site_number)
|
734
|
+
else:
|
735
|
+
run_number = int(sol)
|
736
|
+
site_number = 1
|
737
|
+
|
738
|
+
expected_glob = (
|
739
|
+
package.get_problem_remote_dir('boca') / f'{run_number}-{site_number}.*'
|
740
|
+
)
|
741
|
+
expected_glob = expected_glob.relative_to(pathlib.Path.cwd())
|
742
|
+
for path in pathlib.Path.cwd().glob(str(expected_glob)):
|
743
|
+
if path.is_file():
|
744
|
+
relpath = path.resolve().relative_to(pathlib.Path.cwd())
|
745
|
+
console.console.print(f'Retrieving {href(relpath)} from cache...')
|
746
|
+
return str(relpath)
|
747
|
+
|
748
|
+
boca_uploader = boca_upload.get_boca_uploader()
|
749
|
+
boca_uploader.login()
|
750
|
+
sol_path = boca_uploader.download_run(
|
751
|
+
run_number, site_number, package.get_problem_remote_dir('boca')
|
752
|
+
)
|
753
|
+
console.console.print(f'Downloaded {href(sol_path)} from BOCA...')
|
754
|
+
return str(sol_path.resolve().relative_to(pathlib.Path.cwd()))
|
755
|
+
|
756
|
+
|
757
|
+
def _expand_remote_sols(sols: List[str]) -> List[str]:
|
758
|
+
res = []
|
759
|
+
for sol in sols:
|
760
|
+
if not sol.startswith('@'):
|
761
|
+
res.append(sol)
|
762
|
+
continue
|
763
|
+
expanded = _expand_remote_sol(sol)
|
764
|
+
if expanded is None:
|
765
|
+
continue
|
766
|
+
res.append(expanded)
|
767
|
+
return res
|
768
|
+
|
769
|
+
|
770
|
+
def expand_solutions(sols: List[str]) -> List[Solution]:
|
730
771
|
pkg = package.find_problem_package_or_die()
|
731
|
-
seen_sols =
|
772
|
+
seen_sols = {str(sol.path): sol for sol in pkg.solutions}
|
732
773
|
|
733
|
-
#
|
734
|
-
sols =
|
774
|
+
# Download remote sols.
|
775
|
+
sols = _expand_remote_sols(sols)
|
735
776
|
|
736
777
|
# Ensure sols exist.
|
737
778
|
sols = [sol for sol in sols if pathlib.Path(sol).is_file()]
|
738
779
|
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
780
|
+
res = []
|
781
|
+
for sol in sols:
|
782
|
+
if sol in seen_sols:
|
783
|
+
res.append(seen_sols[sol])
|
784
|
+
else:
|
785
|
+
res.append(
|
786
|
+
Solution(path=pathlib.Path(sol), outcome=ExpectedOutcome.ACCEPTED)
|
787
|
+
)
|
788
|
+
return res
|
743
789
|
|
744
790
|
|
745
791
|
async def pick_solutions(
|
746
792
|
tracked_solutions: Optional[Set[str]],
|
747
|
-
extra_solutions: Optional[
|
793
|
+
extra_solutions: Optional[List[str]] = None,
|
748
794
|
) -> List[str]:
|
749
|
-
extra_sols = set(extra_solutions) if extra_solutions is not None else set()
|
750
|
-
|
751
795
|
pkg = package.find_problem_package_or_die()
|
752
796
|
# Store in a separate list to maintain order with the package declaration.
|
753
797
|
import questionary
|
@@ -763,13 +807,15 @@ async def pick_solutions(
|
|
763
807
|
|
764
808
|
seen_sols = set(str(sol.path) for sol in pkg.solutions)
|
765
809
|
|
766
|
-
if
|
810
|
+
if extra_solutions is not None:
|
767
811
|
# Add only new solutions.
|
768
812
|
choices.extend(
|
769
813
|
questionary.Choice(
|
770
|
-
title=_get_solution_repr(sol),
|
814
|
+
title=_get_solution_repr(sol),
|
815
|
+
value=str(sol.path),
|
816
|
+
checked=True,
|
771
817
|
)
|
772
|
-
for sol in
|
818
|
+
for sol in expand_solutions(extra_solutions)
|
773
819
|
if str(sol.path) not in seen_sols
|
774
820
|
)
|
775
821
|
|
@@ -21,6 +21,20 @@ OptionList {
|
|
21
21
|
border: solid $accent;
|
22
22
|
}
|
23
23
|
|
24
|
+
DiffBox {
|
25
|
+
border: solid $accent;
|
26
|
+
height: 1fr;
|
27
|
+
width: 1fr;
|
28
|
+
Markdown {
|
29
|
+
height: 1fr;
|
30
|
+
width: 1fr;
|
31
|
+
|
32
|
+
.code_inline {
|
33
|
+
background: $background;
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
24
38
|
Button {
|
25
39
|
width: 1fr;
|
26
40
|
background: $accent;
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import pathlib
|
1
2
|
from typing import Type
|
2
3
|
|
3
4
|
from textual.app import App, ComposeResult
|
@@ -5,6 +6,7 @@ from textual.containers import Center
|
|
5
6
|
from textual.screen import Screen
|
6
7
|
from textual.widgets import Footer, Header, OptionList
|
7
8
|
|
9
|
+
from rbx.box.ui.screens.differ import DifferScreen
|
8
10
|
from rbx.box.ui.screens.run_explorer import RunExplorerScreen
|
9
11
|
from rbx.box.ui.screens.test_explorer import TestExplorerScreen
|
10
12
|
|
@@ -35,6 +37,25 @@ class rbxApp(App):
|
|
35
37
|
self.push_screen(screen_cls())
|
36
38
|
|
37
39
|
|
40
|
+
class rbxDifferApp(App):
|
41
|
+
TITLE = 'rbx differ'
|
42
|
+
CSS_PATH = 'css/app.tcss'
|
43
|
+
BINDINGS = [('q', 'quit', 'Quit')]
|
44
|
+
|
45
|
+
def __init__(self, path1: pathlib.Path, path2: pathlib.Path):
|
46
|
+
super().__init__()
|
47
|
+
self.path1 = path1
|
48
|
+
self.path2 = path2
|
49
|
+
|
50
|
+
def on_mount(self):
|
51
|
+
self.push_screen(DifferScreen(self.path1, self.path2))
|
52
|
+
|
53
|
+
|
38
54
|
def start():
|
39
55
|
app = rbxApp()
|
40
56
|
app.run()
|
57
|
+
|
58
|
+
|
59
|
+
def start_differ(path1: pathlib.Path, path2: pathlib.Path):
|
60
|
+
app = rbxDifferApp(path1, path2)
|
61
|
+
app.run()
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import pathlib
|
2
|
+
|
3
|
+
from textual.app import ComposeResult
|
4
|
+
from textual.containers import Vertical
|
5
|
+
from textual.screen import Screen
|
6
|
+
from textual.widgets import Footer, Header
|
7
|
+
|
8
|
+
from rbx.box.ui.widgets.diff_box import DiffBox
|
9
|
+
|
10
|
+
|
11
|
+
class DifferScreen(Screen):
|
12
|
+
BINDINGS = [
|
13
|
+
('q', 'quit', 'Quit'),
|
14
|
+
]
|
15
|
+
|
16
|
+
def __init__(self, path1: pathlib.Path, path2: pathlib.Path):
|
17
|
+
super().__init__()
|
18
|
+
self.path1 = path1
|
19
|
+
self.path2 = path2
|
20
|
+
|
21
|
+
def compose(self) -> ComposeResult:
|
22
|
+
yield Header()
|
23
|
+
yield Footer()
|
24
|
+
with Vertical():
|
25
|
+
yield DiffBox()
|
26
|
+
|
27
|
+
def on_mount(self):
|
28
|
+
diff = self.query_one(DiffBox)
|
29
|
+
diff.paths = (self.path1, self.path2)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import difflib
|
2
|
+
import pathlib
|
3
|
+
from typing import Optional, Tuple
|
4
|
+
|
5
|
+
from rich.markdown import Markdown
|
6
|
+
from textual.app import ComposeResult
|
7
|
+
from textual.reactive import reactive
|
8
|
+
from textual.widget import Widget
|
9
|
+
from textual.widgets import RichLog
|
10
|
+
|
11
|
+
|
12
|
+
def compute_diff(file1: pathlib.Path, file2: pathlib.Path) -> str:
|
13
|
+
lines1 = file1.read_text().splitlines(keepends=True)
|
14
|
+
lines2 = file2.read_text().splitlines(keepends=True)
|
15
|
+
return ''.join(difflib.ndiff(lines1, lines2))
|
16
|
+
|
17
|
+
|
18
|
+
class DiffBox(Widget, can_focus=False):
|
19
|
+
paths: reactive[Optional[Tuple[pathlib.Path, pathlib.Path]]] = reactive(None)
|
20
|
+
|
21
|
+
def __init__(self):
|
22
|
+
super().__init__()
|
23
|
+
|
24
|
+
def compose(self) -> ComposeResult:
|
25
|
+
md = RichLog()
|
26
|
+
md.border_title = 'Differ'
|
27
|
+
yield md
|
28
|
+
|
29
|
+
async def watch_paths(self, paths: Optional[Tuple[pathlib.Path, pathlib.Path]]):
|
30
|
+
log = self.query_one(RichLog)
|
31
|
+
log.clear()
|
32
|
+
if paths is None:
|
33
|
+
return
|
34
|
+
file1, file2 = paths
|
35
|
+
md = Markdown(
|
36
|
+
f'```diff\n{compute_diff(file1, file2)}\n```', code_theme='monokai'
|
37
|
+
)
|
38
|
+
log.write(md)
|
@@ -148,8 +148,6 @@ async def run_validator_unit_tests(progress: StatusProgress):
|
|
148
148
|
|
149
149
|
async def run_checker_unit_tests(progress: StatusProgress):
|
150
150
|
pkg = package.find_problem_package_or_die()
|
151
|
-
if not pkg.unitTests.checker:
|
152
|
-
return
|
153
151
|
|
154
152
|
if not package.get_checker():
|
155
153
|
console.console.print(
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|