rbx.cp 0.5.66__py3-none-any.whl → 0.5.68__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/ui/css/app.tcss CHANGED
@@ -1,10 +1,11 @@
1
1
  Screen {
2
2
  background: $background;
3
3
  color: $text;
4
+ align: center middle;
4
5
  }
5
6
 
6
- Screen {
7
- align: center middle;
7
+ ModalScreen {
8
+ background: $background 65%;
8
9
  }
9
10
 
10
11
  ListView {
@@ -25,13 +26,9 @@ DiffBox {
25
26
  border: solid $accent;
26
27
  height: 1fr;
27
28
  width: 1fr;
28
- Markdown {
29
+ RichLog {
29
30
  height: 1fr;
30
31
  width: 1fr;
31
-
32
- .code_inline {
33
- background: $background;
34
- }
35
32
  }
36
33
  }
37
34
 
@@ -110,4 +107,27 @@ TestExplorerScreen, RunTestExplorerScreen {
110
107
  border: solid $accent;
111
108
  padding: 0 1;
112
109
  }
110
+ }
111
+
112
+ #rich-dialog {
113
+ max-width: 80;
114
+ height: auto;
115
+ max-height: 5;
116
+
117
+ RichLog {
118
+ border: solid $accent;
119
+ padding: 0 1;
120
+ }
121
+ }
122
+
123
+ #selector-dialog {
124
+ max-width: 80;
125
+ height: auto;
126
+ }
127
+
128
+ #run-tips {
129
+ border: solid $accent;
130
+ padding: 0 1;
131
+ height: auto;
132
+ text-align: center;
113
133
  }
rbx/box/ui/main.py CHANGED
@@ -6,6 +6,7 @@ from textual.containers import Center
6
6
  from textual.screen import Screen
7
7
  from textual.widgets import Footer, Header, OptionList
8
8
 
9
+ from rbx.box import remote
9
10
  from rbx.box.ui.screens.differ import DifferScreen
10
11
  from rbx.box.ui.screens.run_explorer import RunExplorerScreen
11
12
  from rbx.box.ui.screens.test_explorer import TestExplorerScreen
@@ -57,5 +58,7 @@ def start():
57
58
 
58
59
 
59
60
  def start_differ(path1: pathlib.Path, path2: pathlib.Path):
61
+ path1, path2 = remote.expand_files([path1, path2])
62
+
60
63
  app = rbxDifferApp(path1, path2)
61
64
  app.run()
@@ -0,0 +1,29 @@
1
+ from typing import Optional
2
+
3
+ from textual.app import ComposeResult
4
+ from textual.containers import Container
5
+ from textual.screen import ModalScreen
6
+
7
+ from rbx.box.ui.widgets.rich_log_box import RichLogBox
8
+
9
+
10
+ class RichLogModal(ModalScreen[None]):
11
+ BINDINGS = [
12
+ ('q', 'app.pop_screen', 'Close'),
13
+ ('g', 'app.pop_screen', 'Close'),
14
+ ]
15
+
16
+ def __init__(self, log: str, title: Optional[str] = None):
17
+ super().__init__()
18
+ self._log = log
19
+ self._title = title
20
+
21
+ def compose(self) -> ComposeResult:
22
+ with Container(id='rich-dialog'):
23
+ box = RichLogBox(markup=True)
24
+ if self._title:
25
+ box.border_title = self._title
26
+ yield box
27
+
28
+ async def on_mount(self):
29
+ self.query_one(RichLogBox).write(self._log)
@@ -1,15 +1,19 @@
1
1
  from typing import Optional
2
2
 
3
3
  from textual.app import ComposeResult
4
+ from textual.containers import Vertical
4
5
  from textual.reactive import reactive
5
6
  from textual.screen import Screen
6
7
  from textual.widgets import Footer, Header, Label, ListItem, ListView
7
8
 
9
+ from rbx.box import package
10
+ from rbx.box.schema import TaskType
8
11
  from rbx.box.solutions import SolutionReportSkeleton
9
12
  from rbx.box.ui.screens.error import ErrorScreen
10
13
  from rbx.box.ui.screens.run_test_explorer import RunTestExplorerScreen
11
14
  from rbx.box.ui.screens.selector import SelectorScreen
12
15
  from rbx.box.ui.utils.run_ui import get_skeleton, get_solution_markup, has_run
16
+ from rbx.box.ui.widgets.rich_log_box import RichLogBox
13
17
 
14
18
 
15
19
  class RunExplorerScreen(Screen):
@@ -29,9 +33,22 @@ class RunExplorerScreen(Screen):
29
33
  Label(get_solution_markup(self.skeleton, sol), markup=True)
30
34
  for i, sol in enumerate(self.skeleton.solutions)
31
35
  ]
32
- run_list = ListView(*[ListItem(item) for item in items], id='run-list')
33
- run_list.border_title = 'Runs'
34
- yield run_list
36
+ with Vertical():
37
+ run_list = ListView(*[ListItem(item) for item in items], id='run-list')
38
+ run_list.border_title = 'Runs'
39
+ yield run_list
40
+
41
+ tips = RichLogBox(id='run-tips')
42
+ tips.markup = True
43
+ tips.display = False
44
+ tips.border_title = 'Tips'
45
+ pkg = package.find_problem_package_or_die()
46
+ if pkg.type == TaskType.COMMUNICATION:
47
+ tips.display = True
48
+ tips.write(
49
+ 'This is an interactive problem.\nYou can use the [bold blue]rbx -d run[/bold blue] command to capture the interaction between the processes and see them here.'
50
+ )
51
+ yield tips
35
52
 
36
53
  def on_mount(self):
37
54
  if not has_run():
@@ -13,7 +13,9 @@ from rbx.box.testcase_extractors import (
13
13
  GenerationTestcaseEntry,
14
14
  extract_generation_testcases,
15
15
  )
16
+ from rbx.box.ui.screens.rich_log_modal import RichLogModal
16
17
  from rbx.box.ui.utils.run_ui import (
18
+ get_metadata_markup,
17
19
  get_run_testcase_markup,
18
20
  get_run_testcase_metadata_markup,
19
21
  )
@@ -30,6 +32,7 @@ class RunTestExplorerScreen(Screen):
30
32
  ('3', 'show_log', 'Show log'),
31
33
  ('m', 'toggle_metadata', 'Toggle metadata'),
32
34
  ('s', 'toggle_side_by_side', 'Toggle sxs'),
35
+ ('g', 'toggle_test_metadata', 'Toggle test metadata'),
33
36
  ]
34
37
 
35
38
  side_by_side: reactive[bool] = reactive(False)
@@ -62,6 +65,11 @@ class RunTestExplorerScreen(Screen):
62
65
  yield TwoSidedTestBoxWidget(id='test-output')
63
66
 
64
67
  async def on_mount(self):
68
+ self.title = str(self.solution.path)
69
+
70
+ if self.diff_solution is not None:
71
+ self.title = f'{self.title} vs. {self.diff_solution.path}'
72
+
65
73
  self.query_one('#test-list').border_title = 'Tests'
66
74
  self.query_one('#test-input').border_title = 'Input'
67
75
 
@@ -164,3 +172,15 @@ class RunTestExplorerScreen(Screen):
164
172
  return
165
173
  widget = self.query_one('#test-output', TwoSidedTestBoxWidget)
166
174
  widget.diff_with_data = diff_with_data
175
+
176
+ def action_toggle_test_metadata(self):
177
+ list_view = self.query_one('#test-list', ListView)
178
+ if list_view.index is None:
179
+ return
180
+ entry = self._entries[list_view.index]
181
+ self.app.push_screen(
182
+ RichLogModal(
183
+ get_metadata_markup(entry),
184
+ title='Testcase metadata',
185
+ )
186
+ )
@@ -1,6 +1,7 @@
1
1
  from typing import List, Optional
2
2
 
3
3
  from textual.app import ComposeResult
4
+ from textual.containers import Container
4
5
  from textual.screen import ModalScreen
5
6
  from textual.widgets import ListItem, ListView
6
7
 
@@ -14,10 +15,11 @@ class SelectorScreen(ModalScreen[int]):
14
15
  self.title = title
15
16
 
16
17
  def compose(self) -> ComposeResult:
17
- list_view = ListView(*self.options)
18
- if self.title:
19
- list_view.border_title = self.title
20
- yield list_view
18
+ with Container(id='selector-dialog'):
19
+ list_view = ListView(*self.options)
20
+ if self.title:
21
+ list_view.border_title = self.title
22
+ yield list_view
21
23
 
22
24
  def on_list_view_selected(self, event: ListView.Selected):
23
25
  self.dismiss(event.list_view.index)
@@ -11,6 +11,7 @@ from rbx.box.testcase_extractors import (
11
11
  GenerationTestcaseEntry,
12
12
  extract_generation_testcases_from_groups,
13
13
  )
14
+ from rbx.box.ui.utils.run_ui import get_metadata_markup
14
15
  from rbx.box.ui.widgets.file_log import FileLog
15
16
  from rbx.box.ui.widgets.rich_log_box import RichLogBox
16
17
  from rbx.box.ui.widgets.test_output_box import TestBoxWidget, TestcaseRenderingData
@@ -78,19 +79,7 @@ class TestExplorerScreen(Screen):
78
79
  )
79
80
 
80
81
  metadata.clear()
81
- metadata.write(
82
- f'[bold]{entry.group_entry.group}[/bold] / [bold]{entry.group_entry.index}[/bold]'
83
- )
84
- if entry.metadata.copied_from is not None:
85
- metadata.write(
86
- f'[bold]Copied from:[/bold] {entry.metadata.copied_from.inputPath}'
87
- )
88
- if entry.metadata.generator_call is not None:
89
- metadata.write(f'[bold]Gen. call:[/bold] {entry.metadata.generator_call}')
90
- if entry.metadata.generator_script is not None:
91
- metadata.write(
92
- f'[bold]Gen. script:[/bold] {entry.metadata.generator_script}'
93
- )
82
+ metadata.write(get_metadata_markup(entry))
94
83
 
95
84
  async def _update_tests(self):
96
85
  self.watch(
@@ -4,6 +4,7 @@ from typing import List, Optional
4
4
  from rbx import utils
5
5
  from rbx.box import package, solutions
6
6
  from rbx.box.solutions import SolutionReportSkeleton, SolutionSkeleton
7
+ from rbx.box.testcase_extractors import GenerationTestcaseEntry
7
8
  from rbx.box.testcase_utils import TestcaseEntry
8
9
  from rbx.grading.steps import Evaluation
9
10
 
@@ -93,3 +94,15 @@ def get_run_testcase_metadata_markup(
93
94
  if checker_msg is not None:
94
95
  lines.append(f'[b]Checker:[/b] {checker_msg}')
95
96
  return '\n'.join(lines)
97
+
98
+
99
+ def get_metadata_markup(entry: GenerationTestcaseEntry) -> str:
100
+ lines = []
101
+ lines.append(f'[b]{entry.group_entry.group}[/b] / [b]{entry.group_entry.index}[/b]')
102
+ if entry.metadata.copied_from is not None:
103
+ lines.append(f'[b]Copied from:[/b] {entry.metadata.copied_from.inputPath}')
104
+ if entry.metadata.generator_call is not None:
105
+ lines.append(f'[b]Gen. call:[/b] {entry.metadata.generator_call}')
106
+ if entry.metadata.generator_script is not None:
107
+ lines.append(f'[b]Gen. script:[/b] {entry.metadata.generator_script}')
108
+ return '\n'.join(lines)
rbx/box/unit.py CHANGED
@@ -14,6 +14,7 @@ from rbx.box.schema import (
14
14
  ValidatorOutcome,
15
15
  ValidatorTest,
16
16
  )
17
+ from rbx.grading.steps import Outcome
17
18
  from rbx.utils import StatusProgress
18
19
 
19
20
 
@@ -181,6 +182,39 @@ async def run_checker_unit_tests(progress: StatusProgress):
181
182
  skip_run_log=True,
182
183
  )
183
184
 
185
+ if test.answer is not None:
186
+ ans_result = await checkers.check(
187
+ compiled_digest,
188
+ run_log=None,
189
+ testcase=Testcase(
190
+ inputPath=test.input or empty_file,
191
+ outputPath=test.answer,
192
+ ),
193
+ program_output=test.answer,
194
+ skip_run_log=True,
195
+ )
196
+
197
+ if ans_result.outcome != Outcome.ACCEPTED:
198
+ console.console.print(
199
+ f'[error]FAIL[/error] Unit test [item]#{i + 1}[/item] ({test.running_tests_formatted_string()})'
200
+ )
201
+ console.console.print(
202
+ '[error]Error validating the [item].ans[/item] file.'
203
+ )
204
+ console.console.print(
205
+ '[error]While checking your [item].ans[/item] against itself, the checker returned the following error:[/error]'
206
+ )
207
+ console.console.print(
208
+ f' [status]Verdict[/status] {ans_result.outcome.name}'
209
+ )
210
+ console.console.print(
211
+ f' [status]Message[/status] {ans_result.message}'
212
+ )
213
+ console.console.print(
214
+ '[error]Please fix your [item].ans[/item] file and try again, or double-check that your checker is correct.[/error]'
215
+ )
216
+ continue
217
+
184
218
  markup = (
185
219
  '[success]OK[/success]'
186
220
  if test.outcome.match(result.outcome)
rbx/grading/steps.py CHANGED
@@ -34,6 +34,7 @@ class Outcome(Enum):
34
34
  WRONG_ANSWER = 'wrong-answer'
35
35
  MEMORY_LIMIT_EXCEEDED = 'memory-limit-exceeded'
36
36
  TIME_LIMIT_EXCEEDED = 'time-limit-exceeded'
37
+ IDLENESS_LIMIT_EXCEEDED = 'idleness-limit-exceeded'
37
38
  RUNTIME_ERROR = 'runtime-error'
38
39
  OUTPUT_LIMIT_EXCEEDED = 'output-limit-exceeded'
39
40
  JUDGE_FAILED = 'judge-failed'
@@ -46,6 +47,12 @@ class Outcome(Enum):
46
47
 
47
48
  return max(outcomes, key=_outcome_to_int)
48
49
 
50
+ def is_slow(self) -> bool:
51
+ return self in [
52
+ Outcome.TIME_LIMIT_EXCEEDED,
53
+ Outcome.IDLENESS_LIMIT_EXCEEDED,
54
+ ]
55
+
49
56
 
50
57
  class DigestHolder(BaseModel):
51
58
  value: Optional[str] = None
@@ -0,0 +1,13 @@
1
+ #include "testlib.h"
2
+
3
+ using namespace std;
4
+
5
+ int main(int argc, char *argv[]) {
6
+ setName("no-op checker");
7
+ registerTestlibCmd(argc, argv);
8
+
9
+ while (!ouf.seekEof()) {
10
+ ouf.skipChar();
11
+ }
12
+ quitf(_ok, "ok");
13
+ }
@@ -107,8 +107,13 @@ cdir=$(pwd)
107
107
  echo "Current directory is $cdir" >&2
108
108
 
109
109
  # Make sure the class name is Main.
110
- mv "src/$name" "src/Main.java"
111
- sed -i -E "s/public[[:space:]]+class[[:space:]]+[A-Za-z0-9_\\$]+([^A-Za-z0-9_\\$])/public class Main\1/" src/Main.java
110
+ regex="public[[:space:]]+class[[:space:]]+[A-Za-z0-9_\\$]+([^A-Za-z0-9_\\$])"
111
+ klass=$(basename "$name" .java)
112
+ if [ -n "$(sed -n -E "/$regex/p" src/$name)" ]; then
113
+ klass="Main"
114
+ mv "src/$name" "src/Main.java"
115
+ sed -i -E "s/$regex/public class Main\1/" src/Main.java
116
+ fi
112
117
 
113
118
  cat <<EOF >compileit.sh
114
119
  #!/bin/bash
@@ -126,8 +131,8 @@ if [ ! -x \$jar ]; then
126
131
  fi
127
132
  export CLASSPATH=.:\$CLASSPATH
128
133
  cd src
129
- if [ -r "Main.java" ]; then
130
- \$javac Main.java
134
+ if [ -r "\$klass.java" ]; then
135
+ \$javac \$klass.java
131
136
  echo \$? > ../compileit.retcode
132
137
  fi
133
138
  find . -name "*.java" | while read lin; do
@@ -135,7 +140,7 @@ find . -name "*.java" | while read lin; do
135
140
  echo \$? > ../compileit.retcode
136
141
  done
137
142
  rm -f ../$jarfile
138
- \$jar cvfe ../$jarfile Main *
143
+ \$jar cvfe ../$jarfile \$klass *
139
144
  exit 0
140
145
  EOF
141
146
  chmod 755 compileit.sh
@@ -42,47 +42,47 @@
42
42
  umask 0022
43
43
 
44
44
  if [ "$1" == "" ]; then
45
- echo "parameter problem"
46
- exit 43
45
+ echo "parameter problem"
46
+ exit 43
47
47
  fi
48
48
  if [ ! -r "$1" ]; then
49
- echo "$1 not found or it's not readable"
50
- exit 44
49
+ echo "$1 not found or it's not readable"
50
+ exit 44
51
51
  fi
52
52
  name="$1"
53
53
  if [ ! -r "$1" ]; then
54
- echo "$1 not found or it's not readable"
55
- exit 44
54
+ echo "$1 not found or it's not readable"
55
+ exit 44
56
56
  fi
57
57
  mkdir -p src
58
58
  if [ "${name##*.}" == "zip" -a "${name##*.}" == "ZIP" ]; then
59
- unzip "$name" -d src
60
- name="*.c"
59
+ unzip "$name" -d src
60
+ name="*.c"
61
61
  else
62
- cp "$name" src
62
+ cp "$name" src
63
63
  fi
64
64
  id -u bocajail >/dev/null 2>/dev/null
65
65
  if [ $? == 0 ]; then
66
- bocau=`id -u bocajail`
67
- bocag=`id -g bocajail`
68
- chown bocajail.nogroup .
66
+ bocau=$(id -u bocajail)
67
+ bocag=$(id -g bocajail)
68
+ chown bocajail.nogroup .
69
69
  else
70
- bocau=`id -u nobody`
71
- bocag=`id -g nobody`
72
- chown nobody.nogroup .
70
+ bocau=$(id -u nobody)
71
+ bocag=$(id -g nobody)
72
+ chown nobody.nogroup .
73
73
  fi
74
74
  if [ "$bocau" == "" -o "$bocag" == "" ]; then
75
- echo "error finding user to run script"
76
- exit 43
75
+ echo "error finding user to run script"
76
+ exit 43
77
77
  fi
78
78
 
79
79
  # this script makes use of safeexec to execute the code with less privilegies
80
80
  # make sure that directories below are correct.
81
- sf=`which safeexec`
81
+ sf=$(which safeexec)
82
82
  [ -x "$sf" ] || sf=/usr/bin/safeexec
83
83
  if [ ! -x $sf ]; then
84
- echo "$sf not found or it's not executable"
85
- exit 46
84
+ echo "$sf not found or it's not executable"
85
+ exit 46
86
86
  fi
87
87
  maxm=512000
88
88
  if [ "$4" != "" ]; then
@@ -93,9 +93,9 @@ fi
93
93
 
94
94
  # setting up the timelimit according to the problem
95
95
  if [ "$3" == "" ]; then
96
- time=5
96
+ time=5
97
97
  else
98
- time=$3
98
+ time=$3
99
99
  fi
100
100
  let "ttime = $time + 30"
101
101
 
@@ -106,7 +106,7 @@ else
106
106
  fi
107
107
 
108
108
  rm -f "$exe" compileit.retcode runit.retcode 2>/dev/null
109
- cat <<EOF > compileit.sh
109
+ cat <<EOF >compileit.sh
110
110
  #!/bin/bash
111
111
  cc=\`which python2\`
112
112
  [ -x "\$cc" ] || cc=/usr/bin/python2
@@ -115,6 +115,14 @@ if [ ! -x "\$cc" ]; then
115
115
  exit 47
116
116
  fi
117
117
  cd src
118
+ "\$cc" -m py_compile "$name"
119
+ pyc_ret=\$?
120
+ if [ "\$pyc_ret" != "0" ]; then
121
+ echo "python syntax check failed: \$pyc_ret"
122
+ echo \$pyc_ret > ../compileit.retcode
123
+ exit 0
124
+ fi
125
+
118
126
  echo "#!/usr/bin/python2" | cat - "$name" > "../$exe"
119
127
  chmod 755 "../$exe"
120
128
  echo \$? > ../compileit.retcode
@@ -122,13 +130,13 @@ exit 0
122
130
  EOF
123
131
  chmod 755 compileit.sh
124
132
 
125
- cdir=`pwd`
133
+ cdir=$(pwd)
126
134
  echo "Current directory is $cdir" >&2
127
135
  echo $cdir | grep -q "/bocajail"
128
136
  if [ $? == 0 ]; then
129
- cdir=`echo $cdir | sed "s/.*\/bocajail//"`
130
- echo "Internal directory is $cdir"
131
- cat <<EOF > runit.sh
137
+ cdir=$(echo $cdir | sed "s/.*\/bocajail//")
138
+ echo "Internal directory is $cdir"
139
+ cat <<EOF >runit.sh
132
140
  #!/bin/bash
133
141
  cd "$cdir"
134
142
  [ -f /proc/cpuinfo ] || /bin/mount -t proc proc /proc
@@ -142,32 +150,32 @@ if [ ! -d /bocajail ]; then
142
150
  /bin/umount /sys 2>/dev/null
143
151
  fi
144
152
  EOF
145
- chmod 755 runit.sh
146
- chroot /bocajail "$cdir/runit.sh"
147
- if [ -r runit.retcode ]; then
148
- ret=`cat runit.retcode`
149
- else
150
- ret=99
151
- fi
153
+ chmod 755 runit.sh
154
+ chroot /bocajail "$cdir/runit.sh"
155
+ if [ -r runit.retcode ]; then
156
+ ret=$(cat runit.retcode)
157
+ else
158
+ ret=99
159
+ fi
152
160
  else
153
- echo "COMPILATION IS NOT BEING CHROOTED -- THIS IS NOT AN IDEAL SETTING"
154
- $sf -r1 -F1000 -n0 -U$bocau -G$bocag -C. -ostdout0 -estderr0 -d$maxm -m$maxm -f20000 -t$ttime -T$ttime ./compileit.sh
155
- ret=$?
161
+ echo "COMPILATION IS NOT BEING CHROOTED -- THIS IS NOT AN IDEAL SETTING"
162
+ $sf -r1 -F1000 -n0 -U$bocau -G$bocag -C. -ostdout0 -estderr0 -d$maxm -m$maxm -f20000 -t$ttime -T$ttime ./compileit.sh
163
+ ret=$?
156
164
  fi
157
165
  if [ -f "stdout0" ]; then
158
- cat "stdout0"
166
+ cat "stdout0"
159
167
  fi
160
168
  if [ -f "stderr0" ]; then
161
- cat "stderr0"
169
+ cat "stderr0"
162
170
  fi
163
171
  rm -rf src/
164
172
  if [ "$ret" != "0" ]; then
165
- echo "Compilation Error: $ret"
166
- exit $ret
173
+ echo "Compilation Error: $ret"
174
+ exit $ret
167
175
  fi
168
- ret=`cat compileit.retcode`
176
+ ret=$(cat compileit.retcode)
169
177
  if [ "$ret" != "0" ]; then
170
- echo "Compilation Error: $ret"
171
- ret=1
178
+ echo "Compilation Error: $ret"
179
+ ret=1
172
180
  fi
173
181
  exit $ret