rbx.cp 0.13.4__py3-none-any.whl → 0.13.6__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 (42) hide show
  1. rbx/box/checkers.py +2 -9
  2. rbx/box/cli.py +0 -1
  3. rbx/box/code.py +27 -80
  4. rbx/box/environment.py +16 -6
  5. rbx/box/generators.py +26 -3
  6. rbx/box/global_package.py +1 -1
  7. rbx/box/header.py +26 -8
  8. rbx/box/package.py +0 -14
  9. rbx/box/setter_config.py +11 -0
  10. rbx/box/solutions.py +12 -4
  11. rbx/box/tasks.py +9 -4
  12. rbx/box/testing/testing_package.py +69 -2
  13. rbx/box/ui/screens/run_explorer.py +0 -8
  14. rbx/box/ui/utils/run_ui.py +7 -3
  15. rbx/box/ui/widgets/test_output_box.py +1 -1
  16. rbx/box/unit.py +4 -4
  17. rbx/box/validators.py +3 -1
  18. rbx/grading/caching.py +65 -15
  19. rbx/grading/judge/cacher.py +5 -3
  20. rbx/grading/judge/program.py +300 -0
  21. rbx/grading/judge/sandbox.py +30 -200
  22. rbx/grading/judge/sandboxes/stupid_sandbox.py +234 -240
  23. rbx/grading/judge/sandboxes/tee.py +31 -0
  24. rbx/grading/judge/storage.py +7 -1
  25. rbx/grading/steps.py +89 -201
  26. rbx/grading/steps_with_caching.py +15 -6
  27. rbx/resources/presets/default/problem/problem.rbx.yml +0 -2
  28. rbx/resources/templates/rbx.h +43 -2
  29. rbx/testing_utils.py +7 -0
  30. rbx/utils.py +104 -6
  31. {rbx_cp-0.13.4.dist-info → rbx_cp-0.13.6.dist-info}/METADATA +1 -1
  32. {rbx_cp-0.13.4.dist-info → rbx_cp-0.13.6.dist-info}/RECORD +35 -40
  33. rbx/grading/judge/sandboxes/isolate.py +0 -695
  34. rbx/grading/judge/sandboxes/timeit.py +0 -358
  35. rbx/grading/judge/test.py +0 -38
  36. rbx/grading/judge/testiso.py +0 -54
  37. rbx/grading/processing_context.py +0 -71
  38. rbx/resources/envs/isolate.rbx.yml +0 -36
  39. rbx/resources/presets/default/problem/sols/slow.cpp +0 -15
  40. {rbx_cp-0.13.4.dist-info → rbx_cp-0.13.6.dist-info}/LICENSE +0 -0
  41. {rbx_cp-0.13.4.dist-info → rbx_cp-0.13.6.dist-info}/WHEEL +0 -0
  42. {rbx_cp-0.13.4.dist-info → rbx_cp-0.13.6.dist-info}/entry_points.txt +0 -0
@@ -1,18 +1,17 @@
1
1
  import abc
2
2
  import asyncio
3
- import collections
4
3
  import dataclasses
5
4
  import io
5
+ import json
6
6
  import logging
7
7
  import os
8
8
  import pathlib
9
9
  import select
10
- import signal
11
10
  import stat
12
11
  import subprocess
13
12
  import sys
14
13
  import typing
15
- from typing import IO, Any, Dict, List, Optional
14
+ from typing import IO, Any, Dict, List, Optional, Tuple
16
15
 
17
16
  import pydantic
18
17
 
@@ -146,12 +145,6 @@ class SandboxParams(pydantic.BaseModel):
146
145
  reverse_io: bool = False
147
146
  pgid: Optional[int] = None
148
147
 
149
- # For timeit
150
- timeit_dups: Dict[str, List[pathlib.Path]] = dataclasses.field(
151
- default_factory=lambda: collections.defaultdict(list)
152
- )
153
- timeit_prefix: Optional[str] = None
154
-
155
148
  def get_cacheable_params(self) -> Dict[str, Any]:
156
149
  return self.model_dump(mode='json', exclude_unset=True, exclude_none=True)
157
150
 
@@ -210,6 +203,22 @@ class SandboxParams(pydantic.BaseModel):
210
203
  self.dirs.append(DirectoryMount(src, dest, options))
211
204
 
212
205
 
206
+ class SandboxLog(pydantic.BaseModel):
207
+ """A log of the sandbox."""
208
+
209
+ params: SandboxParams
210
+ execution_time: float # seconds
211
+ memory_used: int # bytes
212
+ exitcode: int
213
+ exitstatus: str
214
+ killing_signal: Optional[int] = None
215
+ exit_index: int = 0
216
+ other_logs: Dict[str, Any] = pydantic.Field(default_factory=dict)
217
+
218
+ def dump_other_logs(self) -> str:
219
+ return json.dumps(self.other_logs)
220
+
221
+
213
222
  class SandboxBase(abc.ABC):
214
223
  """A base class for all sandboxes, meant to contain common
215
224
  resources.
@@ -229,16 +238,12 @@ class SandboxBase(abc.ABC):
229
238
  file_cacher: cacher.FileCacher
230
239
  name: str
231
240
  temp_dir: Optional[pathlib.Path]
232
- cmd_file: pathlib.Path
233
-
234
- params: SandboxParams
235
241
 
236
242
  def __init__(
237
243
  self,
238
244
  file_cacher: Optional[cacher.FileCacher] = None,
239
245
  name: Optional[str] = None,
240
246
  temp_dir: Optional[pathlib.Path] = None,
241
- params: Optional[SandboxParams] = None,
242
247
  ):
243
248
  """Initialization.
244
249
 
@@ -253,56 +258,7 @@ class SandboxBase(abc.ABC):
253
258
  self.file_cacher = file_cacher or cacher.FileCacher(storage.NullStorage())
254
259
  self.name = name if name is not None else 'unnamed'
255
260
  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}]'
261
+ self.cmd_file = pathlib.PosixPath('__commands__.log')
306
262
 
307
263
  @abc.abstractmethod
308
264
  def get_root_path(self) -> pathlib.Path:
@@ -313,101 +269,6 @@ class SandboxBase(abc.ABC):
313
269
  """
314
270
  pass
315
271
 
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
272
  def use_soft_timeout(self) -> bool:
412
273
  return False
413
274
 
@@ -702,52 +563,24 @@ class SandboxBase(abc.ABC):
702
563
  ]
703
564
 
704
565
  @abc.abstractmethod
705
- def execute_without_std(
566
+ def run(
706
567
  self,
707
568
  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
- """
569
+ params: SandboxParams,
570
+ ) -> SandboxLog:
726
571
  pass
727
572
 
728
573
  @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
- """
574
+ def run_communication(
575
+ self,
576
+ command: List[str],
577
+ params: SandboxParams,
578
+ interactor_command: List[str],
579
+ interactor_params: SandboxParams,
580
+ merged_capture: Optional[pathlib.Path] = None,
581
+ ) -> Tuple[SandboxLog, SandboxLog]:
735
582
  pass
736
583
 
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
584
  @abc.abstractmethod
752
585
  def initialize(self):
753
586
  """Initialize the sandbox.
@@ -779,9 +612,6 @@ class SandboxBase(abc.ABC):
779
612
  """
780
613
  pass
781
614
 
782
- def debug_message(self) -> Any:
783
- return 'N/A'
784
-
785
615
 
786
616
  class Truncator(io.RawIOBase):
787
617
  """Wrap a file-like object to simulate truncation.