rbx.cp 0.5.62__py3-none-any.whl → 0.5.63__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/solutions.py +4 -1
- rbx/box/ui/screens/run_test_explorer.py +12 -1
- rbx/box/ui/screens/test_explorer.py +14 -1
- rbx/box/ui/widgets/interaction_box.py +59 -0
- rbx/box/ui/widgets/test_output_box.py +11 -2
- rbx/box/ui/widgets/two_sided_test_output_box.py +4 -0
- {rbx_cp-0.5.62.dist-info → rbx_cp-0.5.63.dist-info}/METADATA +1 -1
- {rbx_cp-0.5.62.dist-info → rbx_cp-0.5.63.dist-info}/RECORD +11 -10
- {rbx_cp-0.5.62.dist-info → rbx_cp-0.5.63.dist-info}/LICENSE +0 -0
- {rbx_cp-0.5.62.dist-info → rbx_cp-0.5.63.dist-info}/WHEEL +0 -0
- {rbx_cp-0.5.62.dist-info → rbx_cp-0.5.63.dist-info}/entry_points.txt +0 -0
rbx/box/solutions.py
CHANGED
@@ -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,
|
@@ -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]
|
@@ -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'
|
@@ -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.
|
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.
|
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()
|
@@ -52,7 +52,7 @@ rbx/box/retries.py,sha256=cZcNYLVHFDbhbeqMzxITgo8SYY8qzyxm0tIYcmWl1Ek,4877
|
|
52
52
|
rbx/box/sanitizers/warning_stack.py,sha256=RI97_GJgdjTKIXY_r0EKp5h0qQQSDSdNDh5K7zINrqs,2861
|
53
53
|
rbx/box/schema.py,sha256=y736-wZdGw56T6eDC_m7NAm2XRUdauBXJRQkQO79fpc,16264
|
54
54
|
rbx/box/setter_config.py,sha256=s53talhwM6FTGDCcBhY7IlZ6_6mJ3PMp6V4kTtaSs50,4262
|
55
|
-
rbx/box/solutions.py,sha256=
|
55
|
+
rbx/box/solutions.py,sha256=tMG72QbdexEsfiw70Ryn6hcnXiiNbHIKMAZX0_6uYEY,49078
|
56
56
|
rbx/box/solutions_test.py,sha256=PX1TQoRzNd9mi1SGsG7WFrpqFgNrNX5Kwt0mkwFdoOA,1749
|
57
57
|
rbx/box/state.py,sha256=MMf3DvfQji0jKEliCHct2Tpp_0epL1tvP8HbHNArQIc,166
|
58
58
|
rbx/box/statements/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -81,16 +81,17 @@ rbx/box/ui/screens/command.py,sha256=s29xHhvdQhgr9_E7LjggoKmSw3UuQQrJV3UQNnK97Mk
|
|
81
81
|
rbx/box/ui/screens/error.py,sha256=k6Rs5maR_APKepMtPcDMSXo6BDKrP-pAnFFJgqmXDKE,496
|
82
82
|
rbx/box/ui/screens/run.py,sha256=eKIfFRi-VbqKDxlhZDuOEdVl91XCndnmNIZyj_LMV0c,6028
|
83
83
|
rbx/box/ui/screens/run_explorer.py,sha256=Q6VUhiqBaKr70bqA7pV5qKIQamLqUBCtxZnX2tDkap0,2651
|
84
|
-
rbx/box/ui/screens/run_test_explorer.py,sha256=
|
84
|
+
rbx/box/ui/screens/run_test_explorer.py,sha256=rnO2uIeG_7_vZ_HrRwtNSrDkcyo6RU5hITtcG2HSt0w,6001
|
85
85
|
rbx/box/ui/screens/selector.py,sha256=BmzyEVeBKD9IEUiEea-Y04HnNLzDYQJxAj7Jm-s-D3I,753
|
86
|
-
rbx/box/ui/screens/test_explorer.py,sha256=
|
86
|
+
rbx/box/ui/screens/test_explorer.py,sha256=p_MQmTvmNsB5j2E-CwN8G1mS756aWSMWGonkwMXym2I,4595
|
87
87
|
rbx/box/ui/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
88
88
|
rbx/box/ui/utils/run_ui.py,sha256=457xNZteBTb82Rcg5Cr3AmgBIHLOmRrF4BKmCRyxq3Q,3113
|
89
89
|
rbx/box/ui/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
90
90
|
rbx/box/ui/widgets/file_log.py,sha256=3wlrmkWR-EMibwlwXOJ5sGpTFwFEkRaGYo5fdmf8L3w,1704
|
91
|
+
rbx/box/ui/widgets/interaction_box.py,sha256=WDHmpO5ck21y6hNdUVxvJ81jEg9TVJh39hFJUc5-Dos,1572
|
91
92
|
rbx/box/ui/widgets/rich_log_box.py,sha256=mF565c_Y3RYUZ_GJEFj5Eb86SFjsib31wE5qu1K0UBM,91
|
92
|
-
rbx/box/ui/widgets/test_output_box.py,sha256=
|
93
|
-
rbx/box/ui/widgets/two_sided_test_output_box.py,sha256=
|
93
|
+
rbx/box/ui/widgets/test_output_box.py,sha256=yqeAb-JFvVx1Q7w_qJbDMWQigyGy4ofGECDxQ7P0_2s,3864
|
94
|
+
rbx/box/ui/widgets/two_sided_test_output_box.py,sha256=L-ORiDwd6CP5DFpavrKGBaX0ZHkSoQqbJrGZ4BdFUWc,2289
|
94
95
|
rbx/box/unit.py,sha256=PY96t8qnsHLsoJVanbDnrIx-s8Dada9Fj_v375MhvTw,6477
|
95
96
|
rbx/box/validators.py,sha256=oqlNhw7jivbbH5l8g3xwihPRy76AM7MA3G4A8nyI_V0,10416
|
96
97
|
rbx/box/validators_test.py,sha256=WY4Ho-wlsPHc0YNuz0KFVd6KQ9ouuiou3w5_zMOZ4Fs,362
|
@@ -211,8 +212,8 @@ rbx/testcase.py,sha256=yKOq3CAJZ1YTmInvnoIs0u1iJnRj_X85XiWbLI-p9d8,1951
|
|
211
212
|
rbx/testcase_rendering.py,sha256=nfmv6dSEqd4aR3TsaODwkKGK6AXty_DDKtWf_ejiQpI,2084
|
212
213
|
rbx/testing_utils.py,sha256=x_PqD8Zd2PkN91NxVHUnSTs044-1WK5KKtttKQBXpFs,2083
|
213
214
|
rbx/utils.py,sha256=SfR844_i0ebRDMkmS_w1YdZiWPc6h2RGADygewlWRbA,4845
|
214
|
-
rbx_cp-0.5.
|
215
|
-
rbx_cp-0.5.
|
216
|
-
rbx_cp-0.5.
|
217
|
-
rbx_cp-0.5.
|
218
|
-
rbx_cp-0.5.
|
215
|
+
rbx_cp-0.5.63.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
216
|
+
rbx_cp-0.5.63.dist-info/METADATA,sha256=dgNReBRlMvN09iAcedaaGLwPJ69PEfhET7Ml9yaGwpo,3604
|
217
|
+
rbx_cp-0.5.63.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
218
|
+
rbx_cp-0.5.63.dist-info/entry_points.txt,sha256=qBTLBOeifT1F00LWaEewRRE_jQPgvH7BUdJfZ-dYsFU,57
|
219
|
+
rbx_cp-0.5.63.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|