rbx.cp 0.5.48__tar.gz → 0.5.50__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.
Files changed (195) hide show
  1. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/PKG-INFO +1 -1
  2. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/pyproject.toml +1 -1
  3. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/cli.py +1 -0
  4. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/packaging/main.py +3 -0
  5. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/schema.py +8 -13
  6. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/solutions.py +40 -11
  7. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/testcase_utils.py +12 -0
  8. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/testcases/main.py +2 -0
  9. rbx_cp-0.5.50/rbx/box/unit.py +206 -0
  10. rbx_cp-0.5.48/rbx/box/unit.py +0 -116
  11. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/LICENSE +0 -0
  12. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/README.md +0 -0
  13. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/__init__.py +0 -0
  14. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/annotations.py +0 -0
  15. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/autoenum.py +0 -0
  16. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/__init__.py +0 -0
  17. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/builder.py +0 -0
  18. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/cd.py +0 -0
  19. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/checkers.py +0 -0
  20. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/code.py +0 -0
  21. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/compile.py +0 -0
  22. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/conftest.py +0 -0
  23. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/contest/__init__.py +0 -0
  24. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/contest/build_contest_statements.py +0 -0
  25. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/contest/contest_package.py +0 -0
  26. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/contest/contest_utils.py +0 -0
  27. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/contest/main.py +0 -0
  28. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/contest/schema.py +0 -0
  29. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/contest/statements.py +0 -0
  30. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/creation.py +0 -0
  31. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/deferred.py +0 -0
  32. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/download.py +0 -0
  33. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/environment.py +0 -0
  34. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/extensions.py +0 -0
  35. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/formatting.py +0 -0
  36. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/generators.py +0 -0
  37. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/generators_test.py +0 -0
  38. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/lazy_importing_main.py +0 -0
  39. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/lazy_importing_test.py +0 -0
  40. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/main.py +0 -0
  41. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/naming.py +0 -0
  42. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/package.py +0 -0
  43. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/packaging/boca/extension.py +0 -0
  44. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/packaging/boca/packager.py +0 -0
  45. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/packaging/contest_main.py +0 -0
  46. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/packaging/moj/packager.py +0 -0
  47. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/packaging/packager.py +0 -0
  48. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/packaging/polygon/packager.py +0 -0
  49. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/packaging/polygon/test.py +0 -0
  50. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/packaging/polygon/xml_schema.py +0 -0
  51. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/presets/__init__.py +0 -0
  52. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/presets/fetch.py +0 -0
  53. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/presets/lock_schema.py +0 -0
  54. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/presets/schema.py +0 -0
  55. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/retries.py +0 -0
  56. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/sanitizers/warning_stack.py +0 -0
  57. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/setter_config.py +0 -0
  58. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/solutions_test.py +0 -0
  59. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/state.py +0 -0
  60. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/statements/__init__.py +0 -0
  61. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/statements/build_statements.py +0 -0
  62. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/statements/builders.py +0 -0
  63. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/statements/joiners.py +0 -0
  64. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/statements/latex.py +0 -0
  65. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/statements/latex_jinja.py +0 -0
  66. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/statements/schema.py +0 -0
  67. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/stresses.py +0 -0
  68. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/stressing/__init__.py +0 -0
  69. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/stressing/finder_parser.py +0 -0
  70. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/stressing/generator_parser.py +0 -0
  71. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/tasks.py +0 -0
  72. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/testcase_extractors.py +0 -0
  73. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/testcases/__init__.py +0 -0
  74. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/ui/__init__.py +0 -0
  75. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/ui/captured_log.py +0 -0
  76. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/ui/css/app.tcss +0 -0
  77. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/ui/main.py +0 -0
  78. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/ui/run.py +0 -0
  79. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/validators.py +0 -0
  80. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/box/validators_test.py +0 -0
  81. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/checker.py +0 -0
  82. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/clone.py +0 -0
  83. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/config.py +0 -0
  84. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/conftest.py +0 -0
  85. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/console.py +0 -0
  86. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/create.py +0 -0
  87. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/edit.py +0 -0
  88. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/__init__.py +0 -0
  89. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/caching.py +0 -0
  90. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/conftest.py +0 -0
  91. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/judge/__init__.py +0 -0
  92. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/judge/cacher.py +0 -0
  93. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/judge/digester.py +0 -0
  94. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/judge/sandbox.py +0 -0
  95. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/judge/sandboxes/__init__.py +0 -0
  96. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/judge/sandboxes/isolate.py +0 -0
  97. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/judge/sandboxes/stupid_sandbox.py +0 -0
  98. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/judge/sandboxes/timeit.py +0 -0
  99. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/judge/storage.py +0 -0
  100. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/judge/test.py +0 -0
  101. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/judge/testiso.py +0 -0
  102. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/processing_context.py +0 -0
  103. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/steps.py +0 -0
  104. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/steps_with_caching.py +0 -0
  105. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading/steps_with_caching_run_test.py +0 -0
  106. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/grading_utils.py +0 -0
  107. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/hydration.py +0 -0
  108. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/main.py +0 -0
  109. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/metadata.py +0 -0
  110. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/providers/__init__.py +0 -0
  111. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/providers/codeforces.py +0 -0
  112. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/providers/provider.py +0 -0
  113. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/checkers/boilerplate.cpp +0 -0
  114. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/default_config.json +0 -0
  115. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/default_setter_config.mac.yml +0 -0
  116. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/default_setter_config.yml +0 -0
  117. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/envs/default.rbx.yml +0 -0
  118. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/envs/isolate.rbx.yml +0 -0
  119. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/checker.sh +0 -0
  120. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/compare.sh +0 -0
  121. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/compile/c +0 -0
  122. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/compile/cc +0 -0
  123. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/compile/cpp +0 -0
  124. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/compile/java +0 -0
  125. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/compile/kt +0 -0
  126. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/compile/pas +0 -0
  127. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/compile/py2 +0 -0
  128. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/compile/py3 +0 -0
  129. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/interactive/c +0 -0
  130. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/interactive/cc +0 -0
  131. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/interactive/cpp +0 -0
  132. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/interactive/java +0 -0
  133. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/interactive/kt +0 -0
  134. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/interactive/py2 +0 -0
  135. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/interactive/py3 +0 -0
  136. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/interactor_compile.sh +0 -0
  137. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/run/bkp +0 -0
  138. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/run/c +0 -0
  139. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/run/cc +0 -0
  140. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/run/cpp +0 -0
  141. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/run/java +0 -0
  142. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/run/kt +0 -0
  143. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/run/py2 +0 -0
  144. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/boca/run/py3 +0 -0
  145. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/c/compile.sh +0 -0
  146. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/c/prep.sh +0 -0
  147. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/c/run.sh +0 -0
  148. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/compare.sh +0 -0
  149. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/cpp/compile.sh +0 -0
  150. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/cpp/prep.sh +0 -0
  151. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/cpp/run.sh +0 -0
  152. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/interactor_prep.sh +0 -0
  153. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/interactor_run.sh +0 -0
  154. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/java/compile.sh +0 -0
  155. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/java/prep.sh +0 -0
  156. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/java/run.sh +0 -0
  157. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/py2/compile.sh +0 -0
  158. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/py2/prep.sh +0 -0
  159. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/py2/run.sh +0 -0
  160. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/py3/compile.sh +0 -0
  161. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/py3/prep.sh +0 -0
  162. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/packagers/moj/scripts/py3/run.sh +0 -0
  163. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/contest/contest.rbx.yml +0 -0
  164. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/contest/statement/contest.rbx.tex +0 -0
  165. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/contest/statement/olymp.sty +0 -0
  166. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/contest/statement/template.rbx.tex +0 -0
  167. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/preset.rbx.yml +0 -0
  168. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/.gitignore +0 -0
  169. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/gen.cpp +0 -0
  170. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/problem.rbx.yml +0 -0
  171. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/random.py +0 -0
  172. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/random.txt +0 -0
  173. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/sols/main.cpp +0 -0
  174. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/sols/slow.cpp +0 -0
  175. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/sols/wa.cpp +0 -0
  176. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/statement/olymp.sty +0 -0
  177. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/statement/projecao.png +0 -0
  178. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/statement/statement.rbx.tex +0 -0
  179. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/statement/template.rbx.tex +0 -0
  180. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/tests/samples/000.in +0 -0
  181. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/tests/samples/001.in +0 -0
  182. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/validator.cpp +0 -0
  183. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/presets/default/problem/wcmp.cpp +0 -0
  184. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/resources/templates/template.cpp +0 -0
  185. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/run.py +0 -0
  186. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/schema.py +0 -0
  187. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/submit.py +0 -0
  188. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/submitors/__init__.py +0 -0
  189. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/submitors/codeforces.py +0 -0
  190. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/submitors/submitor.py +0 -0
  191. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/test.py +0 -0
  192. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/testcase.py +0 -0
  193. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/testcase_rendering.py +0 -0
  194. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/testing_utils.py +0 -0
  195. {rbx_cp-0.5.48 → rbx_cp-0.5.50}/rbx/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rbx.cp
3
- Version: 0.5.48
3
+ Version: 0.5.50
4
4
  Summary:
5
5
  Author: Roberto Sales
6
6
  Requires-Python: >=3.9,<4.0
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "rbx.cp"
3
- version = "0.5.48"
3
+ version = "0.5.50"
4
4
  description = ""
5
5
  packages = [
6
6
  {include = "rbx"}
@@ -747,6 +747,7 @@ async def validate(
747
747
  rich_help_panel='Testing',
748
748
  help='Run unit tests for the validator and checker.',
749
749
  )
750
+ @package.within_problem
750
751
  def unit_tests():
751
752
  from rbx.box import unit
752
753
 
@@ -64,6 +64,7 @@ async def run_packager(
64
64
 
65
65
 
66
66
  @app.command('polygon', help='Build a package for Polygon.')
67
+ @package.within_problem
67
68
  @syncer.sync
68
69
  async def polygon(
69
70
  verification: environment.VerificationParam,
@@ -74,6 +75,7 @@ async def polygon(
74
75
 
75
76
 
76
77
  @app.command('boca', help='Build a package for BOCA.')
78
+ @package.within_problem
77
79
  @syncer.sync
78
80
  async def boca(
79
81
  verification: environment.VerificationParam,
@@ -84,6 +86,7 @@ async def boca(
84
86
 
85
87
 
86
88
  @app.command('moj', help='Build a package for MOJ.')
89
+ @package.within_problem
87
90
  @syncer.sync
88
91
  async def moj(
89
92
  verification: environment.VerificationParam,
@@ -356,8 +356,8 @@ class LimitModifiers(BaseModel):
356
356
  class ValidatorTest(BaseModel):
357
357
  model_config = ConfigDict(extra='forbid')
358
358
 
359
- input: pathlib.Path = Field(
360
- description='The input file to be used as unit test input for the validator.'
359
+ glob: str = Field(
360
+ description='A glob pattern for the input files to be used as unit test input for the validator.'
361
361
  )
362
362
  outcome: ValidatorOutcome = Field(
363
363
  default=ValidatorOutcome.VALID,
@@ -373,17 +373,12 @@ class ValidatorTest(BaseModel):
373
373
  class CheckerTest(BaseModel):
374
374
  model_config = ConfigDict(extra='forbid')
375
375
 
376
- input: Optional[pathlib.Path] = Field(
377
- default=None,
378
- description='The input file to be used as unit test input for the checker. If not specified, will pass an empty file.',
379
- )
380
- output: Optional[pathlib.Path] = Field(
381
- default=None,
382
- description='The solution output file to be used as unit test output for the checker. If not specified, will pass an empty file.',
383
- )
384
- answer: Optional[pathlib.Path] = Field(
385
- default=None,
386
- description='The answer file to be used as unit test answer for the checker. If not specified, will pass an empty file.',
376
+ glob: str = Field(
377
+ description="""
378
+ A glob pattern for the files to be used as unit test input for the checker.
379
+ This glob should simultaneously match the input, output, and answer files (.in, .out, .ans).
380
+ If one of them is not present, an empty file will be used instead.
381
+ """,
387
382
  )
388
383
 
389
384
  outcome: ExpectedOutcome = Field(
@@ -47,7 +47,12 @@ from rbx.box.tasks import (
47
47
  run_solution_on_testcase,
48
48
  )
49
49
  from rbx.box.testcase_extractors import extract_generation_testcases
50
- from rbx.box.testcase_utils import TestcaseEntry, find_built_testcases
50
+ from rbx.box.testcase_utils import (
51
+ TestcaseEntry,
52
+ find_built_testcases,
53
+ parse_interaction,
54
+ print_interaction,
55
+ )
51
56
  from rbx.grading.steps import (
52
57
  Evaluation,
53
58
  Outcome,
@@ -323,6 +328,19 @@ def _produce_solution_items(
323
328
  return res
324
329
 
325
330
 
331
+ def print_best_output(output_files: List[pathlib.Path], empty_warning: bool = False):
332
+ for output_file in output_files:
333
+ if not output_file.is_file():
334
+ continue
335
+ if output_file.suffix == '.pio':
336
+ print_interaction(parse_interaction(output_file))
337
+ else:
338
+ console.console.print(output_file.read_text())
339
+ return
340
+ if empty_warning:
341
+ console.console.print('[warning]Solution produced no output.[/warning]')
342
+
343
+
326
344
  def run_solutions(
327
345
  progress: Optional[StatusProgress] = None,
328
346
  tracked_solutions: Optional[Set[str]] = None,
@@ -528,6 +546,7 @@ def _run_interactive_solutions(
528
546
  output_dir=output_dir,
529
547
  interactor_digest=interactor_digest,
530
548
  verification=verification,
549
+ capture_pipes=True,
531
550
  )
532
551
 
533
552
  yield EvaluationItem(
@@ -589,18 +608,28 @@ async def run_and_print_interactive_solutions(
589
608
  )
590
609
 
591
610
  stdout_path = eval.log.stdout_absolute_path
592
- if print:
611
+ if print and stdout_path is not None:
612
+ if pkg.type == TaskType.COMMUNICATION:
613
+ console.console.rule('Interaction', style='status')
614
+ output_files = [
615
+ stdout_path.with_suffix('.pio'),
616
+ stdout_path.with_suffix('.pout'),
617
+ ]
618
+ print_best_output(output_files, empty_warning=True)
619
+
593
620
  console.console.rule('Output', style='status')
594
- if (
595
- eval.testcase.output is not None
596
- and stdout_path is not None
597
- and stdout_path.is_file()
598
- ):
599
- console.console.print(stdout_path.read_text())
600
- else:
601
- console.console.print('[warning]Solution produced no output.[/warning]')
621
+ output_files = [stdout_path]
622
+ print_best_output(output_files, empty_warning=True)
602
623
  elif stdout_path is not None:
603
- console.console.print(f'[status]Output:[/status] {stdout_path}')
624
+ if stdout_path.with_suffix('.pout').is_file():
625
+ stdout_path = stdout_path.with_suffix('.pout')
626
+
627
+ if stdout_path.is_file():
628
+ console.console.print(f'[status]Output:[/status] {stdout_path}')
629
+ if stdout_path.with_suffix('.pio').is_file():
630
+ console.console.print(
631
+ f'[status]Interaction:[/status] {stdout_path.with_suffix(".pio")}'
632
+ )
604
633
  if eval.log.stderr_absolute_path is not None:
605
634
  console.console.print(
606
635
  f'[status]Stderr:[/status] {eval.log.stderr_absolute_path}'
@@ -2,6 +2,8 @@ import pathlib
2
2
  import shutil
3
3
  from typing import List, Optional, Tuple
4
4
 
5
+ import rich
6
+ import rich.text
5
7
  import typer
6
8
  from pydantic import BaseModel
7
9
 
@@ -209,3 +211,13 @@ def parse_interaction(file: pathlib.Path) -> TestcaseInteraction:
209
211
  prefixes=(interactor_prefix, solution_prefix),
210
212
  entries=entries,
211
213
  )
214
+
215
+
216
+ def print_interaction(interaction: TestcaseInteraction):
217
+ for entry in interaction.entries:
218
+ text = rich.text.Text(entry.data)
219
+ if entry.pipe == 0:
220
+ text.stylize('status')
221
+ else:
222
+ text.stylize('info')
223
+ console.console.print(text, end='')
@@ -90,6 +90,7 @@ async def _generate_for_editing(
90
90
 
91
91
 
92
92
  @app.command('view, v', help='View a testcase in your default editor.')
93
+ @package.within_problem
93
94
  @syncer.sync
94
95
  async def view(
95
96
  tc: Annotated[
@@ -126,6 +127,7 @@ async def view(
126
127
 
127
128
 
128
129
  @app.command('info, i', help='Show information about testcases.')
130
+ @package.within_problem
129
131
  @syncer.sync
130
132
  async def info(
131
133
  pattern: Annotated[
@@ -0,0 +1,206 @@
1
+ import pathlib
2
+ from typing import List, Optional, Set
3
+
4
+ import syncer
5
+ from pydantic import BaseModel
6
+
7
+ from rbx import console
8
+ from rbx.box import checkers, package, validators
9
+ from rbx.box.schema import (
10
+ CheckerTest,
11
+ CodeItem,
12
+ ExpectedOutcome,
13
+ Testcase,
14
+ ValidatorOutcome,
15
+ ValidatorTest,
16
+ )
17
+ from rbx.utils import StatusProgress
18
+
19
+
20
+ class ValidatorTestEntry(BaseModel):
21
+ input: pathlib.Path
22
+ outcome: ValidatorOutcome
23
+ validator: Optional[CodeItem]
24
+
25
+
26
+ class CheckerTestEntry(BaseModel):
27
+ input: Optional[pathlib.Path] = None
28
+ output: Optional[pathlib.Path] = None
29
+ answer: Optional[pathlib.Path] = None
30
+ outcome: ExpectedOutcome
31
+
32
+ def running_tests_formatted_string(self) -> str:
33
+ res = []
34
+ if self.input:
35
+ res.append(f'[item]{self.input}[/item]')
36
+ if self.output:
37
+ res.append(f'[item]{self.output}[/item]')
38
+ if self.answer:
39
+ res.append(f'[item]{self.answer}[/item]')
40
+ return ', '.join(res)
41
+
42
+
43
+ def _extract_validator_test_entries(
44
+ tests: List[ValidatorTest],
45
+ ) -> List[ValidatorTestEntry]:
46
+ res: List[ValidatorTestEntry] = []
47
+ for test in tests:
48
+ for input in pathlib.Path().glob(str(test.glob)):
49
+ if not input.is_file():
50
+ continue
51
+ res.append(
52
+ ValidatorTestEntry(
53
+ input=input, outcome=test.outcome, validator=test.validator
54
+ )
55
+ )
56
+ return sorted(res, key=lambda x: x.input.name)
57
+
58
+
59
+ def _extract_checker_test_entries(tests: List[CheckerTest]) -> List[CheckerTestEntry]:
60
+ res: List[CheckerTestEntry] = []
61
+ seen: Set[pathlib.Path] = set()
62
+ for test in tests:
63
+ for file in pathlib.Path().glob(str(test.glob)):
64
+ if not file.is_file():
65
+ continue
66
+ if file.suffix not in ['.in', '.out', '.ans']:
67
+ continue
68
+ basefile = file.with_suffix('')
69
+ if basefile in seen:
70
+ continue
71
+ seen.add(basefile)
72
+ input = basefile.with_suffix('.in')
73
+ output = basefile.with_suffix('.out')
74
+ answer = basefile.with_suffix('.ans')
75
+ res.append(
76
+ CheckerTestEntry(
77
+ input=input if input.is_file() else None,
78
+ output=output if output.is_file() else None,
79
+ answer=answer if answer.is_file() else None,
80
+ outcome=test.outcome,
81
+ )
82
+ )
83
+ return res
84
+
85
+
86
+ def _get_validator_for_test(test: ValidatorTestEntry) -> Optional[CodeItem]:
87
+ pkg = package.find_problem_package_or_die()
88
+ if test.validator is not None:
89
+ return test.validator
90
+ return pkg.validator
91
+
92
+
93
+ async def run_validator_unit_tests(progress: StatusProgress):
94
+ pkg = package.find_problem_package_or_die()
95
+
96
+ entries = _extract_validator_test_entries(pkg.unitTests.validator)
97
+
98
+ vals: List[CodeItem] = []
99
+ for test in entries:
100
+ val = _get_validator_for_test(test)
101
+ if val is not None:
102
+ vals.append(val)
103
+
104
+ console.console.rule('Validator tests', style='info')
105
+ if not entries:
106
+ console.console.print(']No validator unit tests found.')
107
+ return
108
+
109
+ compiled_validators = validators.compile_validators(vals, progress=progress)
110
+
111
+ if progress:
112
+ progress.update('Running validator unit tests...')
113
+
114
+ for i, test in enumerate(entries):
115
+ val = _get_validator_for_test(test)
116
+ if val is None:
117
+ console.console.print(
118
+ f'[warning]No validator found for test [item]#{i + 1}[/item], skipping.[/warning]'
119
+ )
120
+ continue
121
+
122
+ compiled_digest = compiled_validators[str(val.path)]
123
+ info = await validators.validate_one_off(
124
+ test.input,
125
+ val,
126
+ compiled_digest,
127
+ )
128
+
129
+ is_valid = test.outcome == ValidatorOutcome.VALID
130
+
131
+ markup = (
132
+ '[success]OK[/success]' if info.ok == is_valid else '[error]FAIL[/error]'
133
+ )
134
+
135
+ console.console.print(
136
+ f'{markup} Unit test [item]#{i + 1}[/item] for [item]{test.input}[/item]'
137
+ )
138
+ console.console.print(f' [status]Expected[/status] {test.outcome.value}')
139
+ if info.ok != is_valid:
140
+ if info.ok:
141
+ console.console.print(' [status]Actual[/status] VALID')
142
+ else:
143
+ console.console.print(' [status]Actual[/status] INVALID')
144
+
145
+ if info.message:
146
+ console.console.print(f' [status]Message[/status] {info.message}')
147
+
148
+
149
+ async def run_checker_unit_tests(progress: StatusProgress):
150
+ pkg = package.find_problem_package_or_die()
151
+ if not pkg.unitTests.checker:
152
+ return
153
+
154
+ if not package.get_checker():
155
+ console.console.print(
156
+ '[warning]No checker found, skipping checker unit tests.[/warning]'
157
+ )
158
+ return
159
+
160
+ console.console.rule('Checker tests', style='info')
161
+
162
+ entries = _extract_checker_test_entries(pkg.unitTests.checker)
163
+ if not entries:
164
+ console.console.print('No checker unit tests found.')
165
+ return
166
+
167
+ compiled_digest = checkers.compile_checker(progress=progress)
168
+
169
+ if progress:
170
+ progress.update('Running checker unit tests...')
171
+
172
+ empty_file = package.get_empty_sentinel_path()
173
+
174
+ for i, test in enumerate(entries):
175
+ result = await checkers.check(
176
+ compiled_digest,
177
+ run_log=None,
178
+ testcase=Testcase(
179
+ inputPath=test.input or empty_file,
180
+ outputPath=test.answer or empty_file,
181
+ ),
182
+ program_output=test.output or empty_file,
183
+ skip_run_log=True,
184
+ )
185
+
186
+ markup = (
187
+ '[success]OK[/success]'
188
+ if test.outcome.match(result.outcome)
189
+ else '[error]FAIL[/error]'
190
+ )
191
+
192
+ console.console.print(
193
+ f'{markup} Unit test [item]#{i + 1}[/item] ({test.running_tests_formatted_string()})'
194
+ )
195
+ console.console.print(f' [status]Expected[/status] {test.outcome.name}')
196
+
197
+ if not test.outcome.match(result.outcome):
198
+ console.console.print(f' [status]Actual[/status] {result.outcome.name}')
199
+ if result.message:
200
+ console.console.print(f' [status]Message[/status] {result.message}')
201
+
202
+
203
+ @syncer.sync
204
+ async def run_unit_tests(progress: StatusProgress):
205
+ await run_validator_unit_tests(progress)
206
+ await run_checker_unit_tests(progress)
@@ -1,116 +0,0 @@
1
- from typing import List, Optional
2
-
3
- import syncer
4
-
5
- from rbx import console
6
- from rbx.box import checkers, package, validators
7
- from rbx.box.schema import CodeItem, Testcase, ValidatorOutcome, ValidatorTest
8
- from rbx.utils import StatusProgress
9
-
10
-
11
- def _get_validator_for_test(test: ValidatorTest) -> Optional[CodeItem]:
12
- pkg = package.find_problem_package_or_die()
13
- if test.validator is not None:
14
- return test.validator
15
- return pkg.validator
16
-
17
-
18
- async def run_validator_unit_tests(progress: StatusProgress):
19
- pkg = package.find_problem_package_or_die()
20
-
21
- vals: List[CodeItem] = []
22
- for test in pkg.unitTests.validator:
23
- val = _get_validator_for_test(test)
24
- if val is not None:
25
- vals.append(val)
26
-
27
- compiled_validators = validators.compile_validators(vals, progress=progress)
28
-
29
- if progress:
30
- progress.update('Running validator unit tests...')
31
-
32
- console.console.rule('Validator tests', style='info')
33
-
34
- for i, test in enumerate(pkg.unitTests.validator):
35
- val = _get_validator_for_test(test)
36
- if val is None:
37
- console.console.print(
38
- f'[warning]No validator found for test [item]#{i + 1}[/item], skipping.[/warning]'
39
- )
40
- continue
41
-
42
- compiled_digest = compiled_validators[str(val.path)]
43
- info = await validators.validate_one_off(
44
- test.input,
45
- val,
46
- compiled_digest,
47
- )
48
-
49
- is_valid = test.outcome == ValidatorOutcome.VALID
50
-
51
- markup = (
52
- '[success]OK[/success]' if info.ok == is_valid else '[error]FAIL[/error]'
53
- )
54
-
55
- console.console.print(
56
- f'{markup} Unit test [item]#{i + 1}[/item] for [item]{test.input}[/item]'
57
- )
58
- console.console.print(f' [status]Expected[/status] {test.outcome.value}')
59
- if info.ok != is_valid:
60
- if info.ok:
61
- console.console.print(' [status]Actual[/status] VALID')
62
- else:
63
- console.console.print(f' [status]Actual[/status] {info.message}')
64
-
65
-
66
- async def run_checker_unit_tests(progress: StatusProgress):
67
- pkg = package.find_problem_package_or_die()
68
- if not pkg.unitTests.checker:
69
- return
70
-
71
- if not package.get_checker():
72
- console.console.print(
73
- '[warning]No checker found, skipping checker unit tests.[/warning]'
74
- )
75
- return
76
-
77
- compiled_digest = checkers.compile_checker(progress=progress)
78
-
79
- if progress:
80
- progress.update('Running checker unit tests...')
81
-
82
- console.console.rule('Checker tests', style='info')
83
-
84
- empty_file = package.get_empty_sentinel_path()
85
-
86
- for i, test in enumerate(pkg.unitTests.checker):
87
- result = await checkers.check(
88
- compiled_digest,
89
- run_log=None,
90
- testcase=Testcase(
91
- inputPath=test.input or empty_file,
92
- outputPath=test.answer or empty_file,
93
- ),
94
- program_output=test.output or empty_file,
95
- skip_run_log=True,
96
- )
97
-
98
- markup = (
99
- '[success]OK[/success]'
100
- if test.outcome.match(result.outcome)
101
- else '[error]FAIL[/error]'
102
- )
103
-
104
- console.console.print(f'{markup} Unit test [item]#{i + 1}[/item]')
105
- console.console.print(f' [status]Expected[/status] {test.outcome.name}')
106
-
107
- if not test.outcome.match(result.outcome):
108
- console.console.print(f' [status]Actual[/status] {result.outcome.name}')
109
- if result.message:
110
- console.console.print(f' [status]Message[/status] {result.message}')
111
-
112
-
113
- @syncer.sync
114
- async def run_unit_tests(progress: StatusProgress):
115
- await run_validator_unit_tests(progress)
116
- await run_checker_unit_tests(progress)
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