rbx.cp 0.5.40__py3-none-any.whl → 0.5.45__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 (57) hide show
  1. rbx/box/builder.py +6 -6
  2. rbx/box/checkers.py +100 -25
  3. rbx/box/cli.py +868 -0
  4. rbx/box/code.py +272 -84
  5. rbx/box/contest/statements.py +4 -2
  6. rbx/box/generators.py +55 -49
  7. rbx/box/generators_test.py +7 -7
  8. rbx/box/main.py +1 -868
  9. rbx/box/package.py +57 -2
  10. rbx/box/packaging/boca/packager.py +2 -1
  11. rbx/box/packaging/main.py +17 -9
  12. rbx/box/packaging/moj/packager.py +49 -10
  13. rbx/box/retries.py +5 -5
  14. rbx/box/schema.py +20 -4
  15. rbx/box/solutions.py +46 -108
  16. rbx/box/solutions_test.py +5 -6
  17. rbx/box/state.py +1 -0
  18. rbx/box/statements/build_statements.py +4 -2
  19. rbx/box/stresses.py +23 -12
  20. rbx/box/tasks.py +277 -0
  21. rbx/box/testcase_extractors.py +21 -21
  22. rbx/box/testcases/main.py +19 -14
  23. rbx/box/unit.py +10 -7
  24. rbx/box/validators.py +10 -10
  25. rbx/box/validators_test.py +3 -3
  26. rbx/grading/judge/cacher.py +0 -4
  27. rbx/grading/judge/digester.py +0 -3
  28. rbx/grading/judge/sandbox.py +15 -0
  29. rbx/grading/judge/sandboxes/stupid_sandbox.py +20 -6
  30. rbx/grading/judge/sandboxes/timeit.py +117 -7
  31. rbx/grading/judge/storage.py +0 -4
  32. rbx/grading/steps.py +76 -2
  33. rbx/grading/steps_with_caching.py +45 -3
  34. rbx/grading/steps_with_caching_run_test.py +51 -49
  35. rbx/main.py +0 -4
  36. rbx/resources/packagers/moj/scripts/compare.sh +25 -6
  37. rbx/test.py +6 -4
  38. {rbx_cp-0.5.40.dist-info → rbx_cp-0.5.45.dist-info}/METADATA +2 -2
  39. {rbx_cp-0.5.40.dist-info → rbx_cp-0.5.45.dist-info}/RECORD +42 -55
  40. {rbx_cp-0.5.40.dist-info → rbx_cp-0.5.45.dist-info}/WHEEL +1 -1
  41. rbx/testdata/box1/gen1.cpp +0 -7
  42. rbx/testdata/box1/gen2.cpp +0 -9
  43. rbx/testdata/box1/genScript.py +0 -2
  44. rbx/testdata/box1/hard-tle.sol.cpp +0 -26
  45. rbx/testdata/box1/ole.cpp +0 -17
  46. rbx/testdata/box1/problem.rbx.yml +0 -39
  47. rbx/testdata/box1/re.sol.cpp +0 -23
  48. rbx/testdata/box1/sol.cpp +0 -22
  49. rbx/testdata/box1/tests/1.in +0 -1
  50. rbx/testdata/box1/tle-and-incorrect.sol.cpp +0 -33
  51. rbx/testdata/box1/tle.sol.cpp +0 -35
  52. rbx/testdata/box1/validator.cpp +0 -11
  53. rbx/testdata/box1/wa.sol.cpp +0 -22
  54. rbx/testdata/caching/executable.py +0 -1
  55. rbx/testdata/compatible +0 -0
  56. {rbx_cp-0.5.40.dist-info → rbx_cp-0.5.45.dist-info}/LICENSE +0 -0
  57. {rbx_cp-0.5.40.dist-info → rbx_cp-0.5.45.dist-info}/entry_points.txt +0 -0
@@ -15,7 +15,7 @@ from rbx.grading.steps import (
15
15
  )
16
16
 
17
17
 
18
- def test_run_from_digest(
18
+ async def test_run_from_digest(
19
19
  cleandir: pathlib.Path,
20
20
  dependency_cache: DependencyCache,
21
21
  sandbox: SandboxBase,
@@ -29,7 +29,7 @@ def test_run_from_digest(
29
29
  artifacts.outputs.append(
30
30
  GradingFileOutput(src=pathlib.Path('box-out.txt'), dest=pathlib.Path('out.txt'))
31
31
  )
32
- steps_with_caching.run(
32
+ await steps_with_caching.run(
33
33
  f'{sys.executable} executable.py',
34
34
  params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
35
35
  sandbox=sandbox,
@@ -45,7 +45,7 @@ def test_run_from_digest(
45
45
  assert not artifacts.logs.cached
46
46
 
47
47
 
48
- def test_run_from_disk(
48
+ async def test_run_from_disk(
49
49
  cleandir: pathlib.Path,
50
50
  dependency_cache: DependencyCache,
51
51
  sandbox: SandboxBase,
@@ -60,7 +60,7 @@ def test_run_from_disk(
60
60
  artifacts.outputs.append(
61
61
  GradingFileOutput(src=pathlib.Path('box-out.txt'), dest=pathlib.Path('out.txt'))
62
62
  )
63
- steps_with_caching.run(
63
+ await steps_with_caching.run(
64
64
  f'{sys.executable} executable.py',
65
65
  params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
66
66
  sandbox=sandbox,
@@ -74,13 +74,13 @@ def test_run_from_disk(
74
74
  assert not artifacts.logs.cached
75
75
 
76
76
 
77
- def test_run_caches_intermediate_digest_if_dest_changes(
77
+ async def test_run_caches_intermediate_digest_if_dest_changes(
78
78
  cleandir: pathlib.Path,
79
79
  dependency_cache: DependencyCache,
80
80
  sandbox: SandboxBase,
81
81
  file_cacher: FileCacher,
82
82
  ):
83
- def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
83
+ async def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
84
84
  executable = DigestOrSource.create(file_cacher.put_file_text('print(5)'))
85
85
  artifacts = GradingArtifacts()
86
86
  artifacts.inputs.append(
@@ -89,7 +89,7 @@ def test_run_caches_intermediate_digest_if_dest_changes(
89
89
  artifacts.outputs.append(
90
90
  GradingFileOutput(src=pathlib.Path('box-out.txt'), dest=dest)
91
91
  )
92
- steps_with_caching.run(
92
+ await steps_with_caching.run(
93
93
  f'{sys.executable} executable.py',
94
94
  params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
95
95
  sandbox=sandbox,
@@ -98,24 +98,26 @@ def test_run_caches_intermediate_digest_if_dest_changes(
98
98
  )
99
99
  return artifacts
100
100
 
101
- artifacts = configure_and_run_with_dest(pathlib.Path('out.txt'))
101
+ artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
102
102
  assert (cleandir / 'out.txt').read_text().strip() == '5'
103
103
  assert artifacts.logs is not None
104
104
  assert not artifacts.logs.cached
105
105
 
106
- another_artifacts = configure_and_run_with_dest(pathlib.Path('another-out.txt'))
106
+ another_artifacts = await configure_and_run_with_dest(
107
+ pathlib.Path('another-out.txt')
108
+ )
107
109
  assert (cleandir / 'out.txt').read_text().strip() == '5'
108
110
  assert another_artifacts.logs is not None
109
111
  assert another_artifacts.logs.cached
110
112
 
111
113
 
112
- def test_run_overwrite_changed_file_with_storage_value(
114
+ async def test_run_overwrite_changed_file_with_storage_value(
113
115
  cleandir: pathlib.Path,
114
116
  dependency_cache: DependencyCache,
115
117
  sandbox: SandboxBase,
116
118
  file_cacher: FileCacher,
117
119
  ):
118
- def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
120
+ async def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
119
121
  executable = DigestOrSource.create(file_cacher.put_file_text('print(5)'))
120
122
  artifacts = GradingArtifacts()
121
123
  artifacts.inputs.append(
@@ -124,7 +126,7 @@ def test_run_overwrite_changed_file_with_storage_value(
124
126
  artifacts.outputs.append(
125
127
  GradingFileOutput(src=pathlib.Path('box-out.txt'), dest=dest)
126
128
  )
127
- steps_with_caching.run(
129
+ await steps_with_caching.run(
128
130
  f'{sys.executable} executable.py',
129
131
  params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
130
132
  sandbox=sandbox,
@@ -133,26 +135,26 @@ def test_run_overwrite_changed_file_with_storage_value(
133
135
  )
134
136
  return artifacts
135
137
 
136
- artifacts = configure_and_run_with_dest(pathlib.Path('out.txt'))
138
+ artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
137
139
  assert (cleandir / 'out.txt').read_text().strip() == '5'
138
140
  assert artifacts.logs is not None
139
141
  assert not artifacts.logs.cached
140
142
 
141
143
  pathlib.Path('out.txt').write_text('42')
142
144
 
143
- another_artifacts = configure_and_run_with_dest(pathlib.Path('out.txt'))
145
+ another_artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
144
146
  assert (cleandir / 'out.txt').read_text().strip() == '5'
145
147
  assert another_artifacts.logs is not None
146
148
  assert another_artifacts.logs.cached
147
149
 
148
150
 
149
- def test_run_recreates_deleted_file_with_storage_value(
151
+ async def test_run_recreates_deleted_file_with_storage_value(
150
152
  cleandir: pathlib.Path,
151
153
  dependency_cache: DependencyCache,
152
154
  sandbox: SandboxBase,
153
155
  file_cacher: FileCacher,
154
156
  ):
155
- def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
157
+ async def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
156
158
  executable = DigestOrSource.create(file_cacher.put_file_text('print(5)'))
157
159
  artifacts = GradingArtifacts()
158
160
  artifacts.inputs.append(
@@ -161,7 +163,7 @@ def test_run_recreates_deleted_file_with_storage_value(
161
163
  artifacts.outputs.append(
162
164
  GradingFileOutput(src=pathlib.Path('box-out.txt'), dest=dest)
163
165
  )
164
- steps_with_caching.run(
166
+ await steps_with_caching.run(
165
167
  f'{sys.executable} executable.py',
166
168
  params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
167
169
  sandbox=sandbox,
@@ -170,26 +172,26 @@ def test_run_recreates_deleted_file_with_storage_value(
170
172
  )
171
173
  return artifacts
172
174
 
173
- artifacts = configure_and_run_with_dest(pathlib.Path('out.txt'))
175
+ artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
174
176
  assert (cleandir / 'out.txt').read_text().strip() == '5'
175
177
  assert artifacts.logs is not None
176
178
  assert not artifacts.logs.cached
177
179
 
178
180
  pathlib.Path('out.txt').unlink()
179
181
 
180
- another_artifacts = configure_and_run_with_dest(pathlib.Path('out.txt'))
182
+ another_artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
181
183
  assert (cleandir / 'out.txt').read_text().strip() == '5'
182
184
  assert another_artifacts.logs is not None
183
185
  assert another_artifacts.logs.cached
184
186
 
185
187
 
186
- def test_run_overwrite_exec_bit_when_changed(
188
+ async def test_run_overwrite_exec_bit_when_changed(
187
189
  cleandir: pathlib.Path,
188
190
  dependency_cache: DependencyCache,
189
191
  sandbox: SandboxBase,
190
192
  file_cacher: FileCacher,
191
193
  ):
192
- def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
194
+ async def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
193
195
  executable = DigestOrSource.create(file_cacher.put_file_text('print(5)'))
194
196
  artifacts = GradingArtifacts()
195
197
  artifacts.inputs.append(
@@ -203,7 +205,7 @@ def test_run_overwrite_exec_bit_when_changed(
203
205
  src=pathlib.Path('box-out.txt'), dest=dest, executable=True
204
206
  )
205
207
  )
206
- steps_with_caching.run(
208
+ await steps_with_caching.run(
207
209
  f'{sys.executable} executable.py',
208
210
  params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
209
211
  sandbox=sandbox,
@@ -212,7 +214,7 @@ def test_run_overwrite_exec_bit_when_changed(
212
214
  )
213
215
  return artifacts
214
216
 
215
- artifacts = configure_and_run_with_dest(pathlib.Path('out.txt'))
217
+ artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
216
218
  assert (cleandir / 'out.txt').read_text().strip() == '5'
217
219
  assert artifacts.logs is not None
218
220
  assert not artifacts.logs.cached
@@ -220,20 +222,20 @@ def test_run_overwrite_exec_bit_when_changed(
220
222
 
221
223
  pathlib.Path('out.txt').chmod(0o644)
222
224
 
223
- another_artifacts = configure_and_run_with_dest(pathlib.Path('out.txt'))
225
+ another_artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
224
226
  assert (cleandir / 'out.txt').read_text().strip() == '5'
225
227
  assert another_artifacts.logs is not None
226
228
  assert another_artifacts.logs.cached
227
229
  assert os.access('out.txt', os.X_OK)
228
230
 
229
231
 
230
- def test_run_evicts_when_changed_file_and_no_hash(
232
+ async def test_run_evicts_when_changed_file_and_no_hash(
231
233
  cleandir: pathlib.Path,
232
234
  dependency_cache: DependencyCache,
233
235
  sandbox: SandboxBase,
234
236
  file_cacher: FileCacher,
235
237
  ):
236
- def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
238
+ async def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
237
239
  executable = DigestOrSource.create(file_cacher.put_file_text('print(5)'))
238
240
  artifacts = GradingArtifacts()
239
241
  artifacts.inputs.append(
@@ -242,7 +244,7 @@ def test_run_evicts_when_changed_file_and_no_hash(
242
244
  artifacts.outputs.append(
243
245
  GradingFileOutput(src=pathlib.Path('box-out.txt'), dest=dest, hash=False)
244
246
  )
245
- steps_with_caching.run(
247
+ await steps_with_caching.run(
246
248
  f'{sys.executable} executable.py',
247
249
  params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
248
250
  sandbox=sandbox,
@@ -251,26 +253,26 @@ def test_run_evicts_when_changed_file_and_no_hash(
251
253
  )
252
254
  return artifacts
253
255
 
254
- artifacts = configure_and_run_with_dest(pathlib.Path('out.txt'))
256
+ artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
255
257
  assert (cleandir / 'out.txt').read_text().strip() == '5'
256
258
  assert artifacts.logs is not None
257
259
  assert not artifacts.logs.cached
258
260
 
259
261
  pathlib.Path('out.txt').write_text('42')
260
262
 
261
- another_artifacts = configure_and_run_with_dest(pathlib.Path('out.txt'))
263
+ another_artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
262
264
  assert (cleandir / 'out.txt').read_text().strip() == '5'
263
265
  assert another_artifacts.logs is not None
264
266
  assert not another_artifacts.logs.cached
265
267
 
266
268
 
267
- def test_run_evicts_when_exec_bit_different_and_no_hash(
269
+ async def test_run_evicts_when_exec_bit_different_and_no_hash(
268
270
  cleandir: pathlib.Path,
269
271
  dependency_cache: DependencyCache,
270
272
  sandbox: SandboxBase,
271
273
  file_cacher: FileCacher,
272
274
  ):
273
- def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
275
+ async def configure_and_run_with_dest(dest: pathlib.Path) -> GradingArtifacts:
274
276
  executable = DigestOrSource.create(file_cacher.put_file_text('print(5)'))
275
277
  artifacts = GradingArtifacts()
276
278
  artifacts.inputs.append(
@@ -281,7 +283,7 @@ def test_run_evicts_when_exec_bit_different_and_no_hash(
281
283
  src=pathlib.Path('box-out.txt'), dest=dest, hash=False, executable=True
282
284
  )
283
285
  )
284
- steps_with_caching.run(
286
+ await steps_with_caching.run(
285
287
  f'{sys.executable} executable.py',
286
288
  params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
287
289
  sandbox=sandbox,
@@ -290,25 +292,25 @@ def test_run_evicts_when_exec_bit_different_and_no_hash(
290
292
  )
291
293
  return artifacts
292
294
 
293
- artifacts = configure_and_run_with_dest(pathlib.Path('out.txt'))
295
+ artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
294
296
  assert (cleandir / 'out.txt').read_text().strip() == '5'
295
297
  assert artifacts.logs is not None
296
298
  assert not artifacts.logs.cached
297
299
 
298
300
  pathlib.Path('out.txt').chmod(0o0644)
299
301
 
300
- another_artifacts = configure_and_run_with_dest(pathlib.Path('out.txt'))
302
+ another_artifacts = await configure_and_run_with_dest(pathlib.Path('out.txt'))
301
303
  assert (cleandir / 'out.txt').read_text().strip() == '5'
302
304
  assert another_artifacts.logs is not None
303
305
  assert not another_artifacts.logs.cached
304
306
 
305
307
 
306
- def test_run_evicts_when_input_fingerprint_changes(
308
+ async def test_run_evicts_when_input_fingerprint_changes(
307
309
  cleandir: pathlib.Path,
308
310
  dependency_cache: DependencyCache,
309
311
  sandbox: SandboxBase,
310
312
  ):
311
- def configure_and_run() -> GradingArtifacts:
313
+ async def configure_and_run() -> GradingArtifacts:
312
314
  executable = DigestOrSource.create(pathlib.Path('executable.py'))
313
315
  artifacts = GradingArtifacts()
314
316
  artifacts.inputs.append(
@@ -320,7 +322,7 @@ def test_run_evicts_when_input_fingerprint_changes(
320
322
  dest=pathlib.Path('out.txt'),
321
323
  )
322
324
  )
323
- steps_with_caching.run(
325
+ await steps_with_caching.run(
324
326
  f'{sys.executable} executable.py',
325
327
  params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
326
328
  sandbox=sandbox,
@@ -331,25 +333,25 @@ def test_run_evicts_when_input_fingerprint_changes(
331
333
 
332
334
  pathlib.Path('executable.py').write_text('print(5)')
333
335
 
334
- artifacts = configure_and_run()
336
+ artifacts = await configure_and_run()
335
337
  assert (cleandir / 'out.txt').read_text().strip() == '5'
336
338
  assert artifacts.logs is not None
337
339
  assert not artifacts.logs.cached
338
340
 
339
341
  pathlib.Path('executable.py').write_text('print(42)')
340
342
 
341
- another_artifacts = configure_and_run()
343
+ another_artifacts = await configure_and_run()
342
344
  assert (cleandir / 'out.txt').read_text().strip() == '42'
343
345
  assert another_artifacts.logs is not None
344
346
  assert not another_artifacts.logs.cached
345
347
 
346
348
 
347
- def test_run_evicts_when_output_is_deleted_and_no_hash(
349
+ async def test_run_evicts_when_output_is_deleted_and_no_hash(
348
350
  cleandir: pathlib.Path,
349
351
  dependency_cache: DependencyCache,
350
352
  sandbox: SandboxBase,
351
353
  ):
352
- def configure_and_run() -> GradingArtifacts:
354
+ async def configure_and_run() -> GradingArtifacts:
353
355
  executable = DigestOrSource.create(pathlib.Path('executable.py'))
354
356
  artifacts = GradingArtifacts()
355
357
  artifacts.inputs.append(
@@ -362,7 +364,7 @@ def test_run_evicts_when_output_is_deleted_and_no_hash(
362
364
  hash=False,
363
365
  )
364
366
  )
365
- steps_with_caching.run(
367
+ await steps_with_caching.run(
366
368
  f'{sys.executable} executable.py',
367
369
  params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
368
370
  sandbox=sandbox,
@@ -373,26 +375,26 @@ def test_run_evicts_when_output_is_deleted_and_no_hash(
373
375
 
374
376
  pathlib.Path('executable.py').write_text('print(5)')
375
377
 
376
- artifacts = configure_and_run()
378
+ artifacts = await configure_and_run()
377
379
  assert (cleandir / 'out.txt').read_text().strip() == '5'
378
380
  assert artifacts.logs is not None
379
381
  assert not artifacts.logs.cached
380
382
 
381
383
  pathlib.Path('out.txt').unlink()
382
384
 
383
- another_artifacts = configure_and_run()
385
+ another_artifacts = await configure_and_run()
384
386
  assert (cleandir / 'out.txt').read_text().strip() == '5'
385
387
  assert another_artifacts.logs is not None
386
388
  assert not another_artifacts.logs.cached
387
389
 
388
390
 
389
- def test_run_misses_when_input_file_changes(
391
+ async def test_run_misses_when_input_file_changes(
390
392
  cleandir: pathlib.Path,
391
393
  dependency_cache: DependencyCache,
392
394
  sandbox: SandboxBase,
393
395
  file_cacher: FileCacher,
394
396
  ):
395
- def configure_and_run(number: int) -> GradingArtifacts:
397
+ async def configure_and_run(number: int) -> GradingArtifacts:
396
398
  executable = DigestOrSource.create(
397
399
  file_cacher.put_file_text(f'print({number})')
398
400
  )
@@ -407,7 +409,7 @@ def test_run_misses_when_input_file_changes(
407
409
  hash=False,
408
410
  )
409
411
  )
410
- steps_with_caching.run(
412
+ await steps_with_caching.run(
411
413
  f'{sys.executable} executable.py',
412
414
  params=SandboxParams(stdout_file=pathlib.Path('box-out.txt')),
413
415
  sandbox=sandbox,
@@ -416,14 +418,14 @@ def test_run_misses_when_input_file_changes(
416
418
  )
417
419
  return artifacts
418
420
 
419
- artifacts = configure_and_run(5)
421
+ artifacts = await configure_and_run(5)
420
422
  assert (cleandir / 'out.txt').read_text().strip() == '5'
421
423
  assert artifacts.logs is not None
422
424
  assert not artifacts.logs.cached
423
425
 
424
426
  pathlib.Path('out.txt').write_text('42')
425
427
 
426
- another_artifacts = configure_and_run(42)
428
+ another_artifacts = await configure_and_run(42)
427
429
  assert (cleandir / 'out.txt').read_text().strip() == '42'
428
430
  assert another_artifacts.logs is not None
429
431
  assert not another_artifacts.logs.cached
rbx/main.py CHANGED
@@ -1,8 +1,4 @@
1
1
  # flake8: noqa
2
- from gevent import monkey
3
-
4
- monkey.patch_all()
5
-
6
2
  import typer
7
3
  from typing_extensions import Annotated
8
4
 
@@ -37,12 +37,28 @@ if [ ! -r "$CHECKERSOURCE" ]; then
37
37
  exit 47
38
38
  fi
39
39
 
40
+ WORKDIR=$(dirname "$1")
40
41
  CHECKERHASH={{checkerHash}}
41
- CHECKERPATH=/tmp/boca-chk/$CHECKERHASH
42
+ CHECKERPATH=$WORKDIR/$CHECKERHASH
42
43
 
43
- compile_checker() {
44
- mkdir -p /tmp/boca-chk
44
+ lock() {
45
+ MAX_ATTEMPTS=100
46
+ ATTEMPTS=0
47
+ while ! ln -s $CHECKERSOURCE $CHECKERPATH.lock; do
48
+ sleep 1
49
+ ATTEMPTS=$((ATTEMPTS + 1))
50
+ if [ $ATTEMPTS -ge $MAX_ATTEMPTS ]; then
51
+ echo "Failed to retrieve checker lock"
52
+ exit 47
53
+ fi
54
+ done
55
+ }
56
+
57
+ unlock() {
58
+ rm -rf $CHECKERPATH.lock
59
+ }
45
60
 
61
+ compile_checker() {
46
62
  cc=$(which g++)
47
63
  [ -x "$cc" ] || cc=/usr/bin/g++
48
64
  if [ ! -x "$cc" ]; then
@@ -50,9 +66,12 @@ compile_checker() {
50
66
  exit 47
51
67
  fi
52
68
 
53
- $cc {{rbxFlags}} $CHECKERSOURCE -o $CHECKERPATH
54
-
55
- chmod 0755 "$CHECKERPATH"
69
+ lock
70
+ if [ ! -x "$CHECKERPATH" ]; then
71
+ $cc {{rbxFlags}} $CHECKERSOURCE -o $CHECKERPATH
72
+ chmod 0755 "$CHECKERPATH"
73
+ fi
74
+ unlock
56
75
  }
57
76
 
58
77
  if [ ! -x "$CHECKERPATH" ]; then
rbx/test.py CHANGED
@@ -3,6 +3,7 @@ import pathlib
3
3
  import tempfile
4
4
  from typing import Dict, List, Optional
5
5
 
6
+ import syncer
6
7
  from rich.columns import Columns
7
8
  from rich.panel import Panel
8
9
  from rich.progress import MofNCompleteColumn, Progress, SpinnerColumn
@@ -46,7 +47,7 @@ def get_testcases_io(
46
47
  return sorted(testcases_per_index.values(), key=lambda x: x.index)
47
48
 
48
49
 
49
- def _run_testcases(
50
+ async def _run_testcases(
50
51
  problem: Problem,
51
52
  lang: Language,
52
53
  lang_name: Optional[str],
@@ -73,7 +74,7 @@ def _run_testcases(
73
74
  artifacts = grading_utils.build_run_grading_artifacts(
74
75
  testcase, persist_root
75
76
  )
76
- run_log = steps.run(
77
+ run_log = await steps.run(
77
78
  lang.exec,
78
79
  params,
79
80
  sandbox,
@@ -234,7 +235,8 @@ def pretty_print_evaluation_results(
234
235
  _pretty_print_evaluation_result(problem, eval, interactive=interactive)
235
236
 
236
237
 
237
- def main(
238
+ @syncer.sync
239
+ async def main(
238
240
  problem: annotations.Problem,
239
241
  language: annotations.LanguageWithDefault = None,
240
242
  keep_sandbox: bool = False,
@@ -322,7 +324,7 @@ def main(
322
324
  )
323
325
  return
324
326
 
325
- testcase_logs = _run_testcases(
327
+ testcase_logs = await _run_testcases(
326
328
  dumped_problem, lang, language, box, testcases, persist_root
327
329
  )
328
330
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rbx.cp
3
- Version: 0.5.40
3
+ Version: 0.5.45
4
4
  Summary:
5
5
  Author: Roberto Sales
6
6
  Requires-Python: >=3.9,<4.0
@@ -13,7 +13,6 @@ Classifier: Programming Language :: Python :: 3.13
13
13
  Requires-Dist: chardet (>=5.2.0,<6.0.0)
14
14
  Requires-Dist: fastapi (>=0.115.8,<0.116.0)
15
15
  Requires-Dist: filelock (>=3.14.0,<4.0.0)
16
- Requires-Dist: gevent (>=24.2.1,<25.0.0)
17
16
  Requires-Dist: gitpython (>=3.1.43,<4.0.0)
18
17
  Requires-Dist: jinja2 (>=3.1.4,<4.0.0)
19
18
  Requires-Dist: lark (>=1.2.2,<2.0.0)
@@ -29,6 +28,7 @@ Requires-Dist: questionary (>=2.1.0,<3.0.0)
29
28
  Requires-Dist: requests (>=2.32.3,<3.0.0)
30
29
  Requires-Dist: rich (>=13.9.4,<14.0.0)
31
30
  Requires-Dist: ruyaml (>=0.91.0,<0.92.0)
31
+ Requires-Dist: syncer (>=2.0.3,<3.0.0)
32
32
  Requires-Dist: textual (>=0.79.1,<0.80.0)
33
33
  Requires-Dist: typer (>=0.15.1,<0.16.0)
34
34
  Description-Content-Type: text/markdown