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.
Files changed (164) hide show
  1. rbx/__init__.py +0 -0
  2. rbx/annotations.py +127 -0
  3. rbx/autoenum.py +333 -0
  4. rbx/box/__init__.py +0 -0
  5. rbx/box/builder.py +77 -0
  6. rbx/box/cd.py +37 -0
  7. rbx/box/checkers.py +134 -0
  8. rbx/box/code.py +185 -0
  9. rbx/box/compile.py +56 -0
  10. rbx/box/conftest.py +42 -0
  11. rbx/box/contest/__init__.py +0 -0
  12. rbx/box/contest/build_contest_statements.py +347 -0
  13. rbx/box/contest/contest_package.py +76 -0
  14. rbx/box/contest/contest_utils.py +20 -0
  15. rbx/box/contest/main.py +179 -0
  16. rbx/box/contest/schema.py +155 -0
  17. rbx/box/contest/statements.py +82 -0
  18. rbx/box/creation.py +72 -0
  19. rbx/box/download.py +64 -0
  20. rbx/box/environment.py +345 -0
  21. rbx/box/extensions.py +26 -0
  22. rbx/box/generators.py +478 -0
  23. rbx/box/generators_test.py +63 -0
  24. rbx/box/main.py +449 -0
  25. rbx/box/package.py +316 -0
  26. rbx/box/packaging/boca/extension.py +27 -0
  27. rbx/box/packaging/boca/packager.py +245 -0
  28. rbx/box/packaging/contest_main.py +82 -0
  29. rbx/box/packaging/main.py +68 -0
  30. rbx/box/packaging/packager.py +117 -0
  31. rbx/box/packaging/polygon/packager.py +320 -0
  32. rbx/box/packaging/polygon/test.py +81 -0
  33. rbx/box/packaging/polygon/xml_schema.py +106 -0
  34. rbx/box/presets/__init__.py +503 -0
  35. rbx/box/presets/fetch.py +70 -0
  36. rbx/box/presets/lock_schema.py +20 -0
  37. rbx/box/presets/schema.py +59 -0
  38. rbx/box/schema.py +394 -0
  39. rbx/box/solutions.py +792 -0
  40. rbx/box/solutions_test.py +41 -0
  41. rbx/box/statements/__init__.py +0 -0
  42. rbx/box/statements/build_statements.py +359 -0
  43. rbx/box/statements/builders.py +375 -0
  44. rbx/box/statements/joiners.py +113 -0
  45. rbx/box/statements/latex.py +47 -0
  46. rbx/box/statements/latex_jinja.py +214 -0
  47. rbx/box/statements/schema.py +138 -0
  48. rbx/box/stresses.py +292 -0
  49. rbx/box/stressing/__init__.py +0 -0
  50. rbx/box/stressing/finder_parser.py +359 -0
  51. rbx/box/stressing/generator_parser.py +258 -0
  52. rbx/box/testcases.py +54 -0
  53. rbx/box/ui/__init__.py +0 -0
  54. rbx/box/ui/captured_log.py +372 -0
  55. rbx/box/ui/css/app.tcss +48 -0
  56. rbx/box/ui/main.py +38 -0
  57. rbx/box/ui/run.py +209 -0
  58. rbx/box/validators.py +245 -0
  59. rbx/box/validators_test.py +15 -0
  60. rbx/checker.py +128 -0
  61. rbx/clone.py +197 -0
  62. rbx/config.py +271 -0
  63. rbx/conftest.py +38 -0
  64. rbx/console.py +27 -0
  65. rbx/create.py +37 -0
  66. rbx/edit.py +24 -0
  67. rbx/grading/__init__.py +0 -0
  68. rbx/grading/caching.py +356 -0
  69. rbx/grading/conftest.py +33 -0
  70. rbx/grading/judge/__init__.py +0 -0
  71. rbx/grading/judge/cacher.py +503 -0
  72. rbx/grading/judge/digester.py +35 -0
  73. rbx/grading/judge/sandbox.py +748 -0
  74. rbx/grading/judge/sandboxes/__init__.py +0 -0
  75. rbx/grading/judge/sandboxes/isolate.py +683 -0
  76. rbx/grading/judge/sandboxes/stupid_sandbox.py +310 -0
  77. rbx/grading/judge/sandboxes/timeit.py +217 -0
  78. rbx/grading/judge/storage.py +284 -0
  79. rbx/grading/judge/test.py +38 -0
  80. rbx/grading/judge/testiso.py +54 -0
  81. rbx/grading/steps.py +522 -0
  82. rbx/grading/steps_with_caching.py +59 -0
  83. rbx/grading/steps_with_caching_run_test.py +429 -0
  84. rbx/grading_utils.py +148 -0
  85. rbx/hydration.py +101 -0
  86. rbx/main.py +122 -0
  87. rbx/metadata.py +105 -0
  88. rbx/providers/__init__.py +43 -0
  89. rbx/providers/codeforces.py +73 -0
  90. rbx/providers/provider.py +26 -0
  91. rbx/resources/checkers/boilerplate.cpp +20 -0
  92. rbx/resources/default_config.json +48 -0
  93. rbx/resources/envs/default.rbx.yml +37 -0
  94. rbx/resources/envs/isolate.rbx.yml +37 -0
  95. rbx/resources/packagers/boca/checker.sh +43 -0
  96. rbx/resources/packagers/boca/compare +53 -0
  97. rbx/resources/packagers/boca/compile/c +172 -0
  98. rbx/resources/packagers/boca/compile/cc +173 -0
  99. rbx/resources/packagers/boca/compile/cpp +172 -0
  100. rbx/resources/packagers/boca/compile/java +194 -0
  101. rbx/resources/packagers/boca/compile/kt +155 -0
  102. rbx/resources/packagers/boca/compile/pas +172 -0
  103. rbx/resources/packagers/boca/compile/py2 +173 -0
  104. rbx/resources/packagers/boca/compile/py3 +173 -0
  105. rbx/resources/packagers/boca/run/c +128 -0
  106. rbx/resources/packagers/boca/run/cc +128 -0
  107. rbx/resources/packagers/boca/run/cpp +128 -0
  108. rbx/resources/packagers/boca/run/java +194 -0
  109. rbx/resources/packagers/boca/run/kt +159 -0
  110. rbx/resources/packagers/boca/run/py2 +166 -0
  111. rbx/resources/packagers/boca/run/py3 +166 -0
  112. rbx/resources/presets/default/contest/contest.rbx.yml +14 -0
  113. rbx/resources/presets/default/contest/statement/contest.rbx.tex +97 -0
  114. rbx/resources/presets/default/contest/statement/olymp.sty +250 -0
  115. rbx/resources/presets/default/contest/statement/template.rbx.tex +42 -0
  116. rbx/resources/presets/default/preset.rbx.yml +12 -0
  117. rbx/resources/presets/default/problem/.gitignore +6 -0
  118. rbx/resources/presets/default/problem/gen.cpp +9 -0
  119. rbx/resources/presets/default/problem/problem.rbx.yml +44 -0
  120. rbx/resources/presets/default/problem/random.py +3 -0
  121. rbx/resources/presets/default/problem/random.txt +2 -0
  122. rbx/resources/presets/default/problem/sols/main.cpp +9 -0
  123. rbx/resources/presets/default/problem/sols/slow.cpp +15 -0
  124. rbx/resources/presets/default/problem/sols/wa.cpp +9 -0
  125. rbx/resources/presets/default/problem/statement/olymp.sty +250 -0
  126. rbx/resources/presets/default/problem/statement/projecao.png +0 -0
  127. rbx/resources/presets/default/problem/statement/statement.rbx.tex +18 -0
  128. rbx/resources/presets/default/problem/statement/template.rbx.tex +89 -0
  129. rbx/resources/presets/default/problem/tests/samples/000.in +1 -0
  130. rbx/resources/presets/default/problem/tests/samples/001.in +1 -0
  131. rbx/resources/presets/default/problem/validator.cpp +16 -0
  132. rbx/resources/presets/default/problem/wcmp.cpp +34 -0
  133. rbx/resources/templates/template.cpp +19 -0
  134. rbx/run.py +45 -0
  135. rbx/schema.py +64 -0
  136. rbx/submit.py +61 -0
  137. rbx/submitors/__init__.py +18 -0
  138. rbx/submitors/codeforces.py +120 -0
  139. rbx/submitors/submitor.py +25 -0
  140. rbx/test.py +347 -0
  141. rbx/testcase.py +70 -0
  142. rbx/testcase_rendering.py +79 -0
  143. rbx/testdata/box1/gen1.cpp +7 -0
  144. rbx/testdata/box1/gen2.cpp +9 -0
  145. rbx/testdata/box1/genScript.py +2 -0
  146. rbx/testdata/box1/hard-tle.sol.cpp +26 -0
  147. rbx/testdata/box1/ole.cpp +17 -0
  148. rbx/testdata/box1/problem.rbx.yml +39 -0
  149. rbx/testdata/box1/re.sol.cpp +23 -0
  150. rbx/testdata/box1/sol.cpp +22 -0
  151. rbx/testdata/box1/tests/1.in +1 -0
  152. rbx/testdata/box1/tle-and-incorrect.sol.cpp +33 -0
  153. rbx/testdata/box1/tle.sol.cpp +35 -0
  154. rbx/testdata/box1/validator.cpp +11 -0
  155. rbx/testdata/box1/wa.sol.cpp +22 -0
  156. rbx/testdata/caching/executable.py +1 -0
  157. rbx/testdata/compatible +0 -0
  158. rbx/testing_utils.py +65 -0
  159. rbx/utils.py +162 -0
  160. rbx_cp-0.5.0.dist-info/LICENSE +201 -0
  161. rbx_cp-0.5.0.dist-info/METADATA +89 -0
  162. rbx_cp-0.5.0.dist-info/RECORD +164 -0
  163. rbx_cp-0.5.0.dist-info/WHEEL +4 -0
  164. rbx_cp-0.5.0.dist-info/entry_points.txt +4 -0
@@ -0,0 +1,41 @@
1
+ import pathlib
2
+
3
+ import pytest
4
+
5
+ from rbx.box.environment import VerificationLevel
6
+ from rbx.box.generators import (
7
+ generate_outputs_for_testcases,
8
+ generate_testcases,
9
+ )
10
+ from rbx.box.solutions import (
11
+ convert_list_of_solution_evaluations_to_dict,
12
+ run_solutions,
13
+ )
14
+ from rbx.grading.steps import Outcome
15
+
16
+
17
+ @pytest.mark.test_pkg('box1')
18
+ def test_solutions(pkg_from_testdata: pathlib.Path):
19
+ generate_testcases()
20
+ generate_outputs_for_testcases()
21
+
22
+ result = run_solutions(verification=VerificationLevel.FULL)
23
+ res = convert_list_of_solution_evaluations_to_dict(result.items)
24
+
25
+ # First solution should pass all tests.
26
+ assert all(chk.result.outcome == Outcome.ACCEPTED for chk in res[0]['gen1'])
27
+ # 25 test should be WA for the second solution.
28
+ assert res[1]['gen1'][3].result.outcome == Outcome.WRONG_ANSWER
29
+ # Runtime error for third solution.
30
+ assert all(chk.result.outcome == Outcome.RUNTIME_ERROR for chk in res[2]['gen1'])
31
+ # 1e9 test should be TLE for the fourth solution (soft TLE)
32
+ assert res[3]['gen1'][4].result.outcome == Outcome.TIME_LIMIT_EXCEEDED
33
+ # no TLE outcome should be WA (soft TLE)
34
+ assert res[4]['gen1'][4].result.no_tle_outcome == Outcome.WRONG_ANSWER
35
+ # hard TLE
36
+ assert res[5]['gen1'][4].result.outcome == Outcome.TIME_LIMIT_EXCEEDED
37
+ assert res[5]['gen1'][4].result.no_tle_outcome is None
38
+ # OLE
39
+ assert all(
40
+ chk.result.outcome == Outcome.OUTPUT_LIMIT_EXCEEDED for chk in res[6]['gen1']
41
+ )
File without changes
@@ -0,0 +1,359 @@
1
+ import pathlib
2
+ import tempfile
3
+ import typing
4
+ from typing import Annotated, Dict, List, Optional, Tuple
5
+
6
+ import typer
7
+
8
+ from rbx import annotations, console
9
+ from rbx.box import builder, environment, package
10
+ from rbx.box.schema import Package
11
+ from rbx.box.statements.builders import (
12
+ BUILDER_LIST,
13
+ PROBLEM_BUILDER_LIST,
14
+ StatementBuilder,
15
+ StatementBuilderContext,
16
+ StatementBuilderProblem,
17
+ StatementCodeLanguage,
18
+ prepare_assets,
19
+ )
20
+ from rbx.box.statements.schema import (
21
+ ConversionStep,
22
+ ConversionType,
23
+ Statement,
24
+ StatementType,
25
+ )
26
+ from rbx.box.testcases import get_samples
27
+
28
+ app = typer.Typer(no_args_is_help=True, cls=annotations.AliasGroup)
29
+
30
+
31
+ def get_environment_languages_for_statement() -> List[StatementCodeLanguage]:
32
+ env = environment.get_environment()
33
+
34
+ res = []
35
+ for language in env.languages:
36
+ cmd = ''
37
+ compilation_cfg = environment.get_compilation_config(language.name)
38
+ cmd = ' && '.join(compilation_cfg.commands or [])
39
+ if not cmd:
40
+ execution_cfg = environment.get_execution_config(language.name)
41
+ cmd = execution_cfg.command
42
+
43
+ res.append(
44
+ StatementCodeLanguage(
45
+ id=language.name,
46
+ name=language.readable_name or language.name,
47
+ command=cmd or '',
48
+ )
49
+ )
50
+
51
+ return res
52
+
53
+
54
+ def get_builder(
55
+ name: ConversionType, builder_list: List[StatementBuilder]
56
+ ) -> StatementBuilder:
57
+ candidates = [builder for builder in builder_list if builder.name() == name]
58
+ if not candidates:
59
+ console.console.print(
60
+ f'[error]No statement builder found with name [name]{name}[/name][/error]'
61
+ )
62
+ raise typer.Exit(1)
63
+ return candidates[0]
64
+
65
+
66
+ def get_implicit_builders(
67
+ input_type: StatementType, output_type: StatementType
68
+ ) -> Optional[List[StatementBuilder]]:
69
+ par: Dict[StatementType, Optional[StatementBuilder]] = {input_type: None}
70
+
71
+ def _iterate() -> bool:
72
+ nonlocal par
73
+ for bdr in BUILDER_LIST:
74
+ u = bdr.input_type()
75
+ if u not in par:
76
+ continue
77
+ v = bdr.output_type()
78
+ if v in par:
79
+ continue
80
+ par[v] = bdr
81
+ return True
82
+ return False
83
+
84
+ while _iterate() and output_type not in par:
85
+ pass
86
+
87
+ if output_type not in par:
88
+ return None
89
+
90
+ res = []
91
+ cur = output_type
92
+ while par[cur] is not None:
93
+ res.append(par[cur])
94
+ cur = typing.cast(StatementBuilder, par[cur]).input_type()
95
+
96
+ return list(reversed(res))
97
+
98
+
99
+ def _try_implicit_builders(
100
+ statement_id: str, input_type: StatementType, output_type: StatementType
101
+ ) -> List[StatementBuilder]:
102
+ implicit_builders = get_implicit_builders(input_type, output_type)
103
+ if implicit_builders is None:
104
+ console.console.print(
105
+ f'[error]Cannot implicitly convert statement [item]{statement_id}[/item] '
106
+ f'from [item]{input_type}[/item] '
107
+ f'to specified output type [item]{output_type}[/item].[/error]'
108
+ )
109
+ raise typer.Exit(1)
110
+ console.console.print(
111
+ 'Implicitly adding statement builders to convert statement '
112
+ f'from [item]{input_type}[/item] to [item]{output_type}[/item]...'
113
+ )
114
+ return implicit_builders
115
+
116
+
117
+ def _get_configured_params_for(
118
+ configure: List[ConversionStep], conversion_type: ConversionType
119
+ ) -> Optional[ConversionStep]:
120
+ for step in configure:
121
+ if step.type == conversion_type:
122
+ return step
123
+ return None
124
+
125
+
126
+ def get_builders(
127
+ statement_id: str,
128
+ steps: List[ConversionStep],
129
+ configure: List[ConversionStep],
130
+ input_type: StatementType,
131
+ output_type: Optional[StatementType],
132
+ builder_list: List[StatementBuilder] = BUILDER_LIST,
133
+ ) -> List[Tuple[StatementBuilder, ConversionStep]]:
134
+ last_output = input_type
135
+ builders: List[Tuple[StatementBuilder, ConversionStep]] = []
136
+
137
+ # Conversion steps to force during build.
138
+ for step in steps:
139
+ builder = get_builder(step.type, builder_list=builder_list)
140
+ if builder.input_type() != last_output:
141
+ implicit_builders = _try_implicit_builders(
142
+ statement_id, last_output, builder.input_type()
143
+ )
144
+ builders.extend(
145
+ (builder, builder.default_params()) for builder in implicit_builders
146
+ )
147
+ builders.append((builder, step))
148
+ last_output = builder.output_type()
149
+
150
+ if output_type is not None and last_output != output_type:
151
+ implicit_builders = _try_implicit_builders(
152
+ statement_id, last_output, output_type
153
+ )
154
+ builders.extend(
155
+ (builder, builder.default_params()) for builder in implicit_builders
156
+ )
157
+
158
+ # Override statement configs.
159
+ def reconfigure(params: ConversionStep) -> ConversionStep:
160
+ new_params = _get_configured_params_for(configure, params.type)
161
+ return new_params or params
162
+
163
+ reconfigured_builders = [
164
+ (builder, reconfigure(params)) for builder, params in builders
165
+ ]
166
+ return reconfigured_builders
167
+
168
+
169
+ def get_relative_assets(
170
+ relative_to: pathlib.Path,
171
+ assets: List[str],
172
+ ) -> List[Tuple[pathlib.Path, pathlib.Path]]:
173
+ relative_to = relative_to.resolve()
174
+ if not relative_to.is_dir():
175
+ relative_to = relative_to.parent
176
+ res = []
177
+ for asset in assets:
178
+ relative_path = pathlib.Path(asset)
179
+ if not relative_path.is_file():
180
+ globbed = list(
181
+ path
182
+ for path in pathlib.Path().glob(str(relative_path))
183
+ if path.is_file()
184
+ )
185
+ if not globbed and '*' not in str(relative_path):
186
+ console.console.print(
187
+ f'[error]Asset [item]{asset}[/item] does not exist.[/error]'
188
+ )
189
+ raise typer.Exit(1)
190
+ res.extend(get_relative_assets(relative_to, list(map(str, globbed))))
191
+ continue
192
+ if not relative_path.resolve().is_relative_to(relative_to):
193
+ console.console.print(
194
+ f'[error]Asset [item]{asset}[/item] is not relative to your statement.[/error]'
195
+ )
196
+ raise typer.Exit(1)
197
+
198
+ res.append(
199
+ (
200
+ relative_path.resolve(),
201
+ relative_path.resolve().relative_to(relative_to),
202
+ )
203
+ )
204
+
205
+ return res
206
+
207
+
208
+ def build_statement_bytes(
209
+ statement: Statement,
210
+ pkg: Package,
211
+ output_type: Optional[StatementType] = None,
212
+ short_name: Optional[str] = None,
213
+ overridden_params_root: pathlib.Path = pathlib.Path(),
214
+ overridden_params: Optional[Dict[ConversionType, ConversionStep]] = None,
215
+ overridden_assets: Optional[List[Tuple[pathlib.Path, pathlib.Path]]] = None,
216
+ use_samples: bool = True,
217
+ is_editorial: bool = False,
218
+ ) -> Tuple[bytes, StatementType]:
219
+ overridden_params = overridden_params or {}
220
+ overridden_assets = overridden_assets or []
221
+
222
+ if not statement.path.is_file():
223
+ console.console.print(
224
+ f'[error]Statement file [item]{statement.path}[/item] does not exist.[/error]'
225
+ )
226
+ raise typer.Exit(1)
227
+ builders = get_builders(
228
+ str(statement.path),
229
+ statement.steps,
230
+ statement.configure,
231
+ statement.type,
232
+ output_type,
233
+ builder_list=PROBLEM_BUILDER_LIST,
234
+ )
235
+ last_output = statement.type
236
+ last_content = statement.path.read_bytes()
237
+ for bdr, params in builders:
238
+ with tempfile.TemporaryDirectory() as td:
239
+ # Here, create a new temp context for each builder call.
240
+ assets = get_relative_assets(statement.path, statement.assets)
241
+
242
+ # Use either overridden assets (by contest) or usual assets.
243
+ # Remember to modify the root to contest root if that's the case.
244
+ if bdr.name() in overridden_params:
245
+ assets.extend(
246
+ bdr.inject_assets(
247
+ overridden_params_root, overridden_params[bdr.name()]
248
+ )
249
+ )
250
+ else:
251
+ assets.extend(bdr.inject_assets(pathlib.Path(), params))
252
+ assets.extend(overridden_assets)
253
+
254
+ prepare_assets(assets, pathlib.Path(td))
255
+ output = bdr.build(
256
+ input=last_content,
257
+ context=StatementBuilderContext(
258
+ languages=get_environment_languages_for_statement(),
259
+ params=params,
260
+ root=pathlib.Path(td),
261
+ editorial=is_editorial,
262
+ ),
263
+ item=StatementBuilderProblem(
264
+ package=pkg,
265
+ statement=statement,
266
+ samples=get_samples() if use_samples else [],
267
+ short_name=short_name,
268
+ ),
269
+ verbose=False,
270
+ )
271
+ last_output = bdr.output_type()
272
+ last_content = output
273
+
274
+ return last_content, last_output
275
+
276
+
277
+ def build_statement(
278
+ statement: Statement,
279
+ pkg: Package,
280
+ output_type: Optional[StatementType] = None,
281
+ use_samples: bool = True,
282
+ is_editorial: bool = False,
283
+ ) -> pathlib.Path:
284
+ last_content, last_output = build_statement_bytes(
285
+ statement,
286
+ pkg,
287
+ output_type=output_type,
288
+ use_samples=use_samples,
289
+ is_editorial=is_editorial,
290
+ )
291
+ statement_path = (
292
+ package.get_build_path()
293
+ / f'{statement.path.stem}{last_output.get_file_suffix()}'
294
+ )
295
+ statement_path.parent.mkdir(parents=True, exist_ok=True)
296
+ statement_path.write_bytes(last_content)
297
+ console.console.print(
298
+ f'Statement built successfully for language '
299
+ f'[item]{statement.language}[/item] at '
300
+ f'[item]{statement_path}[/item].'
301
+ )
302
+ return statement_path
303
+
304
+
305
+ @app.command('build, b', help='Build statements.')
306
+ @package.within_problem
307
+ def build(
308
+ verification: environment.VerificationParam,
309
+ languages: Annotated[
310
+ Optional[List[str]],
311
+ typer.Option(
312
+ default_factory=list,
313
+ help='Languages to build statements for. If not specified, build statements for all available languages.',
314
+ ),
315
+ ],
316
+ output: Annotated[
317
+ Optional[StatementType],
318
+ typer.Option(
319
+ case_sensitive=False,
320
+ help='Output type to be generated. If not specified, will infer from the conversion steps specified in the package.',
321
+ ),
322
+ ] = StatementType.PDF,
323
+ samples: Annotated[
324
+ bool,
325
+ typer.Option(help='Whether to build the statement with samples or not.'),
326
+ ] = True,
327
+ editorial: Annotated[
328
+ bool, typer.Option(help='Whether to add editorial blocks to the statements.')
329
+ ] = False,
330
+ ):
331
+ # At most run the validators, only in samples.
332
+ if samples:
333
+ builder.build(verification=verification, groups=set(['samples']))
334
+
335
+ pkg = package.find_problem_package_or_die()
336
+ candidate_languages = languages
337
+ if not candidate_languages:
338
+ candidate_languages = sorted(set([st.language for st in pkg.statements]))
339
+
340
+ for language in candidate_languages:
341
+ candidates_for_lang = [st for st in pkg.statements if st.language == language]
342
+ if not candidates_for_lang:
343
+ console.console.print(
344
+ f'[error]No statement found for language [item]{language}[/item].[/error]',
345
+ )
346
+ raise typer.Exit(1)
347
+
348
+ build_statement(
349
+ candidates_for_lang[0],
350
+ pkg,
351
+ output_type=output,
352
+ use_samples=samples,
353
+ is_editorial=editorial,
354
+ )
355
+
356
+
357
+ @app.callback()
358
+ def callback():
359
+ pass