rbx.cp 0.13.3__py3-none-any.whl → 0.13.5__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 (73) hide show
  1. rbx/annotations.py +5 -5
  2. rbx/box/checkers.py +26 -22
  3. rbx/box/cli.py +0 -4
  4. rbx/box/code.py +27 -80
  5. rbx/box/contest/build_contest_statements.py +16 -3
  6. rbx/box/contest/schema.py +1 -2
  7. rbx/box/environment.py +16 -6
  8. rbx/box/fields.py +25 -1
  9. rbx/box/generators.py +31 -5
  10. rbx/box/global_package.py +6 -2
  11. rbx/box/header.py +31 -11
  12. rbx/box/package.py +3 -15
  13. rbx/box/presets/__init__.py +2 -2
  14. rbx/box/schema.py +4 -25
  15. rbx/box/setter_config.py +11 -0
  16. rbx/box/solutions.py +12 -4
  17. rbx/box/statements/build_statements.py +5 -1
  18. rbx/box/statements/builders.py +7 -7
  19. rbx/box/statements/schema.py +11 -2
  20. rbx/box/tasks.py +9 -4
  21. rbx/box/testcase_utils.py +2 -0
  22. rbx/box/testing/__init__.py +0 -0
  23. rbx/box/testing/testing_package.py +246 -0
  24. rbx/box/testing/testing_preset.py +36 -0
  25. rbx/box/testing/testing_shared.py +81 -0
  26. rbx/box/ui/screens/run_explorer.py +0 -8
  27. rbx/box/ui/utils/run_ui.py +7 -3
  28. rbx/box/ui/widgets/test_output_box.py +1 -1
  29. rbx/box/validators.py +5 -2
  30. rbx/grading/caching.py +67 -16
  31. rbx/grading/judge/program.py +268 -0
  32. rbx/grading/judge/sandbox.py +30 -193
  33. rbx/grading/judge/sandboxes/stupid_sandbox.py +232 -241
  34. rbx/grading/judge/sandboxes/tee.py +31 -0
  35. rbx/grading/steps.py +87 -199
  36. rbx/grading/steps_with_caching.py +15 -6
  37. rbx/resources/presets/default/problem/problem.rbx.yml +0 -2
  38. rbx/resources/presets/default/shared/contest_template.rbx.tex +1 -1
  39. rbx/resources/presets/default/shared/problem_template.rbx.tex +5 -1
  40. rbx/resources/templates/rbx.h +43 -2
  41. rbx/testing_utils.py +8 -1
  42. rbx/utils.py +59 -1
  43. {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.5.dist-info}/METADATA +2 -1
  44. {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.5.dist-info}/RECORD +47 -67
  45. rbx/box/conftest.py +0 -42
  46. rbx/box/generators_test.py +0 -67
  47. rbx/box/lazy_importing_test.py +0 -25
  48. rbx/box/solutions_test.py +0 -47
  49. rbx/box/validators_test.py +0 -15
  50. rbx/checker.py +0 -128
  51. rbx/clone.py +0 -197
  52. rbx/conftest.py +0 -38
  53. rbx/create.py +0 -37
  54. rbx/edit.py +0 -24
  55. rbx/grading/conftest.py +0 -33
  56. rbx/grading/judge/sandboxes/isolate.py +0 -695
  57. rbx/grading/judge/testiso.py +0 -54
  58. rbx/grading/steps_with_caching_run_test.py +0 -707
  59. rbx/grading_utils.py +0 -148
  60. rbx/hydration.py +0 -101
  61. rbx/main.py +0 -118
  62. rbx/metadata.py +0 -105
  63. rbx/resources/envs/isolate.rbx.yml +0 -36
  64. rbx/resources/presets/default/problem/sols/slow.cpp +0 -15
  65. rbx/run.py +0 -45
  66. rbx/schema.py +0 -64
  67. rbx/submit.py +0 -61
  68. rbx/test.py +0 -349
  69. rbx/testcase.py +0 -70
  70. rbx/testcase_rendering.py +0 -79
  71. {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.5.dist-info}/LICENSE +0 -0
  72. {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.5.dist-info}/WHEEL +0 -0
  73. {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.5.dist-info}/entry_points.txt +0 -0
@@ -3,16 +3,16 @@ import asyncio
3
3
  import collections
4
4
  import dataclasses
5
5
  import io
6
+ import json
6
7
  import logging
7
8
  import os
8
9
  import pathlib
9
10
  import select
10
- import signal
11
11
  import stat
12
12
  import subprocess
13
13
  import sys
14
14
  import typing
15
- from typing import IO, Any, Dict, List, Optional
15
+ from typing import IO, Any, Dict, List, Optional, Tuple
16
16
 
17
17
  import pydantic
18
18
 
@@ -210,6 +210,22 @@ class SandboxParams(pydantic.BaseModel):
210
210
  self.dirs.append(DirectoryMount(src, dest, options))
211
211
 
212
212
 
213
+ class SandboxLog(pydantic.BaseModel):
214
+ """A log of the sandbox."""
215
+
216
+ params: SandboxParams
217
+ execution_time: float # seconds
218
+ memory_used: int # bytes
219
+ exitcode: int
220
+ exitstatus: str
221
+ killing_signal: Optional[int] = None
222
+ exit_index: int = 0
223
+ other_logs: Dict[str, Any] = pydantic.Field(default_factory=dict)
224
+
225
+ def dump_other_logs(self) -> str:
226
+ return json.dumps(self.other_logs)
227
+
228
+
213
229
  class SandboxBase(abc.ABC):
214
230
  """A base class for all sandboxes, meant to contain common
215
231
  resources.
@@ -229,16 +245,12 @@ class SandboxBase(abc.ABC):
229
245
  file_cacher: cacher.FileCacher
230
246
  name: str
231
247
  temp_dir: Optional[pathlib.Path]
232
- cmd_file: pathlib.Path
233
-
234
- params: SandboxParams
235
248
 
236
249
  def __init__(
237
250
  self,
238
251
  file_cacher: Optional[cacher.FileCacher] = None,
239
252
  name: Optional[str] = None,
240
253
  temp_dir: Optional[pathlib.Path] = None,
241
- params: Optional[SandboxParams] = None,
242
254
  ):
243
255
  """Initialization.
244
256
 
@@ -253,56 +265,7 @@ class SandboxBase(abc.ABC):
253
265
  self.file_cacher = file_cacher or cacher.FileCacher(storage.NullStorage())
254
266
  self.name = name if name is not None else 'unnamed'
255
267
  self.temp_dir = temp_dir
256
-
257
- self.cmd_file = pathlib.PosixPath('commands.log')
258
-
259
- self.params = params or SandboxParams()
260
- self.pid = None
261
- self.pid_event = Event_ts()
262
-
263
- # Set common environment variables.
264
- # Specifically needed by Python, that searches the home for
265
- # packages.
266
- self.params.set_env['HOME'] = './'
267
-
268
- def set_params(self, params: SandboxParams):
269
- """Set the parameters of the sandbox.
270
-
271
- params (SandboxParams): the parameters to set.
272
-
273
- """
274
- self.params = params
275
-
276
- def set_multiprocess(self, multiprocess: bool):
277
- """Set the sandbox to (dis-)allow multiple threads and processes.
278
-
279
- multiprocess (bool): whether to allow multiple thread/processes or not.
280
-
281
- """
282
- if multiprocess:
283
- # Max processes is set to 1000 to limit the effect of fork bombs.
284
- self.params.max_processes = 1000
285
- else:
286
- self.params.max_processes = 1
287
-
288
- def get_stats(self) -> str:
289
- """Return a human-readable string representing execution time
290
- and memory usage.
291
-
292
- return (string): human-readable stats.
293
-
294
- """
295
- execution_time = self.get_execution_time()
296
- if execution_time is not None:
297
- time_str = f'{execution_time:.3f} sec'
298
- else:
299
- time_str = '(time unknown)'
300
- memory_used = self.get_memory_used()
301
- if memory_used is not None:
302
- mem_str = f'{memory_used / (1024 * 1024):.2f} MB'
303
- else:
304
- mem_str = '(memory usage unknown)'
305
- return f'[{time_str} - {mem_str}]'
268
+ self.cmd_file = pathlib.PosixPath('__commands__.log')
306
269
 
307
270
  @abc.abstractmethod
308
271
  def get_root_path(self) -> pathlib.Path:
@@ -313,101 +276,6 @@ class SandboxBase(abc.ABC):
313
276
  """
314
277
  pass
315
278
 
316
- @abc.abstractmethod
317
- def get_execution_time(self) -> Optional[float]:
318
- """Return the time spent in the sandbox.
319
-
320
- return (float): time spent in the sandbox.
321
-
322
- """
323
- pass
324
-
325
- @abc.abstractmethod
326
- def get_memory_used(self) -> Optional[int]:
327
- """Return the memory used by the sandbox.
328
-
329
- return (int): memory used by the sandbox (in bytes).
330
-
331
- """
332
- pass
333
-
334
- @abc.abstractmethod
335
- def get_killing_signal(self) -> int:
336
- """Return the signal that killed the sandboxed process.
337
-
338
- return (int): offending signal, or 0.
339
-
340
- """
341
- pass
342
-
343
- @abc.abstractmethod
344
- def get_exit_status(self) -> str:
345
- """Get information about how the sandbox terminated.
346
-
347
- return (string): the main reason why the sandbox terminated.
348
-
349
- """
350
- pass
351
-
352
- @abc.abstractmethod
353
- def get_exit_code(self) -> int:
354
- """Return the exit code of the sandboxed process.
355
-
356
- return (int): exitcode, or 0.
357
-
358
- """
359
- pass
360
-
361
- def set_pid(self, pid: int):
362
- """Set the PID of the sandboxed process.
363
-
364
- pid (int): the PID of the sandboxed process.
365
-
366
- """
367
- self.pid = pid
368
- self.pid_event.set()
369
-
370
- async def get_pid(self) -> int:
371
- """Return the PID of the sandboxed process.
372
-
373
- Blocks until the PID is set.
374
-
375
- return (int): the PID of the sandboxed process.
376
-
377
- """
378
- await self.pid_event.wait()
379
- assert self.pid is not None
380
- return self.pid
381
-
382
- def clear_pid(self):
383
- """Clear the PID of the sandboxed process."""
384
- self.pid_event.clear()
385
- self.pid = None
386
-
387
- def use_pgid(self) -> bool:
388
- """Whether the sandbox supports process groups."""
389
- return False
390
-
391
- @abc.abstractmethod
392
- def get_detailed_logs(self) -> str:
393
- """Return the detailed logs of the sandbox.
394
-
395
- return (string): the detailed logs of the sandbox.
396
-
397
- """
398
- pass
399
-
400
- @abc.abstractmethod
401
- def get_human_exit_description(self) -> str:
402
- """Get the status of the sandbox and return a human-readable
403
- string describing it.
404
-
405
- return (string): human-readable explaination of why the
406
- sandbox terminated.
407
-
408
- """
409
- pass
410
-
411
279
  def use_soft_timeout(self) -> bool:
412
280
  return False
413
281
 
@@ -702,52 +570,24 @@ class SandboxBase(abc.ABC):
702
570
  ]
703
571
 
704
572
  @abc.abstractmethod
705
- def execute_without_std(
573
+ def run(
706
574
  self,
707
575
  command: List[str],
708
- ) -> bool:
709
- """Execute the given command in the sandbox using
710
- subprocess.Popen and discarding standard input, output and
711
- error. More specifically, the standard input gets closed just
712
- after the execution has started; standard output and error are
713
- read until the end, in a way that prevents the execution from
714
- being blocked because of insufficient buffering.
715
-
716
- command ([string]): executable filename and arguments of the
717
- command.
718
- wait (bool): True if this call is blocking, False otherwise
719
-
720
- return (bool|Popen): if the call is blocking, then return True
721
- if the sandbox didn't report errors (caused by the sandbox
722
- itself), False otherwise; if the call is not blocking,
723
- return the Popen object from subprocess.
724
-
725
- """
576
+ params: SandboxParams,
577
+ ) -> SandboxLog:
726
578
  pass
727
579
 
728
580
  @abc.abstractmethod
729
- def hydrate_logs(self):
730
- """Fetch the results of the execution and hydrate logs.
731
-
732
- This method should be called after the execution has
733
- terminated, to hydrate logs and stuff.
734
- """
581
+ def run_communication(
582
+ self,
583
+ command: List[str],
584
+ params: SandboxParams,
585
+ interactor_command: List[str],
586
+ interactor_params: SandboxParams,
587
+ merged_capture: Optional[pathlib.Path] = None,
588
+ ) -> Tuple[SandboxLog, SandboxLog]:
735
589
  pass
736
590
 
737
- def translate_box_exitcode(self, exitcode: int) -> bool:
738
- """Translate the sandbox exit code to a boolean sandbox success.
739
-
740
- _ (int): the exit code of the sandbox.
741
-
742
- return (bool): False if the sandbox had an error, True if it
743
- terminated correctly (regardless of what the internal process
744
- did).
745
-
746
- """
747
- # SIGTERM can be safely ignored, just in case it leaks away from
748
- # the sandbox.
749
- return exitcode == 0 or exitcode == -signal.SIGTERM
750
-
751
591
  @abc.abstractmethod
752
592
  def initialize(self):
753
593
  """Initialize the sandbox.
@@ -779,9 +619,6 @@ class SandboxBase(abc.ABC):
779
619
  """
780
620
  pass
781
621
 
782
- def debug_message(self) -> Any:
783
- return 'N/A'
784
-
785
622
 
786
623
  class Truncator(io.RawIOBase):
787
624
  """Wrap a file-like object to simulate truncation.