rbx.cp 0.5.25__tar.gz → 0.5.26__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 (168) hide show
  1. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/PKG-INFO +1 -1
  2. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/pyproject.toml +1 -1
  3. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/contest/main.py +9 -6
  4. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/main.py +15 -12
  5. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/presets/__init__.py +37 -10
  6. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/solutions.py +19 -3
  7. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/validators.py +15 -3
  8. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/console.py +12 -0
  9. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/LICENSE +0 -0
  10. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/README.md +0 -0
  11. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/__init__.py +0 -0
  12. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/annotations.py +0 -0
  13. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/autoenum.py +0 -0
  14. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/__init__.py +0 -0
  15. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/builder.py +0 -0
  16. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/cd.py +0 -0
  17. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/checkers.py +0 -0
  18. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/code.py +0 -0
  19. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/compile.py +0 -0
  20. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/conftest.py +0 -0
  21. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/contest/__init__.py +0 -0
  22. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/contest/build_contest_statements.py +0 -0
  23. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/contest/contest_package.py +0 -0
  24. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/contest/contest_utils.py +0 -0
  25. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/contest/schema.py +0 -0
  26. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/contest/statements.py +0 -0
  27. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/creation.py +0 -0
  28. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/deferred.py +0 -0
  29. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/download.py +0 -0
  30. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/environment.py +0 -0
  31. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/extensions.py +0 -0
  32. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/generators.py +0 -0
  33. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/generators_test.py +0 -0
  34. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/package.py +0 -0
  35. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/packaging/boca/extension.py +0 -0
  36. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/packaging/boca/packager.py +0 -0
  37. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/packaging/contest_main.py +0 -0
  38. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/packaging/main.py +0 -0
  39. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/packaging/packager.py +0 -0
  40. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/packaging/polygon/packager.py +0 -0
  41. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/packaging/polygon/test.py +0 -0
  42. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/packaging/polygon/xml_schema.py +0 -0
  43. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/presets/fetch.py +0 -0
  44. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/presets/lock_schema.py +0 -0
  45. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/presets/schema.py +0 -0
  46. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/sanitizers/warning_stack.py +0 -0
  47. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/schema.py +0 -0
  48. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/setter_config.py +0 -0
  49. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/solutions_test.py +0 -0
  50. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/statements/__init__.py +0 -0
  51. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/statements/build_statements.py +0 -0
  52. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/statements/builders.py +0 -0
  53. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/statements/joiners.py +0 -0
  54. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/statements/latex.py +0 -0
  55. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/statements/latex_jinja.py +0 -0
  56. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/statements/schema.py +0 -0
  57. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/stresses.py +0 -0
  58. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/stressing/__init__.py +0 -0
  59. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/stressing/finder_parser.py +0 -0
  60. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/stressing/generator_parser.py +0 -0
  61. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/testcases.py +0 -0
  62. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/ui/__init__.py +0 -0
  63. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/ui/captured_log.py +0 -0
  64. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/ui/css/app.tcss +0 -0
  65. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/ui/main.py +0 -0
  66. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/ui/run.py +0 -0
  67. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/box/validators_test.py +0 -0
  68. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/checker.py +0 -0
  69. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/clone.py +0 -0
  70. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/config.py +0 -0
  71. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/conftest.py +0 -0
  72. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/create.py +0 -0
  73. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/edit.py +0 -0
  74. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/__init__.py +0 -0
  75. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/caching.py +0 -0
  76. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/conftest.py +0 -0
  77. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/judge/__init__.py +0 -0
  78. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/judge/cacher.py +0 -0
  79. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/judge/digester.py +0 -0
  80. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/judge/sandbox.py +0 -0
  81. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/judge/sandboxes/__init__.py +0 -0
  82. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/judge/sandboxes/isolate.py +0 -0
  83. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/judge/sandboxes/stupid_sandbox.py +0 -0
  84. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/judge/sandboxes/timeit.py +0 -0
  85. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/judge/storage.py +0 -0
  86. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/judge/test.py +0 -0
  87. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/judge/testiso.py +0 -0
  88. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/steps.py +0 -0
  89. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/steps_with_caching.py +0 -0
  90. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading/steps_with_caching_run_test.py +0 -0
  91. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/grading_utils.py +0 -0
  92. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/hydration.py +0 -0
  93. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/main.py +0 -0
  94. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/metadata.py +0 -0
  95. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/providers/__init__.py +0 -0
  96. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/providers/codeforces.py +0 -0
  97. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/providers/provider.py +0 -0
  98. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/checkers/boilerplate.cpp +0 -0
  99. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/default_config.json +0 -0
  100. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/default_setter_config.mac.yml +0 -0
  101. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/default_setter_config.yml +0 -0
  102. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/envs/default.rbx.yml +0 -0
  103. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/envs/isolate.rbx.yml +0 -0
  104. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/checker.sh +0 -0
  105. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/compare +0 -0
  106. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/compile/c +0 -0
  107. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/compile/cc +0 -0
  108. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/compile/cpp +0 -0
  109. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/compile/java +0 -0
  110. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/compile/kt +0 -0
  111. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/compile/pas +0 -0
  112. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/compile/py2 +0 -0
  113. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/compile/py3 +0 -0
  114. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/run/c +0 -0
  115. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/run/cc +0 -0
  116. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/run/cpp +0 -0
  117. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/run/java +0 -0
  118. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/run/kt +0 -0
  119. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/run/py2 +0 -0
  120. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/packagers/boca/run/py3 +0 -0
  121. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/contest/contest.rbx.yml +0 -0
  122. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/contest/statement/contest.rbx.tex +0 -0
  123. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/contest/statement/olymp.sty +0 -0
  124. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/contest/statement/template.rbx.tex +0 -0
  125. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/preset.rbx.yml +0 -0
  126. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/.gitignore +0 -0
  127. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/gen.cpp +0 -0
  128. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/problem.rbx.yml +0 -0
  129. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/random.py +0 -0
  130. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/random.txt +0 -0
  131. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/sols/main.cpp +0 -0
  132. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/sols/slow.cpp +0 -0
  133. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/sols/wa.cpp +0 -0
  134. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/statement/olymp.sty +0 -0
  135. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/statement/projecao.png +0 -0
  136. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/statement/statement.rbx.tex +0 -0
  137. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/statement/template.rbx.tex +0 -0
  138. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/tests/samples/000.in +0 -0
  139. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/tests/samples/001.in +0 -0
  140. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/validator.cpp +0 -0
  141. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/presets/default/problem/wcmp.cpp +0 -0
  142. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/resources/templates/template.cpp +0 -0
  143. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/run.py +0 -0
  144. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/schema.py +0 -0
  145. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/submit.py +0 -0
  146. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/submitors/__init__.py +0 -0
  147. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/submitors/codeforces.py +0 -0
  148. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/submitors/submitor.py +0 -0
  149. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/test.py +0 -0
  150. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testcase.py +0 -0
  151. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testcase_rendering.py +0 -0
  152. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/box1/gen1.cpp +0 -0
  153. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/box1/gen2.cpp +0 -0
  154. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/box1/genScript.py +0 -0
  155. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/box1/hard-tle.sol.cpp +0 -0
  156. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/box1/ole.cpp +0 -0
  157. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/box1/problem.rbx.yml +0 -0
  158. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/box1/re.sol.cpp +0 -0
  159. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/box1/sol.cpp +0 -0
  160. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/box1/tests/1.in +0 -0
  161. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/box1/tle-and-incorrect.sol.cpp +0 -0
  162. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/box1/tle.sol.cpp +0 -0
  163. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/box1/validator.cpp +0 -0
  164. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/box1/wa.sol.cpp +0 -0
  165. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/caching/executable.py +0 -0
  166. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testdata/compatible +0 -0
  167. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/testing_utils.py +0 -0
  168. {rbx_cp-0.5.25 → rbx_cp-0.5.26}/rbx/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: rbx.cp
3
- Version: 0.5.25
3
+ Version: 0.5.26
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.25"
3
+ version = "0.5.26"
4
4
  description = ""
5
5
  packages = [
6
6
  {include = "rbx"}
@@ -147,12 +147,15 @@ def add(path: str, short_name: str, preset: Optional[str] = None):
147
147
 
148
148
  ru, contest = contest_package.get_ruyaml()
149
149
 
150
- contest['problems'].append(
151
- {
152
- 'short_name': short_name,
153
- 'path': path,
154
- }
155
- )
150
+ item = {
151
+ 'short_name': short_name,
152
+ 'path': path,
153
+ }
154
+ if 'problems' not in contest:
155
+ contest['problems'] = [item]
156
+ else:
157
+ contest['problems'].append(item)
158
+
156
159
  dest = find_contest_yaml()
157
160
  assert dest is not None
158
161
  utils.save_ruyaml(dest, ru, contest)
@@ -197,6 +197,12 @@ def run(
197
197
  if solution:
198
198
  tracked_solutions = {solution}
199
199
 
200
+ if choice:
201
+ tracked_solutions = set(pick_solutions(tracked_solutions))
202
+ if not tracked_solutions:
203
+ console.console.print('[error]No solutions selected. Exiting.[/error]')
204
+ raise typer.Exit(1)
205
+
200
206
  if sanitized and tracked_solutions is None:
201
207
  console.console.print(
202
208
  '[warning]Sanitizers are running, and no solutions were specified to run. Will only run [item]ACCEPTED[/item] solutions.'
@@ -206,12 +212,6 @@ def run(
206
212
  for solution in get_exact_matching_solutions(ExpectedOutcome.ACCEPTED)
207
213
  }
208
214
 
209
- if choice:
210
- tracked_solutions = set(pick_solutions(tracked_solutions))
211
- if not tracked_solutions:
212
- console.console.print('[error]No solutions selected. Exiting.[/error]')
213
- raise typer.Exit(1)
214
-
215
215
  with utils.StatusProgress('Running solutions...') as s:
216
216
  solution_result = run_solutions(
217
217
  progress=s,
@@ -385,6 +385,13 @@ def irun(
385
385
  }
386
386
  if solution:
387
387
  tracked_solutions = {solution}
388
+
389
+ if choice:
390
+ tracked_solutions = set(pick_solutions(tracked_solutions))
391
+ if not tracked_solutions:
392
+ console.console.print('[error]No solutions selected. Exiting.[/error]')
393
+ raise typer.Exit(1)
394
+
388
395
  if sanitized and tracked_solutions is None:
389
396
  console.console.print(
390
397
  '[warning]Sanitizers are running, and no solutions were specified to run. Will only run [item]ACCEPTED[/item] solutions.'
@@ -394,12 +401,6 @@ def irun(
394
401
  for solution in get_exact_matching_solutions(ExpectedOutcome.ACCEPTED)
395
402
  }
396
403
 
397
- if choice:
398
- tracked_solutions = set(pick_solutions(tracked_solutions))
399
- if not tracked_solutions:
400
- console.console.print('[error]No solutions selected. Exiting.[/error]')
401
- raise typer.Exit(1)
402
-
403
404
  with utils.StatusProgress('Running solutions...') as s:
404
405
  asyncio.run(
405
406
  run_and_print_interactive_solutions(
@@ -539,6 +540,8 @@ def stress(
539
540
  name=testgroup, generatorScript=CodeItem(path=new_script_path)
540
541
  )
541
542
  ru, problem_yml = package.get_ruyaml()
543
+ if 'testcases' not in problem_yml:
544
+ problem_yml['testcases'] = []
542
545
  problem_yml['testcases'].append(
543
546
  {
544
547
  'name': testgroup,
@@ -68,13 +68,14 @@ def _find_nested_preset(root: pathlib.Path) -> Optional[pathlib.Path]:
68
68
 
69
69
 
70
70
  def _find_local_preset(root: pathlib.Path) -> Optional[pathlib.Path]:
71
+ original_root = root
71
72
  root = root.resolve()
72
73
  problem_yaml_path = root / '.local.rbx' / 'preset.rbx.yml'
73
74
  while root != pathlib.PosixPath('/') and not problem_yaml_path.is_file():
74
75
  root = root.parent
75
76
  problem_yaml_path = root / '.local.rbx' / 'preset.rbx.yml'
76
77
  if not problem_yaml_path.is_file():
77
- return _find_nested_preset(root)
78
+ return _find_nested_preset(original_root)
78
79
  return problem_yaml_path.parent
79
80
 
80
81
 
@@ -326,6 +327,13 @@ def _install(root: pathlib.Path = pathlib.Path(), force: bool = False):
326
327
  console.console.print('[error]Naming a preset "local" is prohibited.[/error]')
327
328
 
328
329
  console.console.print(f'Installing preset [item]{preset.name}[/item]...')
330
+ installation_path = get_preset_installation_path(preset.name)
331
+
332
+ if root.resolve().is_relative_to(installation_path.resolve()):
333
+ console.console.print(
334
+ '[error]Current folder is nested into the preset installation path, cannot install it.[/error]'
335
+ )
336
+ raise typer.Exit(1)
329
337
 
330
338
  if preset.env is not None:
331
339
  console.console.print(
@@ -346,7 +354,6 @@ def _install(root: pathlib.Path = pathlib.Path(), force: bool = False):
346
354
  shutil.copyfile(str(root / preset.env), get_environment_path(preset.name))
347
355
 
348
356
  console.console.print(f'[item]{preset.name}[/item]: Copying preset folder...')
349
- installation_path = get_preset_installation_path(preset.name)
350
357
  installation_path.parent.mkdir(parents=True, exist_ok=True)
351
358
  if installation_path.exists():
352
359
  res = force or rich.prompt.Confirm.ask(
@@ -412,7 +419,7 @@ def generate_lock(
412
419
  )
413
420
 
414
421
 
415
- def _sync(update: bool = False):
422
+ def _sync(try_update: bool = False):
416
423
  preset_lock = get_preset_lock()
417
424
  if preset_lock is None:
418
425
  console.console.print(
@@ -423,18 +430,17 @@ def _sync(update: bool = False):
423
430
  )
424
431
  raise typer.Exit(1)
425
432
 
426
- should_update = update and preset_lock.uri is not None
433
+ should_update = try_update and preset_lock.uri is not None
427
434
  installed_preset = get_installed_preset_or_null(preset_lock.preset_name)
428
435
  if installed_preset is None:
429
- if not update or preset_lock.uri is None:
436
+ if not try_update or preset_lock.uri is None:
430
437
  console.console.print(
431
438
  f'[error]Preset [item]{preset_lock.preset_name}[/item] is not installed. Install it before trying to update.'
432
439
  )
433
440
  raise typer.Exit(1)
434
- should_update = True
435
-
436
- if should_update:
437
- install(uri=preset_lock.uri)
441
+ install(preset_lock.uri)
442
+ elif should_update:
443
+ update(preset_lock.name)
438
444
 
439
445
  _copy_updated_assets(
440
446
  preset_lock.preset_name,
@@ -477,6 +483,13 @@ def update(
477
483
  presets = [name]
478
484
 
479
485
  for preset_name in presets:
486
+ if preset_name == LOCAL:
487
+ if not questionary.confirm(
488
+ 'Updating local preset will remove all custom changes you made to the preset.',
489
+ default=False,
490
+ ).ask():
491
+ continue
492
+
480
493
  preset = get_installed_preset_or_null(preset_name)
481
494
  if preset is None:
482
495
  console.console.print(
@@ -490,6 +503,20 @@ def update(
490
503
  continue
491
504
  install_from_remote(preset.fetch_info, force=True)
492
505
 
506
+ if preset_name == LOCAL:
507
+ # Get global path to the preset.
508
+ preset_path = get_preset_installation_path(preset.name)
509
+ dest_path = '.local.rbx'
510
+ shutil.rmtree(dest_path, ignore_errors=True)
511
+ shutil.copytree(preset_path, dest_path)
512
+ console.console.print(
513
+ '[success]Local preset updated successfully.[/success]'
514
+ )
515
+ else:
516
+ console.console.print(
517
+ f'[success]Preset [item]{preset_name}[/item] updated successfully.[/success]'
518
+ )
519
+
493
520
 
494
521
  @app.command(
495
522
  'sync',
@@ -507,7 +534,7 @@ def sync(
507
534
  ] = False,
508
535
  ):
509
536
  _check_is_valid_package()
510
- _sync(update=update)
537
+ _sync(try_update=update)
511
538
 
512
539
 
513
540
  @app.command(
@@ -13,6 +13,7 @@ import rich.live
13
13
  import rich.markup
14
14
  import rich.table
15
15
  import rich.text
16
+ import typer
16
17
  from pydantic import BaseModel
17
18
 
18
19
  from rbx import console
@@ -547,14 +548,29 @@ async def run_and_print_interactive_solutions(
547
548
  console.console.print()
548
549
 
549
550
 
551
+ def _get_solution_repr(sol: Solution) -> List[Tuple[str, str]]:
552
+ return [
553
+ ('', f'{str(sol.path)} '),
554
+ (f'fg:{sol.outcome.style().replace('lnumber', 'cyan')}', sol.outcome.name),
555
+ ]
556
+
557
+
550
558
  def pick_solutions(tracked_solutions: Optional[Set[str]]) -> List[str]:
551
559
  pkg = package.find_problem_package_or_die()
552
560
  if tracked_solutions is None:
553
561
  tracked_solutions = set(str(sol.path) for sol in pkg.solutions)
554
562
 
555
- return questionary.checkbox(
556
- 'Select solutions', choices=list(tracked_solutions)
557
- ).ask()
563
+ # Store in a separate list to maintain order with the package declaration.
564
+ choices = [
565
+ questionary.Choice(title=_get_solution_repr(sol), value=str(sol.path))
566
+ for sol in pkg.solutions
567
+ if str(sol.path) in tracked_solutions
568
+ ]
569
+
570
+ picked = questionary.checkbox('Select solutions', choices=choices).ask()
571
+ if picked is None:
572
+ raise typer.Abort()
573
+ return picked
558
574
 
559
575
 
560
576
  def get_outcome_style_verdict(outcome: Outcome) -> str:
@@ -262,10 +262,22 @@ def print_validation_report(infos: List[TestcaseValidationInfo]):
262
262
  if not _has_group_specific_validator():
263
263
  hit_bounds_per_group = {None: _merge_hit_bounds(hit_bounds_per_group.values())}
264
264
 
265
+ def _is_hit_bound_good(hit_bounds: HitBounds) -> bool:
266
+ return any(not v[0] or not v[1] for v in hit_bounds.values())
267
+
268
+ # Cleanup entries in hit bounds per group that are totally empty.
269
+ # Also skip samples.
270
+ hit_bounds_per_group = {
271
+ k: v
272
+ for k, v in hit_bounds_per_group.items()
273
+ if _is_hit_bound_good(v) and k != 'samples'
274
+ }
275
+
276
+ if not hit_bounds_per_group:
277
+ console.console.print('[info]No validation issues found.[/info]')
278
+ return
279
+
265
280
  for group, hit_bounds in hit_bounds_per_group.items():
266
- if group == 'samples':
267
- # Skip samples.
268
- continue
269
281
  if group is None:
270
282
  console.console.print('Hit bounds:')
271
283
  else:
@@ -1,5 +1,7 @@
1
1
  import sys
2
2
 
3
+ import rich
4
+ import rich.markup
3
5
  from rich.console import Console
4
6
  from rich.theme import Theme
5
7
 
@@ -25,3 +27,13 @@ def multiline_prompt(text: str) -> str:
25
27
  lines = sys.stdin.readlines()
26
28
  console.print()
27
29
  return ''.join(lines)
30
+
31
+
32
+ def render_from(r: rich.console.RenderableType) -> str:
33
+ with console.capture() as capture:
34
+ console.print(r)
35
+ return capture.get()
36
+
37
+
38
+ def render_from_markup(markup: str) -> str:
39
+ return render_from(rich.markup.render(markup))
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