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.
- rbx/annotations.py +5 -5
- rbx/box/checkers.py +26 -22
- rbx/box/cli.py +0 -4
- rbx/box/code.py +27 -80
- rbx/box/contest/build_contest_statements.py +16 -3
- rbx/box/contest/schema.py +1 -2
- rbx/box/environment.py +16 -6
- rbx/box/fields.py +25 -1
- rbx/box/generators.py +31 -5
- rbx/box/global_package.py +6 -2
- rbx/box/header.py +31 -11
- rbx/box/package.py +3 -15
- rbx/box/presets/__init__.py +2 -2
- rbx/box/schema.py +4 -25
- rbx/box/setter_config.py +11 -0
- rbx/box/solutions.py +12 -4
- rbx/box/statements/build_statements.py +5 -1
- rbx/box/statements/builders.py +7 -7
- rbx/box/statements/schema.py +11 -2
- rbx/box/tasks.py +9 -4
- rbx/box/testcase_utils.py +2 -0
- rbx/box/testing/__init__.py +0 -0
- rbx/box/testing/testing_package.py +246 -0
- rbx/box/testing/testing_preset.py +36 -0
- rbx/box/testing/testing_shared.py +81 -0
- rbx/box/ui/screens/run_explorer.py +0 -8
- rbx/box/ui/utils/run_ui.py +7 -3
- rbx/box/ui/widgets/test_output_box.py +1 -1
- rbx/box/validators.py +5 -2
- rbx/grading/caching.py +67 -16
- rbx/grading/judge/program.py +268 -0
- rbx/grading/judge/sandbox.py +30 -193
- rbx/grading/judge/sandboxes/stupid_sandbox.py +232 -241
- rbx/grading/judge/sandboxes/tee.py +31 -0
- rbx/grading/steps.py +87 -199
- rbx/grading/steps_with_caching.py +15 -6
- rbx/resources/presets/default/problem/problem.rbx.yml +0 -2
- rbx/resources/presets/default/shared/contest_template.rbx.tex +1 -1
- rbx/resources/presets/default/shared/problem_template.rbx.tex +5 -1
- rbx/resources/templates/rbx.h +43 -2
- rbx/testing_utils.py +8 -1
- rbx/utils.py +59 -1
- {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.5.dist-info}/METADATA +2 -1
- {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.5.dist-info}/RECORD +47 -67
- rbx/box/conftest.py +0 -42
- rbx/box/generators_test.py +0 -67
- rbx/box/lazy_importing_test.py +0 -25
- rbx/box/solutions_test.py +0 -47
- rbx/box/validators_test.py +0 -15
- rbx/checker.py +0 -128
- rbx/clone.py +0 -197
- rbx/conftest.py +0 -38
- rbx/create.py +0 -37
- rbx/edit.py +0 -24
- rbx/grading/conftest.py +0 -33
- rbx/grading/judge/sandboxes/isolate.py +0 -695
- rbx/grading/judge/testiso.py +0 -54
- rbx/grading/steps_with_caching_run_test.py +0 -707
- rbx/grading_utils.py +0 -148
- rbx/hydration.py +0 -101
- rbx/main.py +0 -118
- rbx/metadata.py +0 -105
- rbx/resources/envs/isolate.rbx.yml +0 -36
- rbx/resources/presets/default/problem/sols/slow.cpp +0 -15
- rbx/run.py +0 -45
- rbx/schema.py +0 -64
- rbx/submit.py +0 -61
- rbx/test.py +0 -349
- rbx/testcase.py +0 -70
- rbx/testcase_rendering.py +0 -79
- {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.5.dist-info}/LICENSE +0 -0
- {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.5.dist-info}/WHEEL +0 -0
- {rbx_cp-0.13.3.dist-info → rbx_cp-0.13.5.dist-info}/entry_points.txt +0 -0
rbx/clone.py
DELETED
@@ -1,197 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
import pathlib
|
3
|
-
import threading
|
4
|
-
import time
|
5
|
-
from typing import List, Optional
|
6
|
-
|
7
|
-
import fastapi
|
8
|
-
import jinja2
|
9
|
-
import rich
|
10
|
-
import rich.prompt
|
11
|
-
import rich.status
|
12
|
-
import uvicorn
|
13
|
-
|
14
|
-
from rbx import hydration, metadata, providers, utils
|
15
|
-
from rbx.config import Language, get_config
|
16
|
-
from rbx.console import console
|
17
|
-
from rbx.schema import DumpedProblem, Problem
|
18
|
-
|
19
|
-
|
20
|
-
def clear_loggers():
|
21
|
-
for logger_name in [
|
22
|
-
'uvicorn',
|
23
|
-
'uvicorn.access',
|
24
|
-
'uvicorn.asgi',
|
25
|
-
]:
|
26
|
-
logging.getLogger(logger_name).handlers.clear()
|
27
|
-
logging.getLogger(logger_name).propagate = False
|
28
|
-
|
29
|
-
|
30
|
-
def create_problem_structure(
|
31
|
-
root: pathlib.Path,
|
32
|
-
problem: Problem,
|
33
|
-
lang: Language,
|
34
|
-
status: Optional[rich.status.Status],
|
35
|
-
should_simplify: bool = False,
|
36
|
-
verbose: bool = False,
|
37
|
-
) -> Optional[DumpedProblem]:
|
38
|
-
# Create directory structure.
|
39
|
-
root.parent.mkdir(parents=True, exist_ok=True)
|
40
|
-
|
41
|
-
problem_to_dump = DumpedProblem.from_problem(
|
42
|
-
problem,
|
43
|
-
code=providers.get_code(problem, simplify=should_simplify),
|
44
|
-
aliases=providers.get_aliases(problem),
|
45
|
-
)
|
46
|
-
|
47
|
-
if verbose:
|
48
|
-
console.print(
|
49
|
-
f'Creating problem structure for [item]{problem_to_dump.pretty_name()}[/item]...'
|
50
|
-
)
|
51
|
-
|
52
|
-
code_path = root / lang.get_file(problem_to_dump.code)
|
53
|
-
json_path = root / f'{problem_to_dump.code}.rbx.json'
|
54
|
-
|
55
|
-
existing_problem = metadata.find_problem_by_code(problem_to_dump.code, root)
|
56
|
-
if existing_problem:
|
57
|
-
console.print(
|
58
|
-
f'[error]Problem with identifier [item]{problem_to_dump.code}[/item] already exists in this folder.[/error]'
|
59
|
-
)
|
60
|
-
if not utils.confirm_on_status(
|
61
|
-
status, 'Do you want to overwrite it?', default=False
|
62
|
-
):
|
63
|
-
console.print(
|
64
|
-
f'Skipping problem [item]{problem_to_dump.pretty_name()}[/item].'
|
65
|
-
)
|
66
|
-
return None
|
67
|
-
|
68
|
-
json_path.write_text(utils.model_json(problem_to_dump))
|
69
|
-
code = jinja2.Template(lang.get_template()).render(**problem_to_dump.get_vars())
|
70
|
-
code_path.write_text(code)
|
71
|
-
|
72
|
-
if verbose:
|
73
|
-
console.print(
|
74
|
-
f'Problem structure for [item]{problem_to_dump.pretty_name()}[/item] created successfully.'
|
75
|
-
)
|
76
|
-
return problem_to_dump
|
77
|
-
|
78
|
-
|
79
|
-
def process_problems(
|
80
|
-
problems: List[Problem], lang: Language, status: rich.status.Status
|
81
|
-
):
|
82
|
-
console.print(
|
83
|
-
f'Creating problem structure for [item]{len(problems)}[/item] problems...'
|
84
|
-
)
|
85
|
-
|
86
|
-
should_simplify = False
|
87
|
-
if providers.should_simplify_contest_problems(problems):
|
88
|
-
console.print('Detected the parsed problems are from a contest.')
|
89
|
-
if utils.confirm_on_status(
|
90
|
-
status,
|
91
|
-
'Do you want to identify these problems by their letters?',
|
92
|
-
default=True,
|
93
|
-
):
|
94
|
-
should_simplify = True
|
95
|
-
|
96
|
-
root = pathlib.Path()
|
97
|
-
dumped_problems = []
|
98
|
-
for problem in problems:
|
99
|
-
dumped_problem = create_problem_structure(
|
100
|
-
root, problem, lang, status, should_simplify=should_simplify
|
101
|
-
)
|
102
|
-
if dumped_problem:
|
103
|
-
dumped_problems.append(dumped_problem)
|
104
|
-
console.print(f'Hydrating [item]{len(dumped_problems)}[/item] problems...')
|
105
|
-
for problem in dumped_problems:
|
106
|
-
hydration.hydrate_problem(root, problem)
|
107
|
-
|
108
|
-
|
109
|
-
def main(lang: Optional[str] = None):
|
110
|
-
if get_config().get_language(lang) is None:
|
111
|
-
console.print(
|
112
|
-
f'[error]Language {lang or get_config().defaultLanguage} not found in config. Please check your configuration.[/error]'
|
113
|
-
)
|
114
|
-
return
|
115
|
-
|
116
|
-
app = fastapi.FastAPI()
|
117
|
-
|
118
|
-
async def shutdown():
|
119
|
-
server.should_exit = True
|
120
|
-
|
121
|
-
batch_to_left_lock = threading.Lock()
|
122
|
-
batch_to_left = {}
|
123
|
-
ignored = set()
|
124
|
-
saved_status = None
|
125
|
-
problems_to_process = []
|
126
|
-
|
127
|
-
def process_batch_item(problem: Problem):
|
128
|
-
batch_to_left_lock.acquire()
|
129
|
-
if problem.batch.id in ignored:
|
130
|
-
batch_to_left_lock.release()
|
131
|
-
return True
|
132
|
-
if problem.batch.id not in batch_to_left:
|
133
|
-
if len(batch_to_left) > 0:
|
134
|
-
console.print(
|
135
|
-
f'[error]Ignoring extra batch [item]{problem.batch.id}[/item] since other batch is being parsed.[/error]'
|
136
|
-
)
|
137
|
-
ignored.add(problem.batch.id)
|
138
|
-
batch_to_left_lock.release()
|
139
|
-
return True
|
140
|
-
if problem.batch.size > 1 and saved_status:
|
141
|
-
saved_status.update(
|
142
|
-
f'[rbx]rbx[/rbx] is parsing problems from group [item]{problem.group}[/item]'
|
143
|
-
)
|
144
|
-
elif saved_status:
|
145
|
-
saved_status.update('[rbx]rbx[/rbx] is parsing problems...')
|
146
|
-
console.print(
|
147
|
-
f'Started parsing batch [item]{problem.batch.id}[/item] with size [item]{problem.batch.size}[/item].'
|
148
|
-
)
|
149
|
-
batch_to_left[problem.batch.id] = problem.batch.size
|
150
|
-
console.print(f'Parsing problem [item]{problem.name}[/item]...')
|
151
|
-
problems_to_process.append(problem)
|
152
|
-
finished = False
|
153
|
-
if batch_to_left[problem.batch.id] == 1:
|
154
|
-
finished = True
|
155
|
-
if problem.batch.size > 1:
|
156
|
-
console.print(
|
157
|
-
f'[status][rbx]rbx[/rbx] parsed all problems from group [item]{problem.group}[/item].[/status]'
|
158
|
-
)
|
159
|
-
else:
|
160
|
-
console.print(
|
161
|
-
f'[status][rbx]rbx[/rbx] parsed problem from [item]{problem.url}[/item][/status]'
|
162
|
-
)
|
163
|
-
else:
|
164
|
-
batch_to_left[problem.batch.id] -= 1
|
165
|
-
batch_to_left_lock.release()
|
166
|
-
return not finished
|
167
|
-
|
168
|
-
clock = None
|
169
|
-
|
170
|
-
@app.post('/')
|
171
|
-
async def parse(problem: Problem, background_tasks: fastapi.BackgroundTasks):
|
172
|
-
nonlocal clock
|
173
|
-
if clock is None:
|
174
|
-
clock = time.monotonic()
|
175
|
-
if not process_batch_item(problem):
|
176
|
-
duration = time.monotonic() - clock
|
177
|
-
console.print(
|
178
|
-
f'Parsed all problems in [item]{duration:.2f}[/item] seconds.'
|
179
|
-
)
|
180
|
-
background_tasks.add_task(shutdown)
|
181
|
-
return {}
|
182
|
-
|
183
|
-
config = uvicorn.Config(app, port=1327)
|
184
|
-
server = uvicorn.Server(config=config)
|
185
|
-
clear_loggers()
|
186
|
-
with console.status('Waiting for Competitive Companion request...') as status:
|
187
|
-
saved_status = status
|
188
|
-
server.run()
|
189
|
-
|
190
|
-
with console.status('Processing parsed problems...') as status:
|
191
|
-
language = get_config().get_language(lang)
|
192
|
-
if not language:
|
193
|
-
console.print(
|
194
|
-
f'[error]Language {lang or get_config().defaultLanguage} not found in config. Please check your configuration.[/error]'
|
195
|
-
)
|
196
|
-
return
|
197
|
-
process_problems(problems_to_process, language, status)
|
rbx/conftest.py
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
import pathlib
|
3
|
-
import shutil
|
4
|
-
import tempfile
|
5
|
-
from collections.abc import Iterator
|
6
|
-
|
7
|
-
import pytest
|
8
|
-
|
9
|
-
from rbx.testing_utils import get_testdata_path
|
10
|
-
|
11
|
-
|
12
|
-
@pytest.fixture
|
13
|
-
def testdata_path() -> pathlib.Path:
|
14
|
-
return get_testdata_path()
|
15
|
-
|
16
|
-
|
17
|
-
@pytest.fixture
|
18
|
-
def cleandir() -> Iterator[pathlib.Path]:
|
19
|
-
with tempfile.TemporaryDirectory() as newpath:
|
20
|
-
abspath = pathlib.Path(newpath).absolute()
|
21
|
-
old_cwd = pathlib.Path.cwd()
|
22
|
-
os.chdir(newpath)
|
23
|
-
try:
|
24
|
-
yield abspath
|
25
|
-
finally:
|
26
|
-
os.chdir(str(old_cwd))
|
27
|
-
|
28
|
-
|
29
|
-
@pytest.fixture
|
30
|
-
def cleandir_with_testdata(
|
31
|
-
request, testdata_path: pathlib.Path, cleandir: pathlib.Path
|
32
|
-
) -> Iterator[pathlib.Path]:
|
33
|
-
marker = request.node.get_closest_marker('test_pkg')
|
34
|
-
if marker is None:
|
35
|
-
raise ValueError('test_pkg marker not found')
|
36
|
-
testdata = testdata_path / marker.args[0]
|
37
|
-
shutil.copytree(str(testdata), str(cleandir), dirs_exist_ok=True)
|
38
|
-
yield cleandir
|
rbx/create.py
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
import pathlib
|
2
|
-
|
3
|
-
from rbx import annotations
|
4
|
-
from rbx.clone import create_problem_structure
|
5
|
-
from rbx.config import get_config
|
6
|
-
from rbx.console import console
|
7
|
-
from rbx.schema import Batch, Problem
|
8
|
-
|
9
|
-
|
10
|
-
def main(
|
11
|
-
name: str,
|
12
|
-
lang: annotations.Language,
|
13
|
-
timelimit: annotations.Timelimit = 1000,
|
14
|
-
memorylimit: annotations.Memorylimit = 256,
|
15
|
-
multitest: annotations.Multitest = False,
|
16
|
-
):
|
17
|
-
language = get_config().get_language(lang)
|
18
|
-
if language is None:
|
19
|
-
console.print(
|
20
|
-
f'[error]Language {lang or get_config().defaultLanguage} not found in config. Please check your configuration.[/error]'
|
21
|
-
)
|
22
|
-
return
|
23
|
-
|
24
|
-
problem = Problem(
|
25
|
-
name=name,
|
26
|
-
timeLimit=timelimit,
|
27
|
-
memoryLimit=memorylimit,
|
28
|
-
testType='multiNumber' if multitest else 'single',
|
29
|
-
batch=Batch.create(),
|
30
|
-
)
|
31
|
-
create_problem_structure(
|
32
|
-
pathlib.Path(),
|
33
|
-
problem,
|
34
|
-
language,
|
35
|
-
status=None,
|
36
|
-
verbose=True,
|
37
|
-
)
|
rbx/edit.py
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
import pathlib
|
2
|
-
from typing import Optional
|
3
|
-
|
4
|
-
from rbx import annotations, console, metadata
|
5
|
-
from rbx.config import get_config, open_editor
|
6
|
-
|
7
|
-
|
8
|
-
def main(problem: str, language: Optional[annotations.LanguageWithDefault] = None):
|
9
|
-
lang = get_config().get_language(language)
|
10
|
-
if lang is None:
|
11
|
-
console.console.print(
|
12
|
-
f'[error]Language {language or get_config().defaultLanguage} not found in config. Please check your configuration.[/error]'
|
13
|
-
)
|
14
|
-
return
|
15
|
-
|
16
|
-
dumped_problem = metadata.find_problem_by_anything(problem)
|
17
|
-
if not dumped_problem:
|
18
|
-
console.console.print(
|
19
|
-
f'[error]Problem with identifier {problem} not found.[/error]'
|
20
|
-
)
|
21
|
-
return
|
22
|
-
|
23
|
-
filename = lang.get_file(dumped_problem.code)
|
24
|
-
open_editor(pathlib.Path(filename))
|
rbx/grading/conftest.py
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
import pathlib
|
2
|
-
from collections.abc import Iterator
|
3
|
-
|
4
|
-
import pytest
|
5
|
-
|
6
|
-
from rbx.grading.caching import DependencyCache
|
7
|
-
from rbx.grading.judge.cacher import FileCacher
|
8
|
-
from rbx.grading.judge.sandbox import SandboxBase
|
9
|
-
from rbx.grading.judge.sandboxes.stupid_sandbox import StupidSandbox
|
10
|
-
from rbx.grading.judge.storage import FilesystemStorage, Storage
|
11
|
-
|
12
|
-
|
13
|
-
@pytest.fixture
|
14
|
-
def storage(request, cleandir: pathlib.Path) -> Iterator[Storage]:
|
15
|
-
storage_path = cleandir / '.box' / '.storage'
|
16
|
-
yield FilesystemStorage(storage_path)
|
17
|
-
|
18
|
-
|
19
|
-
@pytest.fixture
|
20
|
-
def file_cacher(request, storage: Storage) -> Iterator[FileCacher]:
|
21
|
-
yield FileCacher(storage)
|
22
|
-
|
23
|
-
|
24
|
-
@pytest.fixture
|
25
|
-
def sandbox(request, file_cacher: FileCacher) -> Iterator[SandboxBase]:
|
26
|
-
yield StupidSandbox(file_cacher=file_cacher)
|
27
|
-
|
28
|
-
|
29
|
-
@pytest.fixture
|
30
|
-
def dependency_cache(
|
31
|
-
request, cleandir: pathlib.Path, file_cacher: FileCacher
|
32
|
-
) -> Iterator[DependencyCache]:
|
33
|
-
yield DependencyCache(cleandir / '.box', file_cacher)
|