rbx.cp 0.5.54__py3-none-any.whl → 0.5.55__py3-none-any.whl

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 (34) hide show
  1. rbx/box/checkers.py +11 -1
  2. rbx/box/cli.py +8 -0
  3. rbx/box/contest/schema.py +53 -4
  4. rbx/box/naming.py +20 -5
  5. rbx/box/packaging/boca/upload.py +247 -0
  6. rbx/box/packaging/main.py +13 -1
  7. rbx/box/solutions.py +12 -1
  8. rbx/box/tasks.py +4 -2
  9. rbx/box/testcase_extractors.py +3 -0
  10. rbx/box/ui/captured_log.py +13 -8
  11. rbx/box/ui/css/app.tcss +47 -8
  12. rbx/box/ui/main.py +5 -1
  13. rbx/box/ui/screens/__init__.py +0 -0
  14. rbx/box/ui/screens/build.py +6 -0
  15. rbx/box/ui/screens/command.py +35 -0
  16. rbx/box/ui/{run.py → screens/run.py} +10 -38
  17. rbx/box/ui/screens/run_explorer.py +5 -0
  18. rbx/box/ui/screens/test_explorer.py +100 -0
  19. rbx/box/ui/widgets/file_log.py +63 -0
  20. rbx/box/ui/widgets/rich_log_box.py +5 -0
  21. rbx/grading/judge/sandboxes/stupid_sandbox.py +5 -1
  22. rbx/grading/judge/sandboxes/timeit.py +2 -1
  23. rbx/resources/packagers/boca/interactive/c +8 -1
  24. rbx/resources/packagers/boca/interactive/cc +8 -1
  25. rbx/resources/packagers/boca/interactive/cpp +8 -1
  26. rbx/resources/packagers/boca/interactive/java +8 -1
  27. rbx/resources/packagers/boca/interactive/kt +8 -1
  28. rbx/resources/packagers/boca/interactive/py2 +8 -1
  29. rbx/resources/packagers/boca/interactive/py3 +8 -1
  30. {rbx_cp-0.5.54.dist-info → rbx_cp-0.5.55.dist-info}/METADATA +7 -2
  31. {rbx_cp-0.5.54.dist-info → rbx_cp-0.5.55.dist-info}/RECORD +34 -26
  32. {rbx_cp-0.5.54.dist-info → rbx_cp-0.5.55.dist-info}/LICENSE +0 -0
  33. {rbx_cp-0.5.54.dist-info → rbx_cp-0.5.55.dist-info}/WHEEL +0 -0
  34. {rbx_cp-0.5.54.dist-info → rbx_cp-0.5.55.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,35 @@
1
+ import asyncio
2
+ from typing import List
3
+
4
+ from textual.app import ComposeResult
5
+ from textual.screen import Screen
6
+ from textual.widgets import Footer, Header
7
+
8
+ from rbx.box.ui.captured_log import LogDisplay
9
+
10
+
11
+ class CommandScreen(Screen):
12
+ BINDINGS = [('q', 'app.pop_screen', 'Back')]
13
+
14
+ def __init__(self, command: List[str]):
15
+ super().__init__()
16
+ self.command = command
17
+
18
+ def compose(self) -> ComposeResult:
19
+ yield Header()
20
+ yield Footer()
21
+ yield LogDisplay()
22
+
23
+ async def _run_command(self):
24
+ exitcode = await self.query_one(LogDisplay).capture(self.command)
25
+ if exitcode != 0:
26
+ self.query_one(LogDisplay).border_subtitle = f'Exit code: {exitcode}'
27
+ return
28
+
29
+ self.query_one(LogDisplay).border_subtitle = 'Finished'
30
+
31
+ async def on_mount(self):
32
+ self.query_one(LogDisplay).border_title = 'Command output'
33
+
34
+ # Fire and forget.
35
+ asyncio.create_task(self._run_command())
@@ -18,9 +18,10 @@ from rbx.box.solutions import (
18
18
  SolutionReportSkeleton,
19
19
  get_evals_formatted_time,
20
20
  get_testcase_markup_verdict,
21
- run_solutions,
22
21
  )
23
22
  from rbx.box.ui.captured_log import LogDisplay, LogDisplayState
23
+ from rbx.box.ui.screens.command import CommandScreen
24
+ from rbx.grading.steps import Evaluation
24
25
 
25
26
 
26
27
  def _build_solution_selection_label(sol: Solution) -> Text:
@@ -36,7 +37,7 @@ def _build_solution_selection_label(sol: Solution) -> Text:
36
37
  class SolutionReportScreen(Screen):
37
38
  skeleton: SolutionReportSkeleton
38
39
 
39
- BINDINGS = [('q', 'app.pop_screen', 'Quit')]
40
+ BINDINGS = [('q', 'app.pop_screen', 'Back')]
40
41
 
41
42
  def __init__(
42
43
  self,
@@ -86,7 +87,7 @@ class SolutionReportScreen(Screen):
86
87
  return i
87
88
  raise
88
89
 
89
- async def process(self, item: EvaluationItem):
90
+ async def process(self, item: EvaluationItem, eval: Evaluation):
90
91
  pkg = package.find_problem_package_or_die()
91
92
  sol_idx_in_skeleton = self._find_solution_index_in_skeleton(
92
93
  pkg.solutions[item.solution_index]
@@ -101,17 +102,19 @@ class SolutionReportScreen(Screen):
101
102
 
102
103
  table.update_cell_at(
103
104
  Coordinate(row=row_idx, column=2),
104
- get_testcase_markup_verdict(await item.eval()),
105
+ get_testcase_markup_verdict(eval),
105
106
  update_width=True,
106
107
  )
107
108
  table.update_cell_at(
108
109
  Coordinate(row=row_idx, column=3),
109
- get_evals_formatted_time([await item.eval()]),
110
+ get_evals_formatted_time([eval]),
110
111
  update_width=True,
111
112
  )
112
113
 
113
114
 
114
115
  class RunScreen(Screen):
116
+ BINDINGS = [('q', 'app.pop_screen', 'Back')]
117
+
115
118
  def compose(self) -> ComposeResult:
116
119
  yield Header()
117
120
  yield Footer()
@@ -141,7 +144,6 @@ class RunScreen(Screen):
141
144
  id='run-config',
142
145
  )
143
146
  yield Button('Run')
144
- yield LogDisplay()
145
147
 
146
148
  def on_mount(self):
147
149
  sols = self.query_one('#run-sols', SelectionList)
@@ -160,7 +162,6 @@ class RunScreen(Screen):
160
162
  async def on_button_pressed(self, _: Button.Pressed):
161
163
  await self.action_run()
162
164
 
163
- @textual.work(thread=True)
164
165
  async def _run_solutions(self, tracked_solutions: Set[str], check: bool):
165
166
  main_solution = package.get_main_solution()
166
167
  if check and main_solution is None:
@@ -169,36 +170,7 @@ class RunScreen(Screen):
169
170
  )
170
171
  check = False
171
172
 
172
- async def build():
173
- return await self.query_one(LogDisplay).capture(['rbx', 'build'])
174
-
175
- exitcode = self.app.call_from_thread(build)
176
-
177
- if exitcode != 0:
178
- textual.log(f'early quit: {exitcode}')
179
- return
180
-
181
- textual.log('build finished ok, running solutions')
182
-
183
- res = run_solutions(tracked_solutions=tracked_solutions, check=check)
184
-
185
- async def mount_report_widget() -> SolutionReportScreen:
186
- # log_display_state = self.query_one(LogDisplay).export()
187
- log_display_state = None
188
- await self.app.push_screen(
189
- screen := SolutionReportScreen(
190
- res.skeleton, log_display_state=log_display_state
191
- )
192
- )
193
- return screen
194
-
195
- new_screen = await mount_report_widget()
196
-
197
- async def process_item(item: EvaluationItem):
198
- await new_screen.process(item)
199
-
200
- for item in res.items:
201
- self.app.call_from_thread(process_item, item)
173
+ self.app.switch_screen(CommandScreen(['rbx', 'run']))
202
174
 
203
175
  async def action_run(self):
204
176
  sols = self.query_one('#run-sols', SelectionList)
@@ -207,4 +179,4 @@ class RunScreen(Screen):
207
179
  tracked_solutions = set(str(sol) for sol in sols.selected)
208
180
  check = 'check' in config.selected
209
181
 
210
- self._run_solutions(tracked_solutions, check)
182
+ await self._run_solutions(tracked_solutions, check)
@@ -0,0 +1,5 @@
1
+ from textual.screen import Screen
2
+
3
+
4
+ class RunExplorerScreen(Screen):
5
+ pass
@@ -0,0 +1,100 @@
1
+ from typing import List, Optional
2
+
3
+ from textual.app import ComposeResult
4
+ from textual.containers import Horizontal, Vertical
5
+ from textual.screen import Screen
6
+ from textual.widgets import Footer, Header, Label, ListItem, ListView, RichLog
7
+
8
+ from rbx.box.testcase_extractors import (
9
+ GenerationTestcaseEntry,
10
+ extract_generation_testcases_from_groups,
11
+ )
12
+ from rbx.box.ui.widgets.file_log import FileLog
13
+ from rbx.box.ui.widgets.rich_log_box import RichLogBox
14
+
15
+
16
+ class TestExplorerScreen(Screen):
17
+ BINDINGS = [
18
+ ('q', 'app.pop_screen', 'Quit'),
19
+ ('m', 'toggle_metadata', 'Toggle metadata'),
20
+ ]
21
+
22
+ def __init__(self):
23
+ super().__init__()
24
+ self._entries: List[GenerationTestcaseEntry] = []
25
+
26
+ def compose(self) -> ComposeResult:
27
+ yield Header()
28
+ yield Footer()
29
+ with Horizontal(id='test-explorer'):
30
+ with Vertical(id='test-list-container'):
31
+ yield ListView(id='test-list')
32
+ with Vertical(id='test-details'):
33
+ yield FileLog(id='test-input')
34
+ yield FileLog(id='test-output')
35
+ yield RichLogBox(id='test-metadata')
36
+
37
+ async def on_mount(self):
38
+ self.query_one('#test-list').border_title = 'Tests'
39
+ self.query_one('#test-input').border_title = 'Input'
40
+ self.query_one('#test-output').border_title = 'Output'
41
+
42
+ metadata = self.query_one('#test-metadata', RichLogBox)
43
+ metadata.display = False
44
+ metadata.border_title = 'Metadata'
45
+ metadata.wrap = True
46
+ metadata.markup = True
47
+ metadata.clear().write('No test selected')
48
+ await self._update_tests()
49
+
50
+ def action_toggle_metadata(self):
51
+ metadata = self.query_one('#test-metadata', RichLogBox)
52
+ metadata.display = not metadata.display
53
+
54
+ def _update_selected_test(self, index: Optional[int]):
55
+ input = self.query_one('#test-input', FileLog)
56
+ output = self.query_one('#test-output', FileLog)
57
+ metadata = self.query_one('#test-metadata', RichLog)
58
+
59
+ if index is None:
60
+ input.path = None
61
+ output.path = None
62
+ metadata.clear().write('No test selected')
63
+ return
64
+ entry = self._entries[index]
65
+ input.path = entry.metadata.copied_to.inputPath
66
+ output.path = entry.metadata.copied_to.outputPath
67
+
68
+ metadata.clear()
69
+ metadata.write(
70
+ f'[bold]{entry.group_entry.group}[/bold] / [bold]{entry.group_entry.index}[/bold]'
71
+ )
72
+ if entry.metadata.copied_from is not None:
73
+ metadata.write(
74
+ f'[bold]Copied from:[/bold] {entry.metadata.copied_from.inputPath}'
75
+ )
76
+ if entry.metadata.generator_call is not None:
77
+ metadata.write(f'[bold]Gen. call:[/bold] {entry.metadata.generator_call}')
78
+ if entry.metadata.generator_script is not None:
79
+ metadata.write(
80
+ f'[bold]Gen. script:[/bold] {entry.metadata.generator_script}'
81
+ )
82
+
83
+ async def _update_tests(self):
84
+ self.watch(
85
+ self.query_one('#test-list', ListView),
86
+ 'index',
87
+ self._update_selected_test,
88
+ )
89
+
90
+ self._entries = await extract_generation_testcases_from_groups()
91
+
92
+ test_names = [
93
+ f'{entry.group_entry.group}/{entry.group_entry.index}'
94
+ for entry in self._entries
95
+ ]
96
+
97
+ await self.query_one('#test-list', ListView).clear()
98
+ await self.query_one('#test-list', ListView).extend(
99
+ [ListItem(Label(name)) for name in test_names]
100
+ )
@@ -0,0 +1,63 @@
1
+ import pathlib
2
+ from typing import Optional
3
+
4
+ import aiofiles
5
+ from textual import work
6
+ from textual.app import ComposeResult
7
+ from textual.reactive import reactive
8
+ from textual.widget import Widget
9
+ from textual.widgets import Log
10
+
11
+ BATCH_SIZE = 1024
12
+
13
+
14
+ class FileLog(Widget, can_focus=False):
15
+ DEFAULT_CSS = """
16
+ FileLog {
17
+ border: solid $accent;
18
+ height: 1fr;
19
+ width: 1fr;
20
+ }
21
+ """
22
+
23
+ path: reactive[Optional[pathlib.Path]] = reactive(None)
24
+
25
+ def compose(self) -> ComposeResult:
26
+ yield Log()
27
+
28
+ def on_mount(self):
29
+ self.query_one(Log).auto_scroll = False
30
+ self.query_one(Log).can_focus = False
31
+
32
+ @work(exclusive=True)
33
+ async def _load_file(self, path: pathlib.Path):
34
+ log = self.query_one(Log)
35
+ log.clear()
36
+ path_str = str(path.relative_to(pathlib.Path.cwd()))
37
+ self.border_subtitle = f'{path_str} (loading...)'
38
+
39
+ async with aiofiles.open(path, 'r') as f:
40
+ batch = []
41
+ async for line in f:
42
+ batch.append(line)
43
+ if len(batch) >= BATCH_SIZE:
44
+ log.write(''.join(batch))
45
+ batch = []
46
+
47
+ if batch:
48
+ log.write(''.join(batch))
49
+
50
+ self.border_subtitle = path_str
51
+
52
+ async def watch_path(self, path: Optional[pathlib.Path]):
53
+ log = self.query_one(Log)
54
+ log.clear()
55
+
56
+ if path is None:
57
+ return
58
+
59
+ if not path.is_file():
60
+ self.query_one(Log).write(f'File {path} does not exist')
61
+ return
62
+
63
+ self._load_file(path)
@@ -0,0 +1,5 @@
1
+ from textual.widgets import RichLog
2
+
3
+
4
+ class RichLogBox(RichLog, can_focus=False):
5
+ pass
@@ -322,7 +322,11 @@ class StupidSandbox(SandboxBase):
322
322
  return self.translate_box_exitcode(self.returncode)
323
323
 
324
324
  def translate_box_exitcode(self, exitcode: int) -> bool:
325
- # SIGALRM can be safely ignored, just in case it leaks away.
325
+ # SIGALRM can be safely ignored, just in case it leaks away. SIGTERM also.
326
+ if self.log is None:
327
+ return False
328
+ if 'TE' in self.get_status_list():
329
+ return True
326
330
  return super().translate_box_exitcode(exitcode) or -exitcode == signal.SIGALRM
327
331
 
328
332
  def debug_message(self) -> Any:
@@ -109,7 +109,8 @@ def create_tee(files, mode, buffer_size=4096, prefix=''):
109
109
  else:
110
110
  # Parent -- Return a file object wrapper around the pipe to the
111
111
  # child.
112
- return os.fdopen(pipe_write, 'w', closefd=False)
112
+ # Preserve line buffering (buffering=1).
113
+ return os.fdopen(pipe_write, 'w', buffering=1, closefd=False)
113
114
 
114
115
 
115
116
  def parse_opts() -> Options:
@@ -146,8 +146,15 @@ echo "solution \$SFPID -> \$ECSF" >&2
146
146
  echo "interactor exitcode \$ECINT" >&2
147
147
  echo "solution exitcode \$ECSF" >&2
148
148
 
149
+ RTE=0
150
+ if [[ \$ECSF -eq -13 ]]; then
151
+ RTE=0
152
+ elif [[ \$ECSF -ne 0 ]] && cat stderr0 | grep -q "wrong output format Unexpected end of file"; then
153
+ RTE=1
154
+ fi
155
+
149
156
  ret=0
150
- if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]]; then
157
+ if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]] && [[ \$RTE -eq 0 ]]; then
151
158
  echo "testlib exitcode \$ECINT" >stdout0
152
159
  ret=0
153
160
  elif [[ \$ECSF -ne 0 ]]; then
@@ -146,8 +146,15 @@ echo "solution \$SFPID -> \$ECSF" >&2
146
146
  echo "interactor exitcode \$ECINT" >&2
147
147
  echo "solution exitcode \$ECSF" >&2
148
148
 
149
+ RTE=0
150
+ if [[ \$ECSF -eq -13 ]]; then
151
+ RTE=0
152
+ elif [[ \$ECSF -ne 0 ]] && cat stderr0 | grep -q "wrong output format Unexpected end of file"; then
153
+ RTE=1
154
+ fi
155
+
149
156
  ret=0
150
- if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]]; then
157
+ if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]] && [[ \$RTE -eq 0 ]]; then
151
158
  echo "testlib exitcode \$ECINT" >stdout0
152
159
  ret=0
153
160
  elif [[ \$ECSF -ne 0 ]]; then
@@ -146,8 +146,15 @@ echo "solution \$SFPID -> \$ECSF" >&2
146
146
  echo "interactor exitcode \$ECINT" >&2
147
147
  echo "solution exitcode \$ECSF" >&2
148
148
 
149
+ RTE=0
150
+ if [[ \$ECSF -eq -13 ]]; then
151
+ RTE=0
152
+ elif [[ \$ECSF -ne 0 ]] && cat stderr0 | grep -q "wrong output format Unexpected end of file"; then
153
+ RTE=1
154
+ fi
155
+
149
156
  ret=0
150
- if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]]; then
157
+ if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]] && [[ \$RTE -eq 0 ]]; then
151
158
  echo "testlib exitcode \$ECINT" >stdout0
152
159
  ret=0
153
160
  elif [[ \$ECSF -ne 0 ]]; then
@@ -159,8 +159,15 @@ echo "solution \$SFPID -> \$ECSF" >&2
159
159
  echo "interactor exitcode \$ECINT" >&2
160
160
  echo "solution exitcode \$ECSF" >&2
161
161
 
162
+ RTE=0
163
+ if [[ \$ECSF -eq -13 ]]; then
164
+ RTE=0
165
+ elif [[ \$ECSF -ne 0 ]] && cat stderr0 | grep -q "wrong output format Unexpected end of file"; then
166
+ RTE=1
167
+ fi
168
+
162
169
  ret=0
163
- if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]]; then
170
+ if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]] && [[ \$RTE -eq 0 ]]; then
164
171
  echo "testlib exitcode \$ECINT" >stdout0
165
172
  ret=0
166
173
  elif [[ \$ECSF -ne 0 ]]; then
@@ -150,8 +150,15 @@ echo "solution \$SFPID -> \$ECSF" >&2
150
150
  echo "interactor exitcode \$ECINT" >&2
151
151
  echo "solution exitcode \$ECSF" >&2
152
152
 
153
+ RTE=0
154
+ if [[ \$ECSF -eq -13 ]]; then
155
+ RTE=0
156
+ elif [[ \$ECSF -ne 0 ]] && cat stderr0 | grep -q "wrong output format Unexpected end of file"; then
157
+ RTE=1
158
+ fi
159
+
153
160
  ret=0
154
- if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]]; then
161
+ if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]] && [[ \$RTE -eq 0 ]]; then
155
162
  echo "testlib exitcode \$ECINT" >stdout0
156
163
  ret=0
157
164
  elif [[ \$ECSF -ne 0 ]]; then
@@ -137,8 +137,15 @@ echo "solution \$SFPID -> \$ECSF" >&2
137
137
  echo "interactor exitcode \$ECINT" >&2
138
138
  echo "solution exitcode \$ECSF" >&2
139
139
 
140
+ RTE=0
141
+ if [[ \$ECSF -eq -13 ]]; then
142
+ RTE=0
143
+ elif [[ \$ECSF -ne 0 ]] && cat stderr0 | grep -q "wrong output format Unexpected end of file"; then
144
+ RTE=1
145
+ fi
146
+
140
147
  ret=0
141
- if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]]; then
148
+ if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]] && [[ \$RTE -eq 0 ]]; then
142
149
  echo "testlib exitcode \$ECINT" >stdout0
143
150
  ret=0
144
151
  elif [[ \$ECSF -ne 0 ]]; then
@@ -137,8 +137,15 @@ echo "solution \$SFPID -> \$ECSF" >&2
137
137
  echo "interactor exitcode \$ECINT" >&2
138
138
  echo "solution exitcode \$ECSF" >&2
139
139
 
140
+ RTE=0
141
+ if [[ \$ECSF -eq -13 ]]; then
142
+ RTE=0
143
+ elif [[ \$ECSF -ne 0 ]] && cat stderr0 | grep -q "wrong output format Unexpected end of file"; then
144
+ RTE=1
145
+ fi
146
+
140
147
  ret=0
141
- if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]]; then
148
+ if [[ \$ECINT -ge 1 ]] && [[ \$ECINT -le 4 ]] && [[ \$RTE -eq 0 ]]; then
142
149
  echo "testlib exitcode \$ECINT" >stdout0
143
150
  ret=0
144
151
  elif [[ \$ECSF -ne 0 ]]; then
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rbx.cp
3
- Version: 0.5.54
3
+ Version: 0.5.55
4
4
  Summary:
5
5
  Author: Roberto Sales
6
6
  Requires-Python: >=3.9,<4.0
@@ -10,8 +10,12 @@ Classifier: Programming Language :: Python :: 3.10
10
10
  Classifier: Programming Language :: Python :: 3.11
11
11
  Classifier: Programming Language :: Python :: 3.12
12
12
  Classifier: Programming Language :: Python :: 3.13
13
+ Requires-Dist: aiofiles (>=24.1.0,<25.0.0)
13
14
  Requires-Dist: async-lru (>=2.0.5,<3.0.0)
15
+ Requires-Dist: beautifulsoup4 (>=4.13.4,<5.0.0)
14
16
  Requires-Dist: chardet (>=5.2.0,<6.0.0)
17
+ Requires-Dist: colour (>=0.1.5,<0.2.0)
18
+ Requires-Dist: dateparser (>=1.2.1,<2.0.0)
15
19
  Requires-Dist: fastapi (>=0.115.8,<0.116.0)
16
20
  Requires-Dist: filelock (>=3.14.0,<4.0.0)
17
21
  Requires-Dist: gitpython (>=3.1.43,<4.0.0)
@@ -32,7 +36,8 @@ Requires-Dist: requests (>=2.32.3,<3.0.0)
32
36
  Requires-Dist: rich (>=13.9.4,<14.0.0)
33
37
  Requires-Dist: ruyaml (>=0.91.0,<0.92.0)
34
38
  Requires-Dist: syncer (>=2.0.3,<3.0.0)
35
- Requires-Dist: textual (>=0.79.1,<0.80.0)
39
+ Requires-Dist: textual (>=3.1.1,<4.0.0)
40
+ Requires-Dist: textual-serve (>=1.1.2,<2.0.0)
36
41
  Requires-Dist: typer (>=0.15.1,<0.16.0)
37
42
  Description-Content-Type: text/markdown
38
43
 
@@ -4,8 +4,8 @@ rbx/autoenum.py,sha256=cusv8ClXRlDVvhZ8eDrtYcL_2peXlHugAey_ht8roXk,12025
4
4
  rbx/box/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  rbx/box/builder.py,sha256=MDm2qqmhedAbhn3rWP6cDwbBsGhV6sz_2sg1zLkPDw0,3613
6
6
  rbx/box/cd.py,sha256=9a_SOnzoJBXxxffp4Wbf3UKXIwKuN3Hvj7K6SocALwE,1194
7
- rbx/box/checkers.py,sha256=5Pj6a8y5YCVY3KvV7B_WLo30uDmIhnEgxE6_KKZqzvY,11923
8
- rbx/box/cli.py,sha256=GPoGDgmaV1lXL9puXhUbZUIEU0lOMvdH1kD4TGCXkCo,26738
7
+ rbx/box/checkers.py,sha256=EQq-NCz4JO3NowKKIs0iNdZgNBx71gG5PSxjw6fsQVg,12277
8
+ rbx/box/cli.py,sha256=QkK_SVdtSk6qI5Q_HD29Eojurnynp-Q8m0aE6z5jQoY,26893
9
9
  rbx/box/code.py,sha256=hmA2EoGOr13AYzicHNsnU2SkFW-44l7kOdu8QRwTJlI,18848
10
10
  rbx/box/compile.py,sha256=OJLthDQ921w9vyoE6Gk1Df54i5RwtRJ2YG-8XEfefcs,2489
11
11
  rbx/box/conftest.py,sha256=sEmciXSeDC-wmrZ1JSxbsUenKNP_VWW32mrCun2pY3I,1070
@@ -14,7 +14,7 @@ rbx/box/contest/build_contest_statements.py,sha256=H2MwmkiPO_cHUEenzfPxHuJ3XcwjH
14
14
  rbx/box/contest/contest_package.py,sha256=OaUbpBtkhkgOPzJ1ccI_Vq4FMSaJvZm3gMOKfVY8oy4,3032
15
15
  rbx/box/contest/contest_utils.py,sha256=TDE7I6YQJlu4dQd68wzOp019bNgqiT0RlM-LMQMjL9w,301
16
16
  rbx/box/contest/main.py,sha256=oL-GbyLKdpMjIWiSuWTQgRhQ9hcb7DuNn0axkunx0io,7436
17
- rbx/box/contest/schema.py,sha256=JMAig5WpaOahNgAHxA9vX4zYeVYDxpjKP_PFGvmmkE0,4954
17
+ rbx/box/contest/schema.py,sha256=OOoQUPYAHzu78aQfRbrqGepiUdGxSVRR1VQKFbKHjkE,6111
18
18
  rbx/box/contest/statements.py,sha256=Or8gFb6P_oViGdeiVgepXsvd_W84mA7LRaVmiAXWWSg,2977
19
19
  rbx/box/creation.py,sha256=Evz7K6JoarD-4JJQsZsgoxU9FgCF9Z7-LfuroG4Cqls,2444
20
20
  rbx/box/deferred.py,sha256=II3X9e87JCOZtmspnHh-n4PFqh-FsH_oc0XJHZ9ZYVQ,691
@@ -29,12 +29,13 @@ rbx/box/header.py,sha256=ifErXcIxG5lM5AyRiHDr7JE401vR4ORNXCNpHXxN_ls,2001
29
29
  rbx/box/lazy_importing_main.py,sha256=6Z8As7qVFFT619xHH9Xt8VCH57NjC4aDxfAgkWiUwT8,116
30
30
  rbx/box/lazy_importing_test.py,sha256=B0-b3y_DkxEmtVfu4NfmVsgVdFl6kRCsEL6GLMHJISo,628
31
31
  rbx/box/main.py,sha256=a8CYi77kOywPFly4-ucEIJLXQW-1NFp91kK2fA42YTE,86
32
- rbx/box/naming.py,sha256=OiaiLe0k1sBx4vIXemUqnzfdNte79rrCgOvBze9XaTw,940
32
+ rbx/box/naming.py,sha256=pOG37X_wQM9CCSYwJIUf-b-ZHEs_nchO7wQEdP_quJg,1367
33
33
  rbx/box/package.py,sha256=YuX_FS6yKx6FaFz0NF0cx3v6jzhqwvsLr3Oprx_TTJA,13645
34
34
  rbx/box/packaging/boca/extension.py,sha256=EQALNEOv4zVDXSKs_dk11n92y7cBZVn8TogIK683lE0,890
35
35
  rbx/box/packaging/boca/packager.py,sha256=XPCauwbemjWNNnfIocJ8pxnlsxRjst4wYXJsVDyMQlM,12632
36
+ rbx/box/packaging/boca/upload.py,sha256=crbch9hcQxH1V2g97vOTOBVALcFvGj91u2K3ce1UtwA,8871
36
37
  rbx/box/packaging/contest_main.py,sha256=UsRfIdNmOf0iLUbzgjxzyECfMuCQINstG1SCClGHaUQ,2808
37
- rbx/box/packaging/main.py,sha256=qltqDncaxtvP3xXyUZGqWampBvh340JJjLru0h8XTPI,3476
38
+ rbx/box/packaging/main.py,sha256=_iZgq-W2JpRdd62lJsQ8vAeLhqtgAY9OFdfo8q58f70,3840
38
39
  rbx/box/packaging/moj/packager.py,sha256=tk0S0hayPnbGrFQsw1Ht_mYOriRlzYHgrkXLO-0ZknY,8724
39
40
  rbx/box/packaging/packager.py,sha256=da2haC1L9cG30myneMrRIAdGubtid0Xmy38BHKPCZZ4,3633
40
41
  rbx/box/packaging/polygon/packager.py,sha256=GfZ-Dc2TDKkb3QNnfOy8yxldho2L401Ao06oWg--Gcs,11714
@@ -50,7 +51,7 @@ rbx/box/retries.py,sha256=tRk2K1bXw2xnwkAj2CsktRHTEhw7YKcPxMQTT6mCy-E,4707
50
51
  rbx/box/sanitizers/warning_stack.py,sha256=RI97_GJgdjTKIXY_r0EKp5h0qQQSDSdNDh5K7zINrqs,2861
51
52
  rbx/box/schema.py,sha256=tOQ1tLHqc_5V-UgrzM44aS8ULAkq-IkeErxjLCFVA8I,16778
52
53
  rbx/box/setter_config.py,sha256=s53talhwM6FTGDCcBhY7IlZ6_6mJ3PMp6V4kTtaSs50,4262
53
- rbx/box/solutions.py,sha256=1DnO6iygX9IflVk5ierP0oL9LS8EuU2cSui8z1YhN08,44653
54
+ rbx/box/solutions.py,sha256=dvED36h6wilQZjbBiKiB98Xx61IeYPUgstSGF1RqH58,45070
54
55
  rbx/box/solutions_test.py,sha256=TCowbxBG3SvDlFO5-qtBj_M_HrAHe0IJaI1XwoQ1d00,1718
55
56
  rbx/box/state.py,sha256=MMf3DvfQji0jKEliCHct2Tpp_0epL1tvP8HbHNArQIc,166
56
57
  rbx/box/statements/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -64,16 +65,23 @@ rbx/box/stresses.py,sha256=k-m8Q2IVd5dap2fSDCbVqLj2LKqXzz6rIR8j9F8sLhY,12310
64
65
  rbx/box/stressing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
66
  rbx/box/stressing/finder_parser.py,sha256=jXpYNa4FyugzmHi3r96Uv4rU1krRQJc5Ihr9jf1cvNo,11918
66
67
  rbx/box/stressing/generator_parser.py,sha256=oHZryjR3YohgaSO9WEirQ7b2e-98WgZStF0N99W4Thw,7380
67
- rbx/box/tasks.py,sha256=oyWtgZvIEIkVV6e-GcJx7x8Z3T5tIDFBZbp0638sLeY,10036
68
- rbx/box/testcase_extractors.py,sha256=T5vCW5qERlqitGrFP6RuITEVr9o8XQozNa4AsxfuV_Y,11871
68
+ rbx/box/tasks.py,sha256=Z_jYkkyHxakQRQjKVQB3zAkXCjMGnfbFOzL4vUoDWvA,10130
69
+ rbx/box/testcase_extractors.py,sha256=J43eG7vpxc5nP_2yhrXJODkd4EYlV4WiYVbM6hzipY4,11944
69
70
  rbx/box/testcase_utils.py,sha256=31rvCpLi681R6Xm1WpG8HPDOkTtF0bRWa8IsmdWGLCk,7556
70
71
  rbx/box/testcases/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
72
  rbx/box/testcases/main.py,sha256=_I7h_obRcpNLRQ6dDJDIE5NAvTyn5nBOhdsBhRA_PvU,5442
72
73
  rbx/box/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
- rbx/box/ui/captured_log.py,sha256=BIlhMFrDcWFa9YD8pUY21G-fJSIBzAz9lpaCZH2WJmc,11526
74
- rbx/box/ui/css/app.tcss,sha256=88tmZCnn4Y2wD-JFEGHoD3VuJGhMU7S7rM2k8FHUZek,777
75
- rbx/box/ui/main.py,sha256=b0rHcBF42W4AOCv7WhtiGf_rUnY0yxpqO5oj3wfR4R4,984
76
- rbx/box/ui/run.py,sha256=Ed5zk3kg3vMggQCud-5GimfGL_n_QwtgATiIim5HYw0,7169
74
+ rbx/box/ui/captured_log.py,sha256=HPoV6LZohuECmjoqOdM_xFZbpICzQnI4n3rF-lf_b1Q,11634
75
+ rbx/box/ui/css/app.tcss,sha256=AeTpKw2dmsBfrxyHGmm3KO7_a-xt7oJrNpA9fzj6xs4,1480
76
+ rbx/box/ui/main.py,sha256=0mdSmUyG8WEhBcbR-k7emZQV5EYtmRc7agoXbC_kR7E,1184
77
+ rbx/box/ui/screens/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
+ rbx/box/ui/screens/build.py,sha256=DtABbf8mJNLn0tCjs5SA9wYBlbxble5-1JKQDlqzphk,156
79
+ rbx/box/ui/screens/command.py,sha256=s29xHhvdQhgr9_E7LjggoKmSw3UuQQrJV3UQNnK97Mk,976
80
+ rbx/box/ui/screens/run.py,sha256=Ab_PFzctlztBTD9L67bYhewvJlhUosWx9beIjyGZ-hI,6270
81
+ rbx/box/ui/screens/run_explorer.py,sha256=3h2R6Vc-YoILqsTq8vrE1JqM7jGOFH17U0JgLuIEolk,78
82
+ rbx/box/ui/screens/test_explorer.py,sha256=cEUZeQNlX8PLggwKwLrJkXby00aJRvh3Mi_5Ju8OJA8,3584
83
+ rbx/box/ui/widgets/file_log.py,sha256=q-kZc7d7wS9fsA85HXWHbhKsqdthApMdrOElPgG6Vgc,1586
84
+ rbx/box/ui/widgets/rich_log_box.py,sha256=mF565c_Y3RYUZ_GJEFj5Eb86SFjsib31wE5qu1K0UBM,91
77
85
  rbx/box/unit.py,sha256=PY96t8qnsHLsoJVanbDnrIx-s8Dada9Fj_v375MhvTw,6477
78
86
  rbx/box/validators.py,sha256=oqlNhw7jivbbH5l8g3xwihPRy76AM7MA3G4A8nyI_V0,10416
79
87
  rbx/box/validators_test.py,sha256=WY4Ho-wlsPHc0YNuz0KFVd6KQ9ouuiou3w5_zMOZ4Fs,362
@@ -93,8 +101,8 @@ rbx/grading/judge/digester.py,sha256=gtOIe_iL4PEWA7OKelW1gjSI-nBvbOpDPJGV8VQyjSg
93
101
  rbx/grading/judge/sandbox.py,sha256=0ILirjd9xQTDH2mycRYAKvad-rMqDHrK72fjX3sBRBw,24868
94
102
  rbx/grading/judge/sandboxes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
95
103
  rbx/grading/judge/sandboxes/isolate.py,sha256=oLFcbOXsuIjbI2G58i9UrGk_h7k32OgL_8yvZybshhQ,25936
96
- rbx/grading/judge/sandboxes/stupid_sandbox.py,sha256=PXVFbXcI0bwG38Blj0PakldzgoRl60vN9vgTbLU3GxQ,10987
97
- rbx/grading/judge/sandboxes/timeit.py,sha256=jQonQhaVI93diYQsJYXwS77IO1t5iZVKJtm80Kuf4hg,10803
104
+ rbx/grading/judge/sandboxes/stupid_sandbox.py,sha256=d0ZrMDFg8P1aDyyvk_dKauP1eAGPMbxgwb3GF_FhuUk,11122
105
+ rbx/grading/judge/sandboxes/timeit.py,sha256=0qs3RD2LmFMg0wolGPSl5sg8HRMHsnZEgUEvBuhGyT4,10865
98
106
  rbx/grading/judge/storage.py,sha256=3vv0HvtenbUZBH33CB5ZzX66ppL22G6munBaAA9BgwQ,9418
99
107
  rbx/grading/judge/test.py,sha256=ll0Iw7zyOpGdKPD_PGH7dvUkb4stQLu-ikbQnqJvuAc,944
100
108
  rbx/grading/judge/testiso.py,sha256=v14DtkWiZFJ9AKMzrb0_vZKPWDt8jz8iIw1Z2O-Advk,1397
@@ -125,13 +133,13 @@ rbx/resources/packagers/boca/compile/kt,sha256=3B900QSD4jSXnX91gJbvI4ZmNELHSiBb5
125
133
  rbx/resources/packagers/boca/compile/pas,sha256=C5IwZzmZpIos49FrLGafRbdGPODNJn7N5JbnLX_FT_4,4576
126
134
  rbx/resources/packagers/boca/compile/py2,sha256=On76To8Zv3z117JiuxjF1pGnq6tKKT4l-FddlP-iQFc,4546
127
135
  rbx/resources/packagers/boca/compile/py3,sha256=6C0n2hy6Pu5kJzkYTuwiCaBB8OrV35nTy9AxI1FMmAk,4546
128
- rbx/resources/packagers/boca/interactive/c,sha256=kNsFAnQ59pq4I0Bvfw7naEfmbhOy3kGdkIM7fq8XHbs,5401
129
- rbx/resources/packagers/boca/interactive/cc,sha256=kNsFAnQ59pq4I0Bvfw7naEfmbhOy3kGdkIM7fq8XHbs,5401
130
- rbx/resources/packagers/boca/interactive/cpp,sha256=kNsFAnQ59pq4I0Bvfw7naEfmbhOy3kGdkIM7fq8XHbs,5401
131
- rbx/resources/packagers/boca/interactive/java,sha256=ePGzIfnTCpVm7arN9mN-sGoPQMTr4ZzSkkY1RBhxPxI,6487
132
- rbx/resources/packagers/boca/interactive/kt,sha256=jBIc3COlY5Zoeitt-3Wu09eXOGGfaH5rZT5T6GGZeto,6377
133
- rbx/resources/packagers/boca/interactive/py2,sha256=TWXMDMC2-4SLgmIxDCpwC6zIJpSgCKORzOyh828DBf0,5565
134
- rbx/resources/packagers/boca/interactive/py3,sha256=PziuEeHuGOkvg-80dqSwORx7zTNs2EVrwXCkpVjiBDE,5565
136
+ rbx/resources/packagers/boca/interactive/c,sha256=_u4-01yugTJFo7UtXproScwJ071NXLXRvrt7fNGSRTs,5578
137
+ rbx/resources/packagers/boca/interactive/cc,sha256=_u4-01yugTJFo7UtXproScwJ071NXLXRvrt7fNGSRTs,5578
138
+ rbx/resources/packagers/boca/interactive/cpp,sha256=_u4-01yugTJFo7UtXproScwJ071NXLXRvrt7fNGSRTs,5578
139
+ rbx/resources/packagers/boca/interactive/java,sha256=RLkK9I_R8CqjdDLNUiujQIk0keDM0BveFzzqyT9MI5s,6664
140
+ rbx/resources/packagers/boca/interactive/kt,sha256=vR_3vqOEsgQu_h-83g0WI6YN8761SdCMsylspn336Sg,6554
141
+ rbx/resources/packagers/boca/interactive/py2,sha256=HnY4ixUbGKDIa8atl4HUBneaQ-lnW7Zj7Ty6q8MznHM,5742
142
+ rbx/resources/packagers/boca/interactive/py3,sha256=ueC9esm9AHJKiKcm8kQk9sVSN9QpTg6kWdEZeuEThro,5742
135
143
  rbx/resources/packagers/boca/interactor_compile.sh,sha256=5dvF_eYuAJS3wlxyjUIJvu9HUNiMvET17rgoPq-WIlc,1082
136
144
  rbx/resources/packagers/boca/run/bkp,sha256=xyDkZDaxgUrW-K2I0YJs8a8dJMuF-k8_ganDGxqhvUQ,4218
137
145
  rbx/resources/packagers/boca/run/c,sha256=1K2KMUEu5w2HAn7aQVI3XgXX6ai8IccGRN2h8L4kPRw,3570
@@ -193,8 +201,8 @@ rbx/testcase.py,sha256=yKOq3CAJZ1YTmInvnoIs0u1iJnRj_X85XiWbLI-p9d8,1951
193
201
  rbx/testcase_rendering.py,sha256=nfmv6dSEqd4aR3TsaODwkKGK6AXty_DDKtWf_ejiQpI,2084
194
202
  rbx/testing_utils.py,sha256=x_PqD8Zd2PkN91NxVHUnSTs044-1WK5KKtttKQBXpFs,2083
195
203
  rbx/utils.py,sha256=SfR844_i0ebRDMkmS_w1YdZiWPc6h2RGADygewlWRbA,4845
196
- rbx_cp-0.5.54.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
197
- rbx_cp-0.5.54.dist-info/METADATA,sha256=Ki-VbHPb5TES3dtzJ_muEqjIuzJRACCQ5MIhdIGG0G4,3387
198
- rbx_cp-0.5.54.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
199
- rbx_cp-0.5.54.dist-info/entry_points.txt,sha256=qBTLBOeifT1F00LWaEewRRE_jQPgvH7BUdJfZ-dYsFU,57
200
- rbx_cp-0.5.54.dist-info/RECORD,,
204
+ rbx_cp-0.5.55.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
205
+ rbx_cp-0.5.55.dist-info/METADATA,sha256=6oII5ebrYHMnirB9nPqL4UvNxdTQM0k65tvUdcjtfPQ,3604
206
+ rbx_cp-0.5.55.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
207
+ rbx_cp-0.5.55.dist-info/entry_points.txt,sha256=qBTLBOeifT1F00LWaEewRRE_jQPgvH7BUdJfZ-dYsFU,57
208
+ rbx_cp-0.5.55.dist-info/RECORD,,