rbx.cp 0.5.62__tar.gz → 0.5.64__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 (219) hide show
  1. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/PKG-INFO +1 -1
  2. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/pyproject.toml +1 -1
  3. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/contest/build_contest_statements.py +2 -1
  4. rbx_cp-0.5.64/rbx/box/formatting.py +35 -0
  5. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/packaging/boca/upload.py +18 -0
  6. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/packaging/main.py +4 -3
  7. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/setter_config.py +4 -0
  8. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/solutions.py +14 -11
  9. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/statements/build_statements.py +2 -1
  10. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/screens/run_test_explorer.py +12 -1
  11. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/screens/test_explorer.py +14 -1
  12. rbx_cp-0.5.64/rbx/box/ui/widgets/interaction_box.py +59 -0
  13. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/widgets/test_output_box.py +11 -2
  14. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/widgets/two_sided_test_output_box.py +4 -0
  15. rbx_cp-0.5.62/rbx/box/formatting.py +0 -10
  16. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/LICENSE +0 -0
  17. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/README.md +0 -0
  18. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/__init__.py +0 -0
  19. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/annotations.py +0 -0
  20. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/autoenum.py +0 -0
  21. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/__init__.py +0 -0
  22. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/builder.py +0 -0
  23. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/cd.py +0 -0
  24. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/checkers.py +0 -0
  25. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/cli.py +0 -0
  26. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/code.py +0 -0
  27. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/compile.py +0 -0
  28. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/conftest.py +0 -0
  29. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/contest/__init__.py +0 -0
  30. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/contest/contest_package.py +0 -0
  31. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/contest/contest_utils.py +0 -0
  32. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/contest/main.py +0 -0
  33. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/contest/schema.py +0 -0
  34. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/contest/statements.py +0 -0
  35. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/creation.py +0 -0
  36. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/deferred.py +0 -0
  37. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/download.py +0 -0
  38. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/dump_schemas.py +0 -0
  39. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/environment.py +0 -0
  40. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/extensions.py +0 -0
  41. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/generators.py +0 -0
  42. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/generators_test.py +0 -0
  43. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/git_utils.py +0 -0
  44. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/header.py +0 -0
  45. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/lazy_importing_main.py +0 -0
  46. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/lazy_importing_test.py +0 -0
  47. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/main.py +0 -0
  48. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/naming.py +0 -0
  49. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/package.py +0 -0
  50. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/packaging/boca/extension.py +0 -0
  51. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/packaging/boca/packager.py +0 -0
  52. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/packaging/contest_main.py +0 -0
  53. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/packaging/moj/packager.py +0 -0
  54. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/packaging/packager.py +0 -0
  55. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/packaging/polygon/packager.py +0 -0
  56. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/packaging/polygon/polygon_api.py +0 -0
  57. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/packaging/polygon/test.py +0 -0
  58. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/packaging/polygon/upload.py +0 -0
  59. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/packaging/polygon/xml_schema.py +0 -0
  60. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/presets/__init__.py +0 -0
  61. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/presets/fetch.py +0 -0
  62. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/presets/lock_schema.py +0 -0
  63. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/presets/schema.py +0 -0
  64. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/retries.py +0 -0
  65. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/sanitizers/warning_stack.py +0 -0
  66. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/schema.py +0 -0
  67. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/solutions_test.py +0 -0
  68. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/state.py +0 -0
  69. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/statements/__init__.py +0 -0
  70. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/statements/builders.py +0 -0
  71. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/statements/joiners.py +0 -0
  72. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/statements/latex.py +0 -0
  73. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/statements/latex_jinja.py +0 -0
  74. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/statements/schema.py +0 -0
  75. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/stresses.py +0 -0
  76. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/stressing/__init__.py +0 -0
  77. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/stressing/finder_parser.py +0 -0
  78. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/stressing/generator_parser.py +0 -0
  79. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/tasks.py +0 -0
  80. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/testcase_extractors.py +0 -0
  81. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/testcase_utils.py +0 -0
  82. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/testcases/__init__.py +0 -0
  83. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/testcases/main.py +0 -0
  84. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/__init__.py +0 -0
  85. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/captured_log.py +0 -0
  86. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/css/app.tcss +0 -0
  87. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/main.py +0 -0
  88. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/screens/__init__.py +0 -0
  89. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/screens/build.py +0 -0
  90. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/screens/command.py +0 -0
  91. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/screens/error.py +0 -0
  92. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/screens/run.py +0 -0
  93. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/screens/run_explorer.py +0 -0
  94. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/screens/selector.py +0 -0
  95. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/utils/__init__.py +0 -0
  96. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/utils/run_ui.py +0 -0
  97. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/widgets/__init__.py +0 -0
  98. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/widgets/file_log.py +0 -0
  99. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/ui/widgets/rich_log_box.py +0 -0
  100. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/unit.py +0 -0
  101. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/validators.py +0 -0
  102. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/box/validators_test.py +0 -0
  103. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/checker.py +0 -0
  104. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/clone.py +0 -0
  105. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/config.py +0 -0
  106. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/conftest.py +0 -0
  107. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/console.py +0 -0
  108. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/create.py +0 -0
  109. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/edit.py +0 -0
  110. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/__init__.py +0 -0
  111. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/caching.py +0 -0
  112. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/conftest.py +0 -0
  113. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/judge/__init__.py +0 -0
  114. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/judge/cacher.py +0 -0
  115. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/judge/digester.py +0 -0
  116. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/judge/sandbox.py +0 -0
  117. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/judge/sandboxes/__init__.py +0 -0
  118. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/judge/sandboxes/isolate.py +0 -0
  119. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/judge/sandboxes/stupid_sandbox.py +0 -0
  120. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/judge/sandboxes/timeit.py +0 -0
  121. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/judge/storage.py +0 -0
  122. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/judge/test.py +0 -0
  123. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/judge/testiso.py +0 -0
  124. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/limits.py +0 -0
  125. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/processing_context.py +0 -0
  126. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/steps.py +0 -0
  127. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/steps_with_caching.py +0 -0
  128. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading/steps_with_caching_run_test.py +0 -0
  129. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/grading_utils.py +0 -0
  130. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/hydration.py +0 -0
  131. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/main.py +0 -0
  132. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/metadata.py +0 -0
  133. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/providers/__init__.py +0 -0
  134. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/providers/codeforces.py +0 -0
  135. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/providers/provider.py +0 -0
  136. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/checkers/boilerplate.cpp +0 -0
  137. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/default_config.json +0 -0
  138. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/default_setter_config.mac.yml +0 -0
  139. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/default_setter_config.yml +0 -0
  140. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/envs/default.rbx.yml +0 -0
  141. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/envs/isolate.rbx.yml +0 -0
  142. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/checker.sh +0 -0
  143. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/compare.sh +0 -0
  144. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/compile/c +0 -0
  145. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/compile/cc +0 -0
  146. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/compile/cpp +0 -0
  147. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/compile/java +0 -0
  148. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/compile/kt +0 -0
  149. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/compile/pas +0 -0
  150. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/compile/py2 +0 -0
  151. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/compile/py3 +0 -0
  152. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/interactive/c +0 -0
  153. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/interactive/cc +0 -0
  154. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/interactive/cpp +0 -0
  155. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/interactive/java +0 -0
  156. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/interactive/kt +0 -0
  157. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/interactive/py2 +0 -0
  158. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/interactive/py3 +0 -0
  159. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/interactor_compile.sh +0 -0
  160. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/run/bkp +0 -0
  161. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/run/c +0 -0
  162. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/run/cc +0 -0
  163. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/run/cpp +0 -0
  164. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/run/java +0 -0
  165. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/run/kt +0 -0
  166. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/run/py2 +0 -0
  167. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/boca/run/py3 +0 -0
  168. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/c/compile.sh +0 -0
  169. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/c/prep.sh +0 -0
  170. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/c/run.sh +0 -0
  171. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/compare.sh +0 -0
  172. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/cpp/compile.sh +0 -0
  173. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/cpp/prep.sh +0 -0
  174. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/cpp/run.sh +0 -0
  175. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/interactor_prep.sh +0 -0
  176. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/interactor_run.sh +0 -0
  177. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/java/compile.sh +0 -0
  178. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/java/prep.sh +0 -0
  179. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/java/run.sh +0 -0
  180. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/py2/compile.sh +0 -0
  181. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/py2/prep.sh +0 -0
  182. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/py2/run.sh +0 -0
  183. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/py3/compile.sh +0 -0
  184. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/py3/prep.sh +0 -0
  185. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/packagers/moj/scripts/py3/run.sh +0 -0
  186. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/contest/contest.rbx.yml +0 -0
  187. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/contest/statement/contest.rbx.tex +0 -0
  188. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/contest/statement/olymp.sty +0 -0
  189. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/contest/statement/template.rbx.tex +0 -0
  190. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/preset.rbx.yml +0 -0
  191. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/.gitignore +0 -0
  192. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/gen.cpp +0 -0
  193. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/problem.rbx.yml +0 -0
  194. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/random.py +0 -0
  195. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/random.txt +0 -0
  196. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/sols/main.cpp +0 -0
  197. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/sols/slow.cpp +0 -0
  198. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/sols/wa.cpp +0 -0
  199. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/statement/olymp.sty +0 -0
  200. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/statement/projecao.png +0 -0
  201. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/statement/statement.rbx.tex +0 -0
  202. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/statement/template.rbx.tex +0 -0
  203. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/tests/samples/000.in +0 -0
  204. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/tests/samples/001.in +0 -0
  205. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/validator.cpp +0 -0
  206. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/presets/default/problem/wcmp.cpp +0 -0
  207. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/templates/rbx.h +0 -0
  208. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/resources/templates/template.cpp +0 -0
  209. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/run.py +0 -0
  210. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/schema.py +0 -0
  211. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/submit.py +0 -0
  212. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/submitors/__init__.py +0 -0
  213. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/submitors/codeforces.py +0 -0
  214. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/submitors/submitor.py +0 -0
  215. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/test.py +0 -0
  216. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/testcase.py +0 -0
  217. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/testcase_rendering.py +0 -0
  218. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/testing_utils.py +0 -0
  219. {rbx_cp-0.5.62 → rbx_cp-0.5.64}/rbx/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rbx.cp
3
- Version: 0.5.62
3
+ Version: 0.5.64
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.62"
3
+ version = "0.5.64"
4
4
  description = ""
5
5
  packages = [
6
6
  {include = "rbx"}
@@ -10,6 +10,7 @@ from rbx import console, testing_utils
10
10
  from rbx.box import cd, package
11
11
  from rbx.box.contest.contest_package import get_problems
12
12
  from rbx.box.contest.schema import Contest, ContestProblem, ContestStatement
13
+ from rbx.box.formatting import href
13
14
  from rbx.box.schema import Package, Testcase
14
15
  from rbx.box.statements import build_statements
15
16
  from rbx.box.statements.build_statements import (
@@ -344,6 +345,6 @@ def build_statement(
344
345
  console.console.print(
345
346
  f'Statement built successfully for language '
346
347
  f'[item]{statement.language}[/item] at '
347
- f'[item]{statement_path.resolve()}[/item]'
348
+ f'{href(statement_path)}'
348
349
  )
349
350
  return statement_path
@@ -0,0 +1,35 @@
1
+ import os
2
+ import pathlib
3
+ from typing import Optional
4
+
5
+ from rbx.box import setter_config
6
+
7
+
8
+ def href(url: os.PathLike[str], text: Optional[str] = None, style: str = 'item') -> str:
9
+ custom_text = False
10
+ if text is None:
11
+ text = str(url)
12
+ else:
13
+ custom_text = True
14
+
15
+ if not custom_text:
16
+ if not setter_config.get_setter_config().hyperlinks:
17
+ return f'[{style}]{text}[/{style}]'
18
+ if os.environ.get('TERM') in ['vscode']:
19
+ return f'[{style}]{text}[/{style}]'
20
+
21
+ if isinstance(url, pathlib.Path):
22
+ url = url.resolve()
23
+ return f'[{style}][link={url}]{text}[/link][/{style}]'
24
+
25
+
26
+ def get_formatted_memory(memory_in_bytes: int, mib_decimal_places: int = 0) -> str:
27
+ if memory_in_bytes < 1024 * 1024:
28
+ if memory_in_bytes < 1024:
29
+ return f'{memory_in_bytes} B'
30
+ return f'{memory_in_bytes / 1024:.0f} KiB'
31
+ return f'{memory_in_bytes / (1024 * 1024):.{mib_decimal_places}f} MiB'
32
+
33
+
34
+ def get_formatted_time(time_in_ms: int) -> str:
35
+ return f'{time_in_ms} ms'
@@ -1,4 +1,5 @@
1
1
  import datetime
2
+ import functools
2
3
  import hashlib
3
4
  import os
4
5
  import pathlib
@@ -41,6 +42,8 @@ class BocaUploader:
41
42
  self.username = _parse_env_var('BOCA_USERNAME', username)
42
43
  self.password = _parse_env_var('BOCA_PASSWORD', password)
43
44
 
45
+ self.loggedIn = False
46
+
44
47
  self.br = mechanize.Browser()
45
48
  self.br.set_handle_robots(False)
46
49
  self.br.addheaders = [ # type: ignore
@@ -140,6 +143,9 @@ class BocaUploader:
140
143
  return self.log_response_alert(response, error_msg)
141
144
 
142
145
  def login(self):
146
+ if self.loggedIn:
147
+ return
148
+
143
149
  _, html = self.open(
144
150
  f'{self.base_url}', error_msg='Error while opening BOCA login page'
145
151
  )
@@ -157,6 +163,8 @@ class BocaUploader:
157
163
  login_url = f'{self.base_url}?name={self.username}&password={pwd_hash}'
158
164
  self.open(login_url, error_msg='Error while logging in to BOCA')
159
165
 
166
+ self.loggedIn = True
167
+
160
168
  def upload(self, file: pathlib.Path) -> bool:
161
169
  self.open(
162
170
  f'{self.base_url}/admin/problem.php',
@@ -226,6 +234,7 @@ class BocaUploader:
226
234
  console.console.print(
227
235
  f'[warning]Potentially transient error while uploading problem to BOCA. Retrying ({tries}/{RETRIES})...[/warning]'
228
236
  )
237
+ self.loggedIn = False
229
238
  continue
230
239
 
231
240
  ok = True
@@ -245,3 +254,12 @@ class BocaUploader:
245
254
  '[warning]Check [item]https://www.php.net/manual/en/ini.core.php#ini.sect.file-uploads[/item] for more information.[/warning]'
246
255
  )
247
256
  raise typer.Exit(1)
257
+
258
+
259
+ @functools.lru_cache
260
+ def get_boca_uploader(
261
+ base_url: Optional[str] = None,
262
+ username: Optional[str] = None,
263
+ password: Optional[str] = None,
264
+ ) -> BocaUploader:
265
+ return BocaUploader(base_url, username, password)
@@ -7,6 +7,7 @@ import typer
7
7
 
8
8
  from rbx import annotations, console
9
9
  from rbx.box import environment, header, package
10
+ from rbx.box.formatting import href
10
11
  from rbx.box.naming import get_problem_name_with_contest_info
11
12
  from rbx.box.package import get_build_path
12
13
  from rbx.box.packaging.packager import BasePackager, BuiltStatement
@@ -62,7 +63,7 @@ async def run_packager(
62
63
  console.console.print(
63
64
  f'[success]Problem packaged for [item]{packager.name()}[/item]![/success]'
64
65
  )
65
- console.console.print(f'Package was saved at [item]{result_path.resolve()}[/item]')
66
+ console.console.print(f'Package was saved at {href(result_path)}')
66
67
  return result_path
67
68
 
68
69
 
@@ -105,9 +106,9 @@ async def boca(
105
106
  result_path = await run_packager(BocaPackager, verification=verification)
106
107
 
107
108
  if upload:
108
- from rbx.box.packaging.boca.upload import BocaUploader
109
+ from rbx.box.packaging.boca.upload import get_boca_uploader
109
110
 
110
- uploader = BocaUploader()
111
+ uploader = get_boca_uploader()
111
112
  uploader.login_and_upload(result_path)
112
113
 
113
114
 
@@ -71,6 +71,10 @@ class SetterConfig(BaseModel):
71
71
  default={},
72
72
  description='Substitutions to apply to commands before running them.',
73
73
  )
74
+ hyperlinks: bool = Field(
75
+ default=True,
76
+ description='Whether to use hyperlinks in the terminal output.',
77
+ )
74
78
 
75
79
  def substitute_command(self, command: str, sanitized: bool = False) -> str:
76
80
  exe = shlex.split(command)[0]
@@ -16,7 +16,7 @@ import typer
16
16
  from pydantic import BaseModel
17
17
 
18
18
  from rbx import console, utils
19
- from rbx.box import checkers, environment, package
19
+ from rbx.box import checkers, environment, package, state
20
20
  from rbx.box.code import (
21
21
  SanitizationLevel,
22
22
  compile_item,
@@ -26,7 +26,7 @@ from rbx.box.deferred import Deferred
26
26
  from rbx.box.environment import (
27
27
  VerificationLevel,
28
28
  )
29
- from rbx.box.formatting import get_formatted_memory, get_formatted_time
29
+ from rbx.box.formatting import get_formatted_memory, get_formatted_time, href
30
30
  from rbx.box.generators import (
31
31
  GenerationMetadata,
32
32
  expand_generator_call,
@@ -87,6 +87,7 @@ class SolutionReportSkeleton(BaseModel):
87
87
  groups: List[GroupSkeleton]
88
88
  limits: Dict[str, Limits]
89
89
  verification: VerificationLevel
90
+ capture_pipes: bool = False
90
91
 
91
92
  def find_group_skeleton(self, group_name: str) -> Optional[GroupSkeleton]:
92
93
  groups = [group for group in self.groups if group.name == group_name]
@@ -165,7 +166,7 @@ def compile_solutions(
165
166
  ):
166
167
  continue
167
168
  if progress:
168
- progress.update(f'Compiling solution [item]{solution.path}[/item]...')
169
+ progress.update(f'Compiling solution {href(solution.path)}...')
169
170
  try:
170
171
  compiled_solutions[solution.path] = compile_item(
171
172
  solution,
@@ -175,7 +176,7 @@ def compile_solutions(
175
176
  )
176
177
  except:
177
178
  console.console.print(
178
- f'[error]Failed compiling solution [item]{solution.path}[/item][/error]'
179
+ f'[error]Failed compiling solution {href(solution.path)}.[/error]'
179
180
  )
180
181
  raise
181
182
 
@@ -203,7 +204,7 @@ def _run_solution(
203
204
 
204
205
  if progress:
205
206
  progress.update(
206
- f'Running solution [item]{solution.path}[/item] on test [item]{group.name}[/item] / [item]{i}[/item]...'
207
+ f'Running solution {href(solution.path)} on test [item]{group.name}[/item] / [item]{i}[/item]...'
207
208
  )
208
209
 
209
210
  async def run_fn(i=i, testcase=testcase, output_path=output_path):
@@ -303,6 +304,7 @@ def _get_report_skeleton(
303
304
  limits=limits,
304
305
  entries=entries,
305
306
  verification=verification,
307
+ capture_pipes=state.STATE.debug_logs,
306
308
  )
307
309
 
308
310
  skeleton_file = runs_dir / 'skeleton.yml'
@@ -627,6 +629,7 @@ def _get_interactive_skeleton(
627
629
  limits=limits,
628
630
  entries=[],
629
631
  verification=verification,
632
+ capture_pipes=True,
630
633
  )
631
634
 
632
635
  skeleton_file = irun_dir / 'skeleton.yml'
@@ -1023,8 +1026,8 @@ def _print_solution_header(
1023
1026
  solution: SolutionSkeleton,
1024
1027
  console: rich.console.Console,
1025
1028
  ):
1026
- console.print(f'[item]{solution.path}[/item]', end=' ')
1027
- console.print(f'({solution.runs_dir})')
1029
+ console.print(f'{href(solution.path)}', end=' ')
1030
+ console.print(f'({href(solution.runs_dir, style="info")})')
1028
1031
 
1029
1032
 
1030
1033
  @dataclasses.dataclass
@@ -1049,14 +1052,14 @@ class TimingSummary:
1049
1052
  def print(self, console: rich.console.Console, tl: Optional[int] = None):
1050
1053
  if self.slowest_good is not None:
1051
1054
  console.print(
1052
- f'Slowest [success]OK[/success] solution: {self.slowest_good.time} ms, [item]{self.slowest_good.solution.path}[/item]'
1055
+ f'Slowest [success]OK[/success] solution: {self.slowest_good.time} ms, {href(self.slowest_good.solution.path)}'
1053
1056
  )
1054
1057
  if self.fastest_slow is not None:
1055
1058
  fastest_slow = self.fastest_slow.time
1056
1059
  if tl is not None and self.fastest_slow.time > tl:
1057
1060
  fastest_slow = f'>{tl}'
1058
1061
  console.print(
1059
- f'Fastest [error]slow[/error] solution: {fastest_slow} ms, [item]{self.fastest_slow.solution.path}[/item]'
1062
+ f'Fastest [error]slow[/error] solution: {fastest_slow} ms, {href(self.fastest_slow.solution.path)}'
1060
1063
  )
1061
1064
 
1062
1065
 
@@ -1181,7 +1184,7 @@ async def _render_detailed_group_table(
1181
1184
  ) -> rich.table.Table:
1182
1185
  table = rich.table.Table()
1183
1186
  for solution in skeleton.solutions:
1184
- table.add_column(f'[item]{solution.path}[/item]', justify='full')
1187
+ table.add_column(f'{href(solution.path)}', justify='full')
1185
1188
 
1186
1189
  padded_rows = []
1187
1190
 
@@ -1421,7 +1424,7 @@ async def estimate_time_limit(
1421
1424
 
1422
1425
  if not timings:
1423
1426
  console.print(
1424
- f'[warning]No timings for solution [item]{solution.path}[/item].[/warning]'
1427
+ f'[warning]No timings for solution {href(solution.path)}.[/warning]'
1425
1428
  )
1426
1429
  continue
1427
1430
 
@@ -8,6 +8,7 @@ import typer
8
8
 
9
9
  from rbx import annotations, console
10
10
  from rbx.box import environment, naming, package
11
+ from rbx.box.formatting import href
11
12
  from rbx.box.schema import Package
12
13
  from rbx.box.statements.builders import (
13
14
  BUILDER_LIST,
@@ -302,7 +303,7 @@ def build_statement(
302
303
  console.console.print(
303
304
  f'Statement built successfully for language '
304
305
  f'[item]{statement.language}[/item] at '
305
- f'[item]{statement_path.resolve()}[/item]'
306
+ f'{href(statement_path)}'
306
307
  )
307
308
  return statement_path
308
309
 
@@ -7,6 +7,7 @@ from textual.screen import Screen
7
7
  from textual.widgets import Footer, Header, Label, ListItem, ListView
8
8
 
9
9
  from rbx.box import package
10
+ from rbx.box.schema import TaskType
10
11
  from rbx.box.solutions import SolutionReportSkeleton, SolutionSkeleton
11
12
  from rbx.box.testcase_extractors import (
12
13
  GenerationTestcaseEntry,
@@ -64,6 +65,9 @@ class RunTestExplorerScreen(Screen):
64
65
  self.query_one('#test-list').border_title = 'Tests'
65
66
  self.query_one('#test-input').border_title = 'Input'
66
67
 
68
+ # Ensure the output is show, even for interactive tests
69
+ self.action_show_output()
70
+
67
71
  await self._update_tests()
68
72
 
69
73
  def _get_rendering_data(
@@ -118,8 +122,15 @@ class RunTestExplorerScreen(Screen):
118
122
  def has_diffable_solution(self) -> bool:
119
123
  return self.diff_solution is not None or package.get_main_solution() is not None
120
124
 
125
+ def should_show_interaction(self) -> bool:
126
+ pkg = package.find_problem_package_or_die()
127
+ return pkg.type == TaskType.COMMUNICATION and self.skeleton.capture_pipes
128
+
121
129
  def action_show_output(self):
122
- self.query_one('#test-output', TwoSidedTestBoxWidget).show_output()
130
+ if self.should_show_interaction():
131
+ self.query_one('#test-output', TwoSidedTestBoxWidget).show_interaction()
132
+ else:
133
+ self.query_one('#test-output', TwoSidedTestBoxWidget).show_output()
123
134
 
124
135
  def action_show_stderr(self):
125
136
  self.query_one('#test-output', TwoSidedTestBoxWidget).show_stderr()
@@ -5,6 +5,8 @@ from textual.containers import Horizontal, Vertical
5
5
  from textual.screen import Screen
6
6
  from textual.widgets import Footer, Header, Label, ListItem, ListView, RichLog
7
7
 
8
+ from rbx.box import package
9
+ from rbx.box.schema import TaskType
8
10
  from rbx.box.testcase_extractors import (
9
11
  GenerationTestcaseEntry,
10
12
  extract_generation_testcases_from_groups,
@@ -42,6 +44,9 @@ class TestExplorerScreen(Screen):
42
44
  self.query_one('#test-list').border_title = 'Tests'
43
45
  self.query_one('#test-input').border_title = 'Input'
44
46
 
47
+ # Ensure either output or interaction is visible.
48
+ self.action_show_output()
49
+
45
50
  metadata = self.query_one('#test-metadata', RichLogBox)
46
51
  metadata.display = False
47
52
  metadata.border_title = 'Metadata'
@@ -67,6 +72,7 @@ class TestExplorerScreen(Screen):
67
72
  entry = self._entries[index]
68
73
  input.path = entry.metadata.copied_to.inputPath
69
74
 
75
+ assert entry.metadata.copied_to.outputPath is not None
70
76
  output.data = TestcaseRenderingData.from_one_path(
71
77
  entry.metadata.copied_to.outputPath
72
78
  )
@@ -105,8 +111,15 @@ class TestExplorerScreen(Screen):
105
111
  [ListItem(Label(name)) for name in test_names]
106
112
  )
107
113
 
114
+ def is_interactive(self) -> bool:
115
+ pkg = package.find_problem_package_or_die()
116
+ return pkg.type == TaskType.COMMUNICATION
117
+
108
118
  def action_show_output(self):
109
- self.query_one('#test-output', TestBoxWidget).show_output()
119
+ if self.is_interactive():
120
+ self.query_one('#test-output', TestBoxWidget).show_interaction()
121
+ else:
122
+ self.query_one('#test-output', TestBoxWidget).show_output()
110
123
 
111
124
  def action_show_stderr(self):
112
125
  self.query_one('#test-output', TestBoxWidget).show_stderr()
@@ -0,0 +1,59 @@
1
+ import asyncio
2
+ import pathlib
3
+ from typing import Optional
4
+
5
+ import rich.text
6
+ from textual import work
7
+ from textual.reactive import reactive
8
+
9
+ from rbx.box import testcase_utils
10
+ from rbx.box.ui.widgets.rich_log_box import RichLogBox
11
+
12
+ BATCH_SIZE = 1024
13
+
14
+
15
+ class InteractionBox(RichLogBox):
16
+ DEFAULT_CSS = """
17
+ InteractionBox {
18
+ border: solid $accent;
19
+ height: 1fr;
20
+ width: 1fr;
21
+ }
22
+ """
23
+
24
+ path: reactive[Optional[pathlib.Path]] = reactive(None)
25
+
26
+ def on_mount(self):
27
+ super().on_mount()
28
+ self.auto_scroll = False
29
+ self.can_focus = False
30
+
31
+ @work(exclusive=True)
32
+ async def _load_file(self, path: pathlib.Path):
33
+ self.clear()
34
+ path_str = str(path.relative_to(pathlib.Path.cwd()))
35
+ self.border_subtitle = f'{path_str} (loading...)'
36
+
37
+ interaction = await asyncio.to_thread(testcase_utils.parse_interaction, path)
38
+
39
+ for entry in interaction.entries:
40
+ if entry.pipe == 0:
41
+ self.write(rich.text.Text(entry.data.rstrip(), style='green'))
42
+ else:
43
+ self.write(rich.text.Text(entry.data.rstrip()))
44
+
45
+ self.border_subtitle = path_str
46
+
47
+ async def watch_path(self, path: Optional[pathlib.Path]):
48
+ self.clear()
49
+
50
+ if path is None:
51
+ self.border_subtitle = '(no file selected)'
52
+ return
53
+
54
+ if not path.is_file():
55
+ path_str = str(path.relative_to(pathlib.Path.cwd()))
56
+ self.border_subtitle = f'{path_str} (does not exist)'
57
+ return
58
+
59
+ self._load_file(path)
@@ -9,6 +9,7 @@ from textual.widget import Widget
9
9
  from textual.widgets import ContentSwitcher
10
10
 
11
11
  from rbx.box.ui.widgets.file_log import FileLog
12
+ from rbx.box.ui.widgets.interaction_box import InteractionBox
12
13
  from rbx.box.ui.widgets.rich_log_box import RichLogBox
13
14
 
14
15
 
@@ -17,6 +18,7 @@ class TestcaseRenderingData:
17
18
  input_path: Optional[pathlib.Path] = None
18
19
  output_path: Optional[pathlib.Path] = None
19
20
  stderr_path: Optional[pathlib.Path] = None
21
+ interaction_path: Optional[pathlib.Path] = None
20
22
  log_path: Optional[pathlib.Path] = None
21
23
  rich_content: Optional[str] = None
22
24
 
@@ -27,6 +29,7 @@ class TestcaseRenderingData:
27
29
  output_path=path.with_suffix('.out'),
28
30
  stderr_path=path.with_suffix('.err'),
29
31
  log_path=path.with_suffix('.log'),
32
+ interaction_path=path.with_suffix('.pio'),
30
33
  )
31
34
 
32
35
 
@@ -41,12 +44,14 @@ class TestBoxWidget(Widget, can_focus=False):
41
44
  output: FileLog
42
45
  stderr: FileLog
43
46
  log: FileLog
47
+ interaction: FileLog
44
48
 
45
49
  def logs(self) -> Logs:
46
50
  return self.Logs(
47
51
  output=self.query_one('#test-box-output', FileLog),
48
52
  stderr=self.query_one('#test-box-stderr', FileLog),
49
53
  log=self.query_one('#test-box-log', FileLog),
54
+ interaction=self.query_one('#test-box-interaction', InteractionBox),
50
55
  )
51
56
 
52
57
  def compose(self) -> ComposeResult:
@@ -55,6 +60,7 @@ class TestBoxWidget(Widget, can_focus=False):
55
60
  yield FileLog(id='test-box-output')
56
61
  yield FileLog(id='test-box-stderr')
57
62
  yield FileLog(id='test-box-log')
63
+ yield InteractionBox(id='test-box-interaction')
58
64
  yield RichLogBox(id='test-box-metadata')
59
65
 
60
66
  def on_mount(self):
@@ -62,7 +68,7 @@ class TestBoxWidget(Widget, can_focus=False):
62
68
  logs.output.border_title = 'Output'
63
69
  logs.stderr.border_title = 'Stderr'
64
70
  logs.log.border_title = 'Log'
65
-
71
+ logs.interaction.border_title = 'Interaction'
66
72
  metadata = self.query_one('#test-box-metadata', RichLogBox)
67
73
  metadata.display = False
68
74
  metadata.border_title = 'Metadata'
@@ -78,7 +84,7 @@ class TestBoxWidget(Widget, can_focus=False):
78
84
  logs.output.path = data.output_path
79
85
  logs.stderr.path = data.stderr_path
80
86
  logs.log.path = data.log_path
81
-
87
+ logs.interaction.path = data.interaction_path
82
88
  metadata = self.query_one('#test-box-metadata', RichLogBox)
83
89
  metadata.clear()
84
90
  if data.rich_content is not None:
@@ -98,6 +104,9 @@ class TestBoxWidget(Widget, can_focus=False):
98
104
  def show_log(self):
99
105
  self.query_one(ContentSwitcher).current = 'test-box-log'
100
106
 
107
+ def show_interaction(self):
108
+ self.query_one(ContentSwitcher).current = 'test-box-interaction'
109
+
101
110
  def toggle_metadata(self):
102
111
  metadata = self.query_one('#test-box-metadata', RichLogBox)
103
112
  metadata.display = not metadata.display
@@ -51,6 +51,10 @@ class TwoSidedTestBoxWidget(Widget, can_focus=False):
51
51
  self.query_one('#test-box-1', TestBoxWidget).show_log()
52
52
  self.query_one('#test-box-2', TestBoxWidget).show_log()
53
53
 
54
+ def show_interaction(self):
55
+ self.query_one('#test-box-1', TestBoxWidget).show_interaction()
56
+ self.query_one('#test-box-2', TestBoxWidget).show_interaction()
57
+
54
58
  def toggle_metadata(self):
55
59
  self.query_one('#test-box-1', TestBoxWidget).toggle_metadata()
56
60
  self.query_one('#test-box-2', TestBoxWidget).toggle_metadata()
@@ -1,10 +0,0 @@
1
- def get_formatted_memory(memory_in_bytes: int, mib_decimal_places: int = 0) -> str:
2
- if memory_in_bytes < 1024 * 1024:
3
- if memory_in_bytes < 1024:
4
- return f'{memory_in_bytes} B'
5
- return f'{memory_in_bytes / 1024:.0f} KiB'
6
- return f'{memory_in_bytes / (1024 * 1024):.{mib_decimal_places}f} MiB'
7
-
8
-
9
- def get_formatted_time(time_in_ms: int) -> str:
10
- return f'{time_in_ms} ms'
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