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
rbx/config.py
ADDED
@@ -0,0 +1,271 @@
|
|
1
|
+
import functools
|
2
|
+
import importlib
|
3
|
+
import importlib.resources
|
4
|
+
import os
|
5
|
+
import pathlib
|
6
|
+
import shutil
|
7
|
+
import subprocess
|
8
|
+
from typing import Any, Dict, List, Optional
|
9
|
+
|
10
|
+
import requests
|
11
|
+
import typer
|
12
|
+
from pydantic import BaseModel
|
13
|
+
|
14
|
+
from rbx import utils
|
15
|
+
from rbx.console import console
|
16
|
+
from rbx.grading.judge.storage import copyfileobj
|
17
|
+
|
18
|
+
app = typer.Typer(no_args_is_help=True)
|
19
|
+
|
20
|
+
_RESOURCES_PKG = 'rbx.resources'
|
21
|
+
_CONFIG_FILE_NAME = 'default_config.json'
|
22
|
+
|
23
|
+
|
24
|
+
def format_vars(template: str, **kwargs) -> str:
|
25
|
+
res = template
|
26
|
+
for key, value in kwargs.items():
|
27
|
+
key = key.replace('_', '-')
|
28
|
+
res = res.replace(f'%{{{key}}}', value)
|
29
|
+
return res
|
30
|
+
|
31
|
+
|
32
|
+
class Artifact(BaseModel):
|
33
|
+
filename: Optional[str] = None
|
34
|
+
executable: bool = False
|
35
|
+
optional: bool = False
|
36
|
+
|
37
|
+
|
38
|
+
class Language(BaseModel):
|
39
|
+
template: str
|
40
|
+
file: str
|
41
|
+
submitFile: Optional[str] = None
|
42
|
+
preprocess: Optional[List[str]] = None
|
43
|
+
exec: str
|
44
|
+
artifacts: Dict[str, Optional[Artifact]] = {}
|
45
|
+
submitor: Optional[str] = None
|
46
|
+
|
47
|
+
def get_file(self, basename: str) -> str:
|
48
|
+
return format_vars(self.file, problem_code=basename)
|
49
|
+
|
50
|
+
def has_submit_file(self) -> bool:
|
51
|
+
return self.submitFile is not None
|
52
|
+
|
53
|
+
def get_submit_file(self, basename: str) -> str:
|
54
|
+
if not self.submitFile:
|
55
|
+
return self.get_file(basename)
|
56
|
+
return format_vars(
|
57
|
+
self.submitFile, file=self.get_file(basename), problem_code=basename
|
58
|
+
)
|
59
|
+
|
60
|
+
def get_template(self) -> str:
|
61
|
+
return get_app_file(pathlib.Path('templates') / self.template).read_text()
|
62
|
+
|
63
|
+
|
64
|
+
SubmitorConfig = Dict[str, Any]
|
65
|
+
Credentials = Dict[str, Any]
|
66
|
+
|
67
|
+
|
68
|
+
class Config(BaseModel):
|
69
|
+
defaultLanguage: str
|
70
|
+
languages: Dict[str, Language]
|
71
|
+
editor: Optional[str] = None
|
72
|
+
submitor: Dict[str, SubmitorConfig]
|
73
|
+
credentials: Credentials
|
74
|
+
boxEnvironment: str = 'default'
|
75
|
+
|
76
|
+
def get_default_language(self) -> Optional[Language]:
|
77
|
+
return self.languages.get(self.defaultLanguage)
|
78
|
+
|
79
|
+
def get_language(self, name: Optional[str] = None) -> Optional[Language]:
|
80
|
+
return self.languages.get(name or self.defaultLanguage)
|
81
|
+
|
82
|
+
|
83
|
+
def get_app_path() -> pathlib.Path:
|
84
|
+
return utils.get_app_path()
|
85
|
+
|
86
|
+
|
87
|
+
def get_empty_app_persist_path() -> pathlib.Path:
|
88
|
+
app_dir = get_app_path() / 'persist'
|
89
|
+
shutil.rmtree(str(app_dir), ignore_errors=True)
|
90
|
+
app_dir.mkdir(parents=True, exist_ok=True)
|
91
|
+
return app_dir
|
92
|
+
|
93
|
+
|
94
|
+
def get_app_file(path: pathlib.Path) -> pathlib.Path:
|
95
|
+
file_path = get_app_path() / path
|
96
|
+
if file_path.is_file():
|
97
|
+
return file_path
|
98
|
+
|
99
|
+
with importlib.resources.as_file(
|
100
|
+
importlib.resources.files('rbx') / 'resources' / path # type: ignore
|
101
|
+
) as file:
|
102
|
+
if file.is_file():
|
103
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
104
|
+
with file.open('rb') as fr:
|
105
|
+
with file_path.open('wb') as fw:
|
106
|
+
copyfileobj(fr, fw)
|
107
|
+
return file_path
|
108
|
+
|
109
|
+
|
110
|
+
def _download_checker(name: str, save_at: pathlib.Path):
|
111
|
+
console.print(f'Downloading checker {name}...')
|
112
|
+
r = requests.get(
|
113
|
+
f'https://raw.githubusercontent.com/MikeMirzayanov/testlib/master/checkers/{name}'
|
114
|
+
)
|
115
|
+
|
116
|
+
if r.ok:
|
117
|
+
save_at.parent.mkdir(parents=True, exist_ok=True)
|
118
|
+
with save_at.open('wb') as f:
|
119
|
+
f.write(r.content)
|
120
|
+
|
121
|
+
|
122
|
+
def _download_testlib(save_at: pathlib.Path):
|
123
|
+
console.print('Downloading testlib.h...')
|
124
|
+
r = requests.get(
|
125
|
+
'https://raw.githubusercontent.com/MikeMirzayanov/testlib/master/testlib.h'
|
126
|
+
)
|
127
|
+
|
128
|
+
if r.ok:
|
129
|
+
save_at.parent.mkdir(parents=True, exist_ok=True)
|
130
|
+
with save_at.open('wb') as f:
|
131
|
+
f.write(r.content)
|
132
|
+
else:
|
133
|
+
console.print('[error]Failed to download testlib.h.[/error]')
|
134
|
+
raise typer.Exit(1)
|
135
|
+
|
136
|
+
|
137
|
+
def _download_jngen(save_at: pathlib.Path):
|
138
|
+
console.print('Downloading jngen.h...')
|
139
|
+
r = requests.get('https://raw.githubusercontent.com/ifsmirnov/jngen/master/jngen.h')
|
140
|
+
|
141
|
+
if r.ok:
|
142
|
+
save_at.parent.mkdir(parents=True, exist_ok=True)
|
143
|
+
with save_at.open('wb') as f:
|
144
|
+
f.write(r.content)
|
145
|
+
else:
|
146
|
+
console.print('[error]Failed to download jngen.h.[/error]')
|
147
|
+
raise typer.Exit(1)
|
148
|
+
|
149
|
+
|
150
|
+
def _download_bits_stdcpp(save_at: pathlib.Path):
|
151
|
+
console.print('Downloading bits/stdc++.h...')
|
152
|
+
r = requests.get(
|
153
|
+
'https://raw.githubusercontent.com/tekfyl/bits-stdc-.h-for-mac/master/stdc%2B%2B.h'
|
154
|
+
)
|
155
|
+
|
156
|
+
if r.ok:
|
157
|
+
save_at.parent.mkdir(parents=True, exist_ok=True)
|
158
|
+
with save_at.open('wb') as f:
|
159
|
+
f.write(r.content)
|
160
|
+
else:
|
161
|
+
console.print('[error]Failed to download bits/stdc++.h.[/error]')
|
162
|
+
raise typer.Exit(1)
|
163
|
+
|
164
|
+
|
165
|
+
def get_builtin_checker(name: str) -> pathlib.Path:
|
166
|
+
app_file = get_app_file(pathlib.Path('checkers') / name)
|
167
|
+
if not app_file.exists():
|
168
|
+
_download_checker(name, app_file)
|
169
|
+
return app_file
|
170
|
+
|
171
|
+
|
172
|
+
def get_testlib() -> pathlib.Path:
|
173
|
+
app_file = get_app_file(pathlib.Path('testlib.h'))
|
174
|
+
if not app_file.exists():
|
175
|
+
_download_testlib(app_file)
|
176
|
+
return app_file
|
177
|
+
|
178
|
+
|
179
|
+
def get_jngen() -> pathlib.Path:
|
180
|
+
app_file = get_app_file(pathlib.Path('jngen.h'))
|
181
|
+
if not app_file.exists():
|
182
|
+
_download_jngen(app_file)
|
183
|
+
return app_file
|
184
|
+
|
185
|
+
|
186
|
+
def get_bits_stdcpp() -> pathlib.Path:
|
187
|
+
app_file = get_app_file(pathlib.Path('stdc++.h'))
|
188
|
+
if not app_file.exists():
|
189
|
+
_download_bits_stdcpp(app_file)
|
190
|
+
return app_file
|
191
|
+
|
192
|
+
|
193
|
+
def get_default_config_path() -> pathlib.Path:
|
194
|
+
with importlib.resources.as_file(
|
195
|
+
importlib.resources.files('rbx') / 'resources' / _CONFIG_FILE_NAME
|
196
|
+
) as file:
|
197
|
+
return file
|
198
|
+
|
199
|
+
|
200
|
+
def get_default_app_path() -> pathlib.Path:
|
201
|
+
return get_default_config_path().parent
|
202
|
+
|
203
|
+
|
204
|
+
def get_default_config() -> Config:
|
205
|
+
return Config.model_validate_json(get_default_config_path().read_text())
|
206
|
+
|
207
|
+
|
208
|
+
def get_config_path() -> pathlib.Path:
|
209
|
+
return get_app_path() / 'config.json'
|
210
|
+
|
211
|
+
|
212
|
+
def get_editor():
|
213
|
+
return get_config().editor or os.environ.get('EDITOR', None)
|
214
|
+
|
215
|
+
|
216
|
+
def open_editor(path: pathlib.Path, *args):
|
217
|
+
editor = get_editor()
|
218
|
+
if editor is None:
|
219
|
+
raise Exception('No editor found. Please set the EDITOR environment variable.')
|
220
|
+
subprocess.run([editor, str(path), *[str(arg) for arg in args]])
|
221
|
+
|
222
|
+
|
223
|
+
@functools.cache
|
224
|
+
def get_config() -> Config:
|
225
|
+
config_path = get_config_path()
|
226
|
+
if not config_path.is_file():
|
227
|
+
utils.create_and_write(config_path, utils.model_json(get_default_config()))
|
228
|
+
return Config.model_validate_json(config_path.read_text())
|
229
|
+
|
230
|
+
|
231
|
+
def save_config(cfg: Config):
|
232
|
+
cfg_path = get_config_path()
|
233
|
+
cfg_path.write_text(utils.model_json(cfg))
|
234
|
+
get_config.cache_clear()
|
235
|
+
|
236
|
+
|
237
|
+
@app.command()
|
238
|
+
def path():
|
239
|
+
"""
|
240
|
+
Show the absolute path of the config file.
|
241
|
+
"""
|
242
|
+
get_config() # Ensure config is created.
|
243
|
+
console.print(get_config_path())
|
244
|
+
|
245
|
+
|
246
|
+
@app.command('list, ls')
|
247
|
+
def list():
|
248
|
+
"""
|
249
|
+
Pretty print the config file.
|
250
|
+
"""
|
251
|
+
console.print_json(utils.model_json(get_config()))
|
252
|
+
|
253
|
+
|
254
|
+
@app.command()
|
255
|
+
def reset():
|
256
|
+
"""
|
257
|
+
Reset the config file to the default one.
|
258
|
+
"""
|
259
|
+
if not typer.confirm('Do you really want to reset your config to the default one?'):
|
260
|
+
return
|
261
|
+
cfg_path = get_config_path()
|
262
|
+
cfg_path.unlink(missing_ok=True)
|
263
|
+
get_config() # Reset the config.
|
264
|
+
|
265
|
+
|
266
|
+
@app.command('edit, e')
|
267
|
+
def edit():
|
268
|
+
"""
|
269
|
+
Open the config in an editor.
|
270
|
+
"""
|
271
|
+
open_editor(get_config_path())
|
rbx/conftest.py
ADDED
@@ -0,0 +1,38 @@
|
|
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/console.py
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
import sys
|
2
|
+
|
3
|
+
from rich.console import Console
|
4
|
+
from rich.theme import Theme
|
5
|
+
|
6
|
+
theme = Theme(
|
7
|
+
{
|
8
|
+
'default': 'bright_white',
|
9
|
+
'rbx': 'bold italic yellow',
|
10
|
+
'info': 'bright_black',
|
11
|
+
'status': 'bright_white',
|
12
|
+
'item': 'bold blue',
|
13
|
+
'error': 'bold red',
|
14
|
+
'success': 'bold green',
|
15
|
+
'lnumber': 'dim cyan',
|
16
|
+
'warning': 'bold yellow',
|
17
|
+
}
|
18
|
+
)
|
19
|
+
console = Console(theme=theme, style='info', highlight=False)
|
20
|
+
stderr_console = Console(theme=theme, style='info', highlight=False, stderr=True)
|
21
|
+
|
22
|
+
|
23
|
+
def multiline_prompt(text: str) -> str:
|
24
|
+
console.print(f'{text} (Ctrl-D to finish):\n')
|
25
|
+
lines = sys.stdin.readlines()
|
26
|
+
console.print()
|
27
|
+
return ''.join(lines)
|
rbx/create.py
ADDED
@@ -0,0 +1,37 @@
|
|
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
ADDED
@@ -0,0 +1,24 @@
|
|
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/__init__.py
ADDED
File without changes
|