rbx.cp 0.5.0__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/__init__.py +0 -0
- rbx/annotations.py +127 -0
- rbx/autoenum.py +333 -0
- rbx/box/__init__.py +0 -0
- rbx/box/builder.py +77 -0
- rbx/box/cd.py +37 -0
- rbx/box/checkers.py +134 -0
- rbx/box/code.py +185 -0
- rbx/box/compile.py +56 -0
- rbx/box/conftest.py +42 -0
- rbx/box/contest/__init__.py +0 -0
- rbx/box/contest/build_contest_statements.py +347 -0
- rbx/box/contest/contest_package.py +76 -0
- rbx/box/contest/contest_utils.py +20 -0
- rbx/box/contest/main.py +179 -0
- rbx/box/contest/schema.py +155 -0
- rbx/box/contest/statements.py +82 -0
- rbx/box/creation.py +72 -0
- rbx/box/download.py +64 -0
- rbx/box/environment.py +345 -0
- rbx/box/extensions.py +26 -0
- rbx/box/generators.py +478 -0
- rbx/box/generators_test.py +63 -0
- rbx/box/main.py +449 -0
- rbx/box/package.py +316 -0
- rbx/box/packaging/boca/extension.py +27 -0
- rbx/box/packaging/boca/packager.py +245 -0
- rbx/box/packaging/contest_main.py +82 -0
- rbx/box/packaging/main.py +68 -0
- rbx/box/packaging/packager.py +117 -0
- rbx/box/packaging/polygon/packager.py +320 -0
- rbx/box/packaging/polygon/test.py +81 -0
- rbx/box/packaging/polygon/xml_schema.py +106 -0
- rbx/box/presets/__init__.py +503 -0
- rbx/box/presets/fetch.py +70 -0
- rbx/box/presets/lock_schema.py +20 -0
- rbx/box/presets/schema.py +59 -0
- rbx/box/schema.py +394 -0
- rbx/box/solutions.py +792 -0
- rbx/box/solutions_test.py +41 -0
- rbx/box/statements/__init__.py +0 -0
- rbx/box/statements/build_statements.py +359 -0
- rbx/box/statements/builders.py +375 -0
- rbx/box/statements/joiners.py +113 -0
- rbx/box/statements/latex.py +47 -0
- rbx/box/statements/latex_jinja.py +214 -0
- rbx/box/statements/schema.py +138 -0
- rbx/box/stresses.py +292 -0
- rbx/box/stressing/__init__.py +0 -0
- rbx/box/stressing/finder_parser.py +359 -0
- rbx/box/stressing/generator_parser.py +258 -0
- rbx/box/testcases.py +54 -0
- rbx/box/ui/__init__.py +0 -0
- rbx/box/ui/captured_log.py +372 -0
- rbx/box/ui/css/app.tcss +48 -0
- rbx/box/ui/main.py +38 -0
- rbx/box/ui/run.py +209 -0
- rbx/box/validators.py +245 -0
- rbx/box/validators_test.py +15 -0
- rbx/checker.py +128 -0
- rbx/clone.py +197 -0
- rbx/config.py +271 -0
- rbx/conftest.py +38 -0
- rbx/console.py +27 -0
- rbx/create.py +37 -0
- rbx/edit.py +24 -0
- rbx/grading/__init__.py +0 -0
- rbx/grading/caching.py +356 -0
- rbx/grading/conftest.py +33 -0
- rbx/grading/judge/__init__.py +0 -0
- rbx/grading/judge/cacher.py +503 -0
- rbx/grading/judge/digester.py +35 -0
- rbx/grading/judge/sandbox.py +748 -0
- rbx/grading/judge/sandboxes/__init__.py +0 -0
- rbx/grading/judge/sandboxes/isolate.py +683 -0
- rbx/grading/judge/sandboxes/stupid_sandbox.py +310 -0
- rbx/grading/judge/sandboxes/timeit.py +217 -0
- rbx/grading/judge/storage.py +284 -0
- rbx/grading/judge/test.py +38 -0
- rbx/grading/judge/testiso.py +54 -0
- rbx/grading/steps.py +522 -0
- rbx/grading/steps_with_caching.py +59 -0
- rbx/grading/steps_with_caching_run_test.py +429 -0
- rbx/grading_utils.py +148 -0
- rbx/hydration.py +101 -0
- rbx/main.py +122 -0
- rbx/metadata.py +105 -0
- rbx/providers/__init__.py +43 -0
- rbx/providers/codeforces.py +73 -0
- rbx/providers/provider.py +26 -0
- rbx/resources/checkers/boilerplate.cpp +20 -0
- rbx/resources/default_config.json +48 -0
- rbx/resources/envs/default.rbx.yml +37 -0
- rbx/resources/envs/isolate.rbx.yml +37 -0
- rbx/resources/packagers/boca/checker.sh +43 -0
- rbx/resources/packagers/boca/compare +53 -0
- rbx/resources/packagers/boca/compile/c +172 -0
- rbx/resources/packagers/boca/compile/cc +173 -0
- rbx/resources/packagers/boca/compile/cpp +172 -0
- rbx/resources/packagers/boca/compile/java +194 -0
- rbx/resources/packagers/boca/compile/kt +155 -0
- rbx/resources/packagers/boca/compile/pas +172 -0
- rbx/resources/packagers/boca/compile/py2 +173 -0
- rbx/resources/packagers/boca/compile/py3 +173 -0
- rbx/resources/packagers/boca/run/c +128 -0
- rbx/resources/packagers/boca/run/cc +128 -0
- rbx/resources/packagers/boca/run/cpp +128 -0
- rbx/resources/packagers/boca/run/java +194 -0
- rbx/resources/packagers/boca/run/kt +159 -0
- rbx/resources/packagers/boca/run/py2 +166 -0
- rbx/resources/packagers/boca/run/py3 +166 -0
- rbx/resources/presets/default/contest/contest.rbx.yml +14 -0
- rbx/resources/presets/default/contest/statement/contest.rbx.tex +97 -0
- rbx/resources/presets/default/contest/statement/olymp.sty +250 -0
- rbx/resources/presets/default/contest/statement/template.rbx.tex +42 -0
- rbx/resources/presets/default/preset.rbx.yml +12 -0
- rbx/resources/presets/default/problem/.gitignore +6 -0
- rbx/resources/presets/default/problem/gen.cpp +9 -0
- rbx/resources/presets/default/problem/problem.rbx.yml +44 -0
- rbx/resources/presets/default/problem/random.py +3 -0
- rbx/resources/presets/default/problem/random.txt +2 -0
- rbx/resources/presets/default/problem/sols/main.cpp +9 -0
- rbx/resources/presets/default/problem/sols/slow.cpp +15 -0
- rbx/resources/presets/default/problem/sols/wa.cpp +9 -0
- rbx/resources/presets/default/problem/statement/olymp.sty +250 -0
- rbx/resources/presets/default/problem/statement/projecao.png +0 -0
- rbx/resources/presets/default/problem/statement/statement.rbx.tex +18 -0
- rbx/resources/presets/default/problem/statement/template.rbx.tex +89 -0
- rbx/resources/presets/default/problem/tests/samples/000.in +1 -0
- rbx/resources/presets/default/problem/tests/samples/001.in +1 -0
- rbx/resources/presets/default/problem/validator.cpp +16 -0
- rbx/resources/presets/default/problem/wcmp.cpp +34 -0
- rbx/resources/templates/template.cpp +19 -0
- rbx/run.py +45 -0
- rbx/schema.py +64 -0
- rbx/submit.py +61 -0
- rbx/submitors/__init__.py +18 -0
- rbx/submitors/codeforces.py +120 -0
- rbx/submitors/submitor.py +25 -0
- rbx/test.py +347 -0
- rbx/testcase.py +70 -0
- rbx/testcase_rendering.py +79 -0
- rbx/testdata/box1/gen1.cpp +7 -0
- rbx/testdata/box1/gen2.cpp +9 -0
- rbx/testdata/box1/genScript.py +2 -0
- rbx/testdata/box1/hard-tle.sol.cpp +26 -0
- rbx/testdata/box1/ole.cpp +17 -0
- rbx/testdata/box1/problem.rbx.yml +39 -0
- rbx/testdata/box1/re.sol.cpp +23 -0
- rbx/testdata/box1/sol.cpp +22 -0
- rbx/testdata/box1/tests/1.in +1 -0
- rbx/testdata/box1/tle-and-incorrect.sol.cpp +33 -0
- rbx/testdata/box1/tle.sol.cpp +35 -0
- rbx/testdata/box1/validator.cpp +11 -0
- rbx/testdata/box1/wa.sol.cpp +22 -0
- rbx/testdata/caching/executable.py +1 -0
- rbx/testdata/compatible +0 -0
- rbx/testing_utils.py +65 -0
- rbx/utils.py +162 -0
- rbx_cp-0.5.0.dist-info/LICENSE +201 -0
- rbx_cp-0.5.0.dist-info/METADATA +89 -0
- rbx_cp-0.5.0.dist-info/RECORD +164 -0
- rbx_cp-0.5.0.dist-info/WHEEL +4 -0
- rbx_cp-0.5.0.dist-info/entry_points.txt +4 -0
@@ -0,0 +1,284 @@
|
|
1
|
+
import dataclasses
|
2
|
+
import io
|
3
|
+
import logging
|
4
|
+
import pathlib
|
5
|
+
import tempfile
|
6
|
+
from abc import ABC, abstractmethod
|
7
|
+
from typing import IO, AnyStr, List, Optional
|
8
|
+
|
9
|
+
import gevent
|
10
|
+
|
11
|
+
logger = logging.getLogger(__name__)
|
12
|
+
|
13
|
+
TOMBSTONE = 'x'
|
14
|
+
|
15
|
+
|
16
|
+
def copyfileobj(
|
17
|
+
source_fobj: IO[AnyStr],
|
18
|
+
destination_fobj: IO[AnyStr],
|
19
|
+
buffer_size=io.DEFAULT_BUFFER_SIZE,
|
20
|
+
maxlen: Optional[int] = None,
|
21
|
+
):
|
22
|
+
"""Read all content from one file object and write it to another.
|
23
|
+
Repeatedly read from the given source file object, until no content
|
24
|
+
is left, and at the same time write the content to the destination
|
25
|
+
file object. Never read or write more than the given buffer size.
|
26
|
+
Be cooperative with other greenlets by yielding often.
|
27
|
+
source_fobj (fileobj): a file object open for reading, in either
|
28
|
+
binary or str mode (doesn't need to be buffered).
|
29
|
+
destination_fobj (fileobj): a file object open for writing, in the
|
30
|
+
same mode as the source (doesn't need to be buffered).
|
31
|
+
buffer_size (int): the size of the read/write buffer.
|
32
|
+
maxlen (int): the maximum number of bytes to copy. If None, copy all.
|
33
|
+
"""
|
34
|
+
if maxlen is None:
|
35
|
+
maxlen = -1
|
36
|
+
while maxlen:
|
37
|
+
buffer = source_fobj.read(buffer_size)
|
38
|
+
if len(buffer) == 0:
|
39
|
+
break
|
40
|
+
if maxlen > 0 and maxlen < len(buffer):
|
41
|
+
buffer = buffer[:maxlen]
|
42
|
+
while len(buffer) > 0:
|
43
|
+
gevent.sleep(0)
|
44
|
+
written = destination_fobj.write(buffer)
|
45
|
+
buffer = buffer[written:]
|
46
|
+
maxlen -= written
|
47
|
+
gevent.sleep(0)
|
48
|
+
|
49
|
+
|
50
|
+
@dataclasses.dataclass
|
51
|
+
class PendingFile:
|
52
|
+
fd: IO[bytes]
|
53
|
+
filename: str
|
54
|
+
|
55
|
+
|
56
|
+
@dataclasses.dataclass
|
57
|
+
class FileWithDescription:
|
58
|
+
filename: str
|
59
|
+
description: str
|
60
|
+
|
61
|
+
|
62
|
+
class Storage(ABC):
|
63
|
+
"""Abstract base class for all concrete storages."""
|
64
|
+
|
65
|
+
@abstractmethod
|
66
|
+
def get_file(self, filename: str) -> IO[bytes]:
|
67
|
+
"""Retrieve a file from the storage.
|
68
|
+
filename (unicode): the path of the file to retrieve.
|
69
|
+
return (fileobj): a readable binary file-like object from which
|
70
|
+
to read the contents of the file.
|
71
|
+
raise (KeyError): if the file cannot be found.
|
72
|
+
"""
|
73
|
+
pass
|
74
|
+
|
75
|
+
@abstractmethod
|
76
|
+
def create_file(self, filename: str) -> Optional[PendingFile]:
|
77
|
+
"""Create an empty file that will live in the storage.
|
78
|
+
Once the caller has written the contents to the file, the commit_file()
|
79
|
+
method must be called to commit it into the store.
|
80
|
+
filename (unicode): the filename of the file to store.
|
81
|
+
return (fileobj): a writable binary file-like object on which
|
82
|
+
to write the contents of the file, or None if the file is
|
83
|
+
already stored.
|
84
|
+
"""
|
85
|
+
pass
|
86
|
+
|
87
|
+
@abstractmethod
|
88
|
+
def commit_file(self, file: PendingFile, desc: str = '') -> bool:
|
89
|
+
"""Commit a file created by create_file() to be stored.
|
90
|
+
Given a file object returned by create_file(), this function populates
|
91
|
+
the database to record that this file now legitimately exists and can
|
92
|
+
be used.
|
93
|
+
fobj (fileobj): the object returned by create_file()
|
94
|
+
file (PendingFile): the file to commit.
|
95
|
+
return (bool): True if the file was committed successfully, False if
|
96
|
+
there was already a file with the same filename in the database. This
|
97
|
+
shouldn't make any difference to the caller, except for testing
|
98
|
+
purposes!
|
99
|
+
"""
|
100
|
+
pass
|
101
|
+
|
102
|
+
@abstractmethod
|
103
|
+
def exists(self, filename: str) -> bool:
|
104
|
+
"""Check if a file exists in the storage."""
|
105
|
+
pass
|
106
|
+
|
107
|
+
@abstractmethod
|
108
|
+
def describe(self, filename: str) -> str:
|
109
|
+
"""Return the description of a file given its filename.
|
110
|
+
filename (unicode): the filename of the file to describe.
|
111
|
+
return (unicode): the description of the file.
|
112
|
+
raise (KeyError): if the file cannot be found.
|
113
|
+
"""
|
114
|
+
pass
|
115
|
+
|
116
|
+
@abstractmethod
|
117
|
+
def get_size(self, filename: str) -> int:
|
118
|
+
"""Return the size of a file given its filename.
|
119
|
+
filename (unicode): the filename of the file to calculate the size
|
120
|
+
of.
|
121
|
+
return (int): the size of the file, in bytes.
|
122
|
+
raise (KeyError): if the file cannot be found.
|
123
|
+
"""
|
124
|
+
pass
|
125
|
+
|
126
|
+
@abstractmethod
|
127
|
+
def delete(self, filename: str):
|
128
|
+
"""Delete a file from the storage.
|
129
|
+
filename (unicode): the filename of the file to delete.
|
130
|
+
"""
|
131
|
+
pass
|
132
|
+
|
133
|
+
@abstractmethod
|
134
|
+
def list(self) -> List[FileWithDescription]:
|
135
|
+
"""List the files available in the storage.
|
136
|
+
return ([(unicode, unicode)]): a list of pairs, each
|
137
|
+
representing a file in the form (filename, description).
|
138
|
+
"""
|
139
|
+
pass
|
140
|
+
|
141
|
+
@abstractmethod
|
142
|
+
def path_for_symlink(self, filename: str) -> Optional[pathlib.Path]:
|
143
|
+
pass
|
144
|
+
|
145
|
+
|
146
|
+
class NullStorage(Storage):
|
147
|
+
"""This backend is always empty, it just drops each file that
|
148
|
+
receives. It looks mostly like /dev/null. It is useful when you
|
149
|
+
want to just rely on the caching capabilities of FileCacher for
|
150
|
+
very short-lived and local storages.
|
151
|
+
|
152
|
+
"""
|
153
|
+
|
154
|
+
def get_file(self, digest: str) -> IO[bytes]:
|
155
|
+
raise KeyError('File not found.')
|
156
|
+
|
157
|
+
def create_file(self, digest: str) -> Optional[PendingFile]:
|
158
|
+
return None
|
159
|
+
|
160
|
+
def commit_file(self, file: PendingFile, desc: str = '') -> bool:
|
161
|
+
return False
|
162
|
+
|
163
|
+
def exists(self, filename: str) -> bool:
|
164
|
+
return False
|
165
|
+
|
166
|
+
def describe(self, digest: str) -> str:
|
167
|
+
raise KeyError('File not found.')
|
168
|
+
|
169
|
+
def get_size(self, digest: str) -> int:
|
170
|
+
raise KeyError('File not found.')
|
171
|
+
|
172
|
+
def delete(self, digest: str):
|
173
|
+
pass
|
174
|
+
|
175
|
+
def list(self) -> List[FileWithDescription]:
|
176
|
+
return list()
|
177
|
+
|
178
|
+
def path_for_symlink(self, digest: str) -> Optional[pathlib.Path]:
|
179
|
+
return None
|
180
|
+
|
181
|
+
|
182
|
+
class FilesystemStorage(Storage):
|
183
|
+
"""This class implements a backend for FileCacher that keeps all
|
184
|
+
the files in a file system directory, named after their filename.
|
185
|
+
"""
|
186
|
+
|
187
|
+
def __init__(self, path: pathlib.Path):
|
188
|
+
"""Initialize the backend.
|
189
|
+
path (string): the base path for the storage.
|
190
|
+
"""
|
191
|
+
self.path = path
|
192
|
+
|
193
|
+
# Create the directory if it doesn't exist
|
194
|
+
path.mkdir(parents=True, exist_ok=True)
|
195
|
+
|
196
|
+
def get_file(self, filename: str) -> IO[bytes]:
|
197
|
+
"""See FileCacherBackend.get_file()."""
|
198
|
+
file_path = self.path / filename
|
199
|
+
|
200
|
+
if not file_path.is_file():
|
201
|
+
raise KeyError('File not found.')
|
202
|
+
|
203
|
+
return file_path.open('rb')
|
204
|
+
|
205
|
+
def create_file(self, filename: str) -> Optional[PendingFile]:
|
206
|
+
"""See FileCacherBackend.create_file()."""
|
207
|
+
# Check if the file already exists. Return None if so, to inform the
|
208
|
+
# caller they don't need to store the file.
|
209
|
+
file_path = self.path / filename
|
210
|
+
|
211
|
+
if file_path.is_file():
|
212
|
+
return None
|
213
|
+
|
214
|
+
# Create a temporary file in the same directory
|
215
|
+
temp_file = tempfile.NamedTemporaryFile(
|
216
|
+
'wb', delete=False, prefix='.tmp.', suffix=filename, dir=self.path
|
217
|
+
)
|
218
|
+
return PendingFile(fd=temp_file, filename=filename)
|
219
|
+
|
220
|
+
def commit_file(self, file: PendingFile, desc: str = '') -> bool:
|
221
|
+
"""See FileCacherBackend.commit_file()."""
|
222
|
+
file.fd.close()
|
223
|
+
|
224
|
+
file_path: pathlib.Path = self.path / file.filename
|
225
|
+
# Move it into place in the cache. Skip if it already exists, and
|
226
|
+
# delete the temporary file instead.
|
227
|
+
if not file_path.is_file():
|
228
|
+
# There is a race condition here if someone else puts the file here
|
229
|
+
# between checking and renaming. Put it doesn't matter in practice,
|
230
|
+
# because rename will replace the file anyway (which should be
|
231
|
+
# identical).
|
232
|
+
pathlib.PosixPath(file.fd.name).rename(file_path)
|
233
|
+
return True
|
234
|
+
else:
|
235
|
+
pathlib.PosixPath(file.fd.name).unlink()
|
236
|
+
return False
|
237
|
+
|
238
|
+
def exists(self, filename: str) -> bool:
|
239
|
+
"""See FileCacherBackend.exists()."""
|
240
|
+
file_path: pathlib.Path = self.path / filename
|
241
|
+
|
242
|
+
return file_path.is_file()
|
243
|
+
|
244
|
+
def describe(self, filename: str) -> str:
|
245
|
+
"""See FileCacherBackend.describe()."""
|
246
|
+
file_path: pathlib.Path = self.path / filename
|
247
|
+
|
248
|
+
if not file_path.is_file():
|
249
|
+
raise KeyError('File not found.')
|
250
|
+
|
251
|
+
return ''
|
252
|
+
|
253
|
+
def get_size(self, filename: str) -> int:
|
254
|
+
"""See FileCacherBackend.get_size()."""
|
255
|
+
file_path: pathlib.Path = self.path / filename
|
256
|
+
|
257
|
+
if not file_path.is_file():
|
258
|
+
raise KeyError('File not found.')
|
259
|
+
|
260
|
+
return file_path.stat().st_size
|
261
|
+
|
262
|
+
def delete(self, filename: str):
|
263
|
+
"""See FileCacherBackend.delete()."""
|
264
|
+
file_path: pathlib.Path = self.path / filename
|
265
|
+
|
266
|
+
file_path.unlink(missing_ok=True)
|
267
|
+
|
268
|
+
def list(self) -> List[FileWithDescription]:
|
269
|
+
"""See FileCacherBackend.list()."""
|
270
|
+
res = []
|
271
|
+
for path in self.path.glob('*'):
|
272
|
+
if path.is_file():
|
273
|
+
res.append(
|
274
|
+
FileWithDescription(
|
275
|
+
filename=str(path.relative_to(self.path)), description=''
|
276
|
+
)
|
277
|
+
)
|
278
|
+
return res
|
279
|
+
|
280
|
+
def path_for_symlink(self, filename: str) -> Optional[pathlib.Path]:
|
281
|
+
file_path = self.path / filename
|
282
|
+
if not file_path.is_file():
|
283
|
+
raise KeyError('File not found.')
|
284
|
+
return file_path
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import atexit
|
2
|
+
import pathlib
|
3
|
+
|
4
|
+
from rich.console import Console
|
5
|
+
|
6
|
+
from rbx.grading.judge import cacher, storage
|
7
|
+
from rbx.grading.judge.sandboxes import stupid_sandbox
|
8
|
+
|
9
|
+
console = Console()
|
10
|
+
|
11
|
+
|
12
|
+
def main():
|
13
|
+
fs = storage.FilesystemStorage(pathlib.PosixPath('/tmp/rbx-storage'))
|
14
|
+
cache = cacher.FileCacher(fs)
|
15
|
+
|
16
|
+
python_file = cache.put_file_text("print('hello')")
|
17
|
+
|
18
|
+
sandbox = stupid_sandbox.StupidSandbox(cache)
|
19
|
+
atexit.register(sandbox.cleanup)
|
20
|
+
sandbox.create_file_from_storage(pathlib.PosixPath('run.py'), python_file)
|
21
|
+
|
22
|
+
sandbox.params.stdout_file = pathlib.PosixPath('run.out')
|
23
|
+
|
24
|
+
sandbox.execute_without_std(['ls'])
|
25
|
+
try:
|
26
|
+
sandbox.hydrate_logs()
|
27
|
+
except Exception:
|
28
|
+
console.print_exception()
|
29
|
+
|
30
|
+
print(sandbox.get_human_exit_description())
|
31
|
+
print(sandbox.get_stats())
|
32
|
+
print(sandbox.log)
|
33
|
+
|
34
|
+
print(sandbox.get_file_to_string(pathlib.PosixPath('run.out')))
|
35
|
+
|
36
|
+
|
37
|
+
if __name__ == '__main__':
|
38
|
+
main()
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import atexit
|
2
|
+
import pathlib
|
3
|
+
|
4
|
+
from rich.console import Console
|
5
|
+
|
6
|
+
from rbx import grading_utils
|
7
|
+
from rbx.grading.judge import cacher, storage
|
8
|
+
from rbx.grading.judge.sandboxes.isolate import IsolateSandbox
|
9
|
+
|
10
|
+
console = Console()
|
11
|
+
|
12
|
+
|
13
|
+
def main():
|
14
|
+
fs = storage.FilesystemStorage(pathlib.PosixPath('/tmp/rbx-storage'))
|
15
|
+
cache = cacher.FileCacher(fs)
|
16
|
+
|
17
|
+
python_file = cache.put_file_text(
|
18
|
+
"""
|
19
|
+
#include <bits/stdc++.h>
|
20
|
+
|
21
|
+
int main() {
|
22
|
+
std::cout << "Hello, World!" << std::endl;
|
23
|
+
return 0;
|
24
|
+
}
|
25
|
+
"""
|
26
|
+
)
|
27
|
+
|
28
|
+
sandbox = IsolateSandbox(
|
29
|
+
cache, params=grading_utils.build_preprocess_sandbox_params(), debug=True
|
30
|
+
)
|
31
|
+
atexit.register(sandbox.cleanup)
|
32
|
+
sandbox.create_file_from_storage(pathlib.PosixPath('run.cpp'), python_file)
|
33
|
+
|
34
|
+
sandbox.params.stdout_file = pathlib.PosixPath('run.out')
|
35
|
+
sandbox.params.stderr_file = pathlib.PosixPath('run.err')
|
36
|
+
|
37
|
+
sandbox.execute_without_std(
|
38
|
+
['/usr/bin/g++', '-std=c++17', '-o', 'executable', 'run.cpp'],
|
39
|
+
)
|
40
|
+
try:
|
41
|
+
sandbox.hydrate_logs()
|
42
|
+
except Exception:
|
43
|
+
console.print_exception()
|
44
|
+
|
45
|
+
print(sandbox.log)
|
46
|
+
print(sandbox.get_human_exit_description())
|
47
|
+
print(sandbox.get_stats())
|
48
|
+
|
49
|
+
print(sandbox.get_file_to_string(pathlib.PosixPath('run.out')))
|
50
|
+
print(sandbox.get_file_to_string(pathlib.PosixPath('run.err')))
|
51
|
+
|
52
|
+
|
53
|
+
if __name__ == '__main__':
|
54
|
+
main()
|