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.
- rbx/box/checkers.py +11 -1
- rbx/box/cli.py +8 -0
- rbx/box/contest/schema.py +53 -4
- rbx/box/naming.py +20 -5
- rbx/box/packaging/boca/upload.py +247 -0
- rbx/box/packaging/main.py +13 -1
- rbx/box/solutions.py +12 -1
- rbx/box/tasks.py +4 -2
- rbx/box/testcase_extractors.py +3 -0
- rbx/box/ui/captured_log.py +13 -8
- rbx/box/ui/css/app.tcss +47 -8
- rbx/box/ui/main.py +5 -1
- rbx/box/ui/screens/__init__.py +0 -0
- rbx/box/ui/screens/build.py +6 -0
- rbx/box/ui/screens/command.py +35 -0
- rbx/box/ui/{run.py → screens/run.py} +10 -38
- rbx/box/ui/screens/run_explorer.py +5 -0
- rbx/box/ui/screens/test_explorer.py +100 -0
- rbx/box/ui/widgets/file_log.py +63 -0
- rbx/box/ui/widgets/rich_log_box.py +5 -0
- rbx/grading/judge/sandboxes/stupid_sandbox.py +5 -1
- rbx/grading/judge/sandboxes/timeit.py +2 -1
- rbx/resources/packagers/boca/interactive/c +8 -1
- rbx/resources/packagers/boca/interactive/cc +8 -1
- rbx/resources/packagers/boca/interactive/cpp +8 -1
- rbx/resources/packagers/boca/interactive/java +8 -1
- rbx/resources/packagers/boca/interactive/kt +8 -1
- rbx/resources/packagers/boca/interactive/py2 +8 -1
- rbx/resources/packagers/boca/interactive/py3 +8 -1
- {rbx_cp-0.5.54.dist-info → rbx_cp-0.5.55.dist-info}/METADATA +7 -2
- {rbx_cp-0.5.54.dist-info → rbx_cp-0.5.55.dist-info}/RECORD +34 -26
- {rbx_cp-0.5.54.dist-info → rbx_cp-0.5.55.dist-info}/LICENSE +0 -0
- {rbx_cp-0.5.54.dist-info → rbx_cp-0.5.55.dist-info}/WHEEL +0 -0
- {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', '
|
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(
|
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([
|
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
|
-
|
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,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)
|
@@ -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
|
-
|
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.
|
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 (>=
|
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=
|
8
|
-
rbx/box/cli.py,sha256=
|
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=
|
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=
|
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=
|
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=
|
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=
|
68
|
-
rbx/box/testcase_extractors.py,sha256=
|
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=
|
74
|
-
rbx/box/ui/css/app.tcss,sha256=
|
75
|
-
rbx/box/ui/main.py,sha256=
|
76
|
-
rbx/box/ui/
|
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=
|
97
|
-
rbx/grading/judge/sandboxes/timeit.py,sha256=
|
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=
|
129
|
-
rbx/resources/packagers/boca/interactive/cc,sha256=
|
130
|
-
rbx/resources/packagers/boca/interactive/cpp,sha256=
|
131
|
-
rbx/resources/packagers/boca/interactive/java,sha256=
|
132
|
-
rbx/resources/packagers/boca/interactive/kt,sha256=
|
133
|
-
rbx/resources/packagers/boca/interactive/py2,sha256=
|
134
|
-
rbx/resources/packagers/boca/interactive/py3,sha256=
|
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.
|
197
|
-
rbx_cp-0.5.
|
198
|
-
rbx_cp-0.5.
|
199
|
-
rbx_cp-0.5.
|
200
|
-
rbx_cp-0.5.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|