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
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)