rbx.cp 0.8.0__py3-none-any.whl → 0.9.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 (47) hide show
  1. rbx/box/cd.py +2 -2
  2. rbx/box/cli.py +8 -2
  3. rbx/box/code.py +2 -2
  4. rbx/box/contest/build_contest_statements.py +2 -2
  5. rbx/box/contest/contest_package.py +1 -1
  6. rbx/box/contest/main.py +29 -2
  7. rbx/box/environment.py +140 -80
  8. rbx/box/formatting.py +2 -1
  9. rbx/box/package.py +5 -5
  10. rbx/box/packaging/__init__.py +0 -0
  11. rbx/box/packaging/boca/__init__.py +0 -0
  12. rbx/box/packaging/polygon/packager.py +3 -3
  13. rbx/box/presets/__init__.py +369 -53
  14. rbx/box/presets/lock_schema.py +42 -2
  15. rbx/box/presets/schema.py +4 -0
  16. rbx/box/remote.py +3 -3
  17. rbx/box/retries.py +3 -2
  18. rbx/box/sanitizers/warning_stack.py +2 -2
  19. rbx/box/solutions.py +24 -18
  20. rbx/box/statements/build_statements.py +6 -6
  21. rbx/box/statements/builders.py +1 -1
  22. rbx/box/stresses.py +2 -2
  23. rbx/box/testcase_utils.py +3 -3
  24. rbx/grading/judge/sandbox.py +2 -1
  25. rbx/grading/judge/sandboxes/isolate.py +3 -2
  26. rbx/grading/judge/sandboxes/stupid_sandbox.py +3 -2
  27. rbx/grading/judge/storage.py +2 -1
  28. rbx/grading/steps.py +2 -1
  29. rbx/resources/envs/default.rbx.yml +2 -3
  30. rbx/resources/envs/isolate.rbx.yml +2 -3
  31. rbx/resources/presets/default/contest/.gitignore +5 -1
  32. rbx/resources/presets/default/contest/statement/contest.rbx.tex +0 -1
  33. rbx/resources/presets/default/env.rbx.yml +67 -0
  34. rbx/resources/presets/default/preset.rbx.yml +6 -2
  35. rbx/resources/presets/default/problem/.gitignore +1 -1
  36. rbx/resources/presets/default/{contest/statement/template.rbx.tex → shared/problem_template.rbx.tex} +13 -7
  37. rbx/submitors/codeforces.py +3 -2
  38. rbx/test.py +1 -1
  39. rbx/utils.py +6 -1
  40. {rbx_cp-0.8.0.dist-info → rbx_cp-0.9.0.dist-info}/METADATA +2 -1
  41. {rbx_cp-0.8.0.dist-info → rbx_cp-0.9.0.dist-info}/RECORD +46 -44
  42. rbx/resources/presets/default/problem/statement/icpc.sty +0 -322
  43. /rbx/resources/presets/default/{problem/statement/template.rbx.tex → shared/contest_template.rbx.tex} +0 -0
  44. /rbx/resources/presets/default/{contest/statement → shared}/icpc.sty +0 -0
  45. {rbx_cp-0.8.0.dist-info → rbx_cp-0.9.0.dist-info}/LICENSE +0 -0
  46. {rbx_cp-0.8.0.dist-info → rbx_cp-0.9.0.dist-info}/WHEEL +0 -0
  47. {rbx_cp-0.8.0.dist-info → rbx_cp-0.9.0.dist-info}/entry_points.txt +0 -0
rbx/box/cd.py CHANGED
@@ -5,7 +5,7 @@ from typing import List, Optional
5
5
 
6
6
  import typer
7
7
 
8
- from rbx import console
8
+ from rbx import console, utils
9
9
  from rbx.box.sanitizers import warning_stack
10
10
  from rbx.utils import new_cd
11
11
 
@@ -13,7 +13,7 @@ from rbx.utils import new_cd
13
13
  def find_package(
14
14
  root: pathlib.Path = pathlib.Path(), consider_presets: bool = False
15
15
  ) -> Optional[pathlib.Path]:
16
- root = root.resolve()
16
+ root = utils.abspath(root)
17
17
 
18
18
  def has_file():
19
19
  problem_yaml_path = root / 'problem.rbx.yml'
rbx/box/cli.py CHANGED
@@ -577,7 +577,13 @@ async def irun(
577
577
  help='Create a new problem package.',
578
578
  )
579
579
  def create(
580
- name: str,
580
+ name: Annotated[
581
+ str,
582
+ typer.Option(
583
+ help='Name of the problem to create, which will be used as the name of the new folder.',
584
+ prompt='What should the name of the problem be?',
585
+ ),
586
+ ],
581
587
  preset: Annotated[
582
588
  Optional[str], typer.Option(help='Preset to use when creating the problem.')
583
589
  ] = None,
@@ -914,7 +920,7 @@ def languages():
914
920
 
915
921
  for language in env.languages:
916
922
  console.console.print(
917
- f'[item]{language.name}[/item], aka [item]{language.readable_name or language.name}[/item]:'
923
+ f'[item]{language.name}[/item], aka [item]{language.readableName or language.name}[/item]:'
918
924
  )
919
925
  console.console.print(language)
920
926
  console.console.print()
rbx/box/code.py CHANGED
@@ -12,7 +12,7 @@ import rich.text
12
12
  import typer
13
13
  from pydantic import BaseModel
14
14
 
15
- from rbx import console
15
+ from rbx import console, utils
16
16
  from rbx.box import download, global_package, package, setter_config, state
17
17
  from rbx.box.environment import (
18
18
  CompilationConfig,
@@ -296,7 +296,7 @@ def _prepare_for_communication(
296
296
  )
297
297
 
298
298
  if capture.merged_capture is not None:
299
- merged_output_path = package.get_merged_capture_path().resolve()
299
+ merged_output_path = utils.abspath(package.get_merged_capture_path())
300
300
  run.sandbox_params.timeit_dups['Do'].append(merged_output_path)
301
301
 
302
302
  run.artifacts.outputs.append(
@@ -6,7 +6,7 @@ from typing import Any, Dict, List, Optional, Tuple
6
6
 
7
7
  import typer
8
8
 
9
- from rbx import console, testing_utils
9
+ from rbx import console, testing_utils, utils
10
10
  from rbx.box import cd, package
11
11
  from rbx.box.contest.contest_package import get_problems
12
12
  from rbx.box.contest.schema import Contest, ContestProblem, ContestStatement
@@ -156,7 +156,7 @@ def _build_problem_statements(
156
156
  console.console.print('Building problem-level statements...')
157
157
  extracted_problems = get_problems_for_statement(contest, statement)
158
158
  res = []
159
- contest_cwd_absolute = pathlib.Path().resolve()
159
+ contest_cwd_absolute = utils.abspath(pathlib.Path())
160
160
  contest_assets = get_relative_assets(statement.path, statement.assets)
161
161
 
162
162
  extra_vars = dict(statement.override.vars if statement.override is not None else {})
@@ -17,7 +17,7 @@ YAML_NAME = 'contest.rbx.yml'
17
17
 
18
18
  @functools.cache
19
19
  def find_contest_yaml(root: pathlib.Path = pathlib.Path()) -> Optional[pathlib.Path]:
20
- root = root.resolve()
20
+ root = utils.abspath(root)
21
21
  contest_yaml_path = root / YAML_NAME
22
22
  while root != pathlib.PosixPath('/') and not contest_yaml_path.is_file():
23
23
  root = root.parent
rbx/box/contest/main.py CHANGED
@@ -38,7 +38,13 @@ app.add_typer(
38
38
 
39
39
  @app.command('create, c', help='Create a new contest package.')
40
40
  def create(
41
- path: str,
41
+ path: Annotated[
42
+ str,
43
+ typer.Option(
44
+ help='Path where to create the contest.',
45
+ prompt='Where should the contest be created, relative to the current directory? (e.g. "contests/ioi2024")',
46
+ ),
47
+ ],
42
48
  preset: Annotated[
43
49
  Optional[str],
44
50
  typer.Option(
@@ -108,7 +114,28 @@ def edit():
108
114
 
109
115
  @app.command('add, a', help='Add new problem to contest.')
110
116
  @within_contest
111
- def add(path: str, short_name: str, preset: Optional[str] = None):
117
+ def add(
118
+ path: Annotated[
119
+ str,
120
+ typer.Option(
121
+ help='Path where to create the problem. Name part of the path will be used as the problem name.',
122
+ prompt='Where should the problem be created, relative to the contest root? (e.g. problems/choco will create a problem named "choco" in this directory)',
123
+ ),
124
+ ],
125
+ short_name: Annotated[
126
+ str,
127
+ typer.Option(
128
+ help='Short name of the problem. Will be used as the identifier in the contest.',
129
+ prompt='What should the problem be named? (e.g. "A", "B1", "B2", "Z")',
130
+ ),
131
+ ],
132
+ preset: Annotated[
133
+ Optional[str],
134
+ typer.Option(
135
+ help='Preset to use when creating the problem. If not specified, the active preset will be used.',
136
+ ),
137
+ ] = None,
138
+ ):
112
139
  problem_path = pathlib.Path(path)
113
140
  name = problem_path.stem
114
141
  utils.validate_field(ContestProblem, 'short_name', short_name)
rbx/box/environment.py CHANGED
@@ -40,102 +40,149 @@ VerificationParam = Annotated[
40
40
  class FileMapping(BaseModel):
41
41
  model_config = ConfigDict(extra='forbid')
42
42
 
43
- # Path where to copy the stdin file to before running the program,
44
- # relative to the sandbox root.
45
- input: str = 'stdin'
43
+ input: str = Field(
44
+ default='stdin',
45
+ description="""Path where to copy the stdin file to before running the program,
46
+ relative to the sandbox root.""",
47
+ )
46
48
 
47
- # Path where to output the stdout file after running the program,
48
- # relative to the sandbox root.
49
- output: str = 'stdout'
49
+ output: str = Field(
50
+ default='stdout',
51
+ description="""Path where to output the stdout file after running the program,
52
+ relative to the sandbox root.""",
53
+ )
50
54
 
51
- # Path where to output the stderr file after running the program,
52
- # relative to the sandbox root.
53
- error: str = 'stderr'
55
+ error: str = Field(
56
+ default='stderr',
57
+ description="""Path where to output the stderr file after running the program,
58
+ relative to the sandbox root.""",
59
+ )
54
60
 
55
- # Path where to copy the compilable file to before compiling the program,
56
- # relative to the sandbox root.
57
- compilable: str = 'compilable'
61
+ compilable: str = Field(
62
+ default='compilable',
63
+ description="""Path where to copy the compilable file to before compiling the program,
64
+ relative to the sandbox root.""",
65
+ )
58
66
 
59
- # Path to where to output the executable file after compiling the program,
60
- # relative to the sandbox root.
61
- executable: str = 'executable'
67
+ executable: str = Field(
68
+ default='executable',
69
+ description="""Path to where to output the executable file after compiling the program,
70
+ relative to the sandbox root.""",
71
+ )
62
72
 
63
73
 
64
74
  class EnvironmentSandbox(BaseModel):
65
75
  model_config = ConfigDict(extra='forbid')
66
76
 
67
- # Max. number of process to allow to run concurrently for the program.
68
- maxProcesses: Optional[int] = 1
77
+ maxProcesses: Optional[int] = Field(
78
+ default=1,
79
+ description="""Max. number of process to allow to run concurrently for the program.""",
80
+ )
69
81
 
70
- # Time limit in milliseconds to allow the program to run.
71
- timeLimit: Optional[int] = None
82
+ timeLimit: Optional[int] = Field(
83
+ default=None,
84
+ description="""Time limit in milliseconds to allow the program to run.""",
85
+ )
72
86
 
73
- # Wall time limit in milliseconds to allow the program to run.
74
- wallTimeLimit: Optional[int] = None
87
+ wallTimeLimit: Optional[int] = Field(
88
+ default=None,
89
+ description="""Wall time limit in milliseconds to allow the program to run.""",
90
+ )
75
91
 
76
- # Memory limit in MiB.
77
- memoryLimit: Optional[int] = None
92
+ memoryLimit: Optional[int] = Field(
93
+ default=None,
94
+ description="""Memory limit in MiB.""",
95
+ )
78
96
 
79
- # File size limit in KiB
80
- fileSizeLimit: Optional[int] = None
97
+ fileSizeLimit: Optional[int] = Field(
98
+ default=None,
99
+ description="""File size limit in KiB""",
100
+ )
81
101
 
82
- # Stack limit in MiB.
83
- stackLimit: Optional[int] = None
102
+ stackLimit: Optional[int] = Field(
103
+ default=None,
104
+ description="""Stack limit in MiB.""",
105
+ )
84
106
 
85
- # Whether to preserve env. variables coming from the host.
86
- preserveEnv: Optional[bool] = False
107
+ preserveEnv: Optional[bool] = Field(
108
+ default=False,
109
+ description="""Whether to preserve env. variables coming from the host.""",
110
+ )
87
111
 
88
- # Directories in the host that should be read-only exposed to the sandbox.
89
- mirrorDirs: Optional[List[str]] = []
112
+ mirrorDirs: Optional[List[str]] = Field(
113
+ default=[],
114
+ description="""Directories in the host that should be read-only exposed to the sandbox.""",
115
+ )
90
116
 
91
117
 
92
118
  class CompilationConfig(BaseModel):
93
- # Commands to compile the program.
94
- commands: Optional[List[str]] = []
119
+ commands: Optional[List[str]] = Field(
120
+ default=[],
121
+ description="""Commands to compile the program.""",
122
+ )
95
123
 
96
- # Sandbox configuration to use when compiling for this language.
97
- sandbox: Optional[EnvironmentSandbox] = None
124
+ sandbox: Optional[EnvironmentSandbox] = Field(
125
+ default=None,
126
+ description="""Sandbox configuration to use when compiling for this language.""",
127
+ )
98
128
 
99
129
 
100
130
  class ExecutionConfig(BaseModel):
101
131
  model_config = ConfigDict(extra='forbid')
102
132
 
103
- # Command to run the program.
104
- command: Optional[str] = None
133
+ command: Optional[str] = Field(
134
+ default=None,
135
+ description="""Command to run the program.""",
136
+ )
105
137
 
106
- # Sandbox configuration to use when executing for this language.
107
- sandbox: Optional[EnvironmentSandbox] = None
138
+ sandbox: Optional[EnvironmentSandbox] = Field(
139
+ default=None,
140
+ description="""Sandbox configuration to use when executing for this language.""",
141
+ )
108
142
 
109
- # Original limits of the problem.
110
- problemLimits: Limits = Field(default_factory=Limits)
143
+ problemLimits: Limits = Field(
144
+ default_factory=Limits,
145
+ description="""Original limits of the problem.""",
146
+ )
111
147
 
112
148
 
113
149
  class EnvironmentLanguage(BaseModel):
114
150
  model_config = ConfigDict(extra='forbid')
115
151
 
116
- # Identifier of this language within this environment.
117
- name: str
152
+ name: str = Field(
153
+ description="""Identifier of this language within this environment."""
154
+ )
118
155
 
119
- # Readable name for this language.
120
- readable_name: Optional[str] = None
156
+ readableName: Optional[str] = Field(
157
+ default=None,
158
+ description="""Readable name for this language.""",
159
+ )
121
160
 
122
- # File extension supported by this language. If there's only one language
123
- # that supports a certain file extension in the environment, the tool
124
- # will automatically identify the language based on such extension.
125
- extension: str
161
+ extension: str = Field(
162
+ description="""File extension supported by this language. If there's only one language
163
+ that supports a certain file extension in the environment, the tool
164
+ will automatically identify the language based on such extension."""
165
+ )
126
166
 
127
- # Compilation config to use when compiling programs for this language.
128
- compilation: Optional[CompilationConfig] = None
167
+ compilation: Optional[CompilationConfig] = Field(
168
+ default=None,
169
+ description="""Compilation config to use when compiling programs for this language.""",
170
+ )
129
171
 
130
- # Execution config to use when running programs for this language.
131
- execution: ExecutionConfig
172
+ execution: ExecutionConfig = Field(
173
+ description="""Execution config to use when running programs for this language."""
174
+ )
132
175
 
133
- # Mapping for files within the sandbox. If not specified, the default mapping
134
- # for the environment will be used.
135
- fileMapping: Optional[FileMapping] = None
176
+ fileMapping: Optional[FileMapping] = Field(
177
+ default=None,
178
+ description="""Mapping for files within the sandbox. If not specified, the default mapping
179
+ for the environment will be used.""",
180
+ )
136
181
 
137
- # Exntensions to apply for this language.
138
- extensions: Optional[LanguageExtensions] = None
182
+ extensions: Optional[LanguageExtensions] = Field(
183
+ default=None,
184
+ description="""Extensions to apply for this language.""",
185
+ )
139
186
 
140
187
  def get_extension(self, name: str, _: Type[T]) -> Optional[T]:
141
188
  if self.extensions is None:
@@ -151,39 +198,52 @@ class EnvironmentLanguage(BaseModel):
151
198
  class TimingConfig(BaseModel):
152
199
  model_config = ConfigDict(extra='forbid')
153
200
 
154
- # Formula to use to calculate the time limit for the environment.
155
- formula: str = 'step_up(max(fastest * 3, slowest * 1.5), 100)'
201
+ formula: str = Field(
202
+ default='step_up(max(fastest * 3, slowest * 1.5), 100)',
203
+ description="""Formula to use to calculate the time limit for the environment.""",
204
+ )
156
205
 
157
206
 
158
207
  class Environment(BaseModel):
159
208
  model_config = ConfigDict(extra='forbid')
160
209
 
161
- # Default mapping for files within the sandbox. Fields in the mapping can be
162
- # individually overridden in the language configuration.
163
- defaultFileMapping: Optional[FileMapping] = None
164
-
165
- # Default compilation configuration to use when compiling programs. Fields in
166
- # the compilation config can be individually overridden in the language configuration.
167
- defaultCompilation: Optional[CompilationConfig] = None
210
+ defaultFileMapping: Optional[FileMapping] = Field(
211
+ default=None,
212
+ description="""Default mapping for files within the sandbox. Fields in the mapping can be
213
+ individually overridden in the language configuration.""",
214
+ )
168
215
 
169
- # Default execution configuration to use when running programs. Fields in the
170
- # execution config can be individually overridden in the language configuration.
171
- defaultExecution: Optional[ExecutionConfig] = None
216
+ defaultCompilation: Optional[CompilationConfig] = Field(
217
+ default=None,
218
+ description="""Default compilation configuration to use when compiling programs. Fields in
219
+ the compilation config can be individually overridden in the language configuration.""",
220
+ )
172
221
 
173
- # Configuration for each language supported in this environment.
174
- languages: List[EnvironmentLanguage] = []
222
+ defaultExecution: Optional[ExecutionConfig] = Field(
223
+ default=None,
224
+ description="""Default execution configuration to use when running programs. Fields in the
225
+ execution config can be individually overridden in the language configuration.""",
226
+ )
175
227
 
176
- # Identifier of the sandbox used by this environment (e.g. "stupid", "isolate")
177
- sandbox: str = 'stupid'
228
+ languages: List[EnvironmentLanguage] = Field(
229
+ default=[],
230
+ description="""Configuration for each language supported in this environment.""",
231
+ )
178
232
 
179
- # Identifier of the preset that should be used when creating new problems.
180
- preset: str = 'default'
233
+ sandbox: str = Field(
234
+ default='stupid',
235
+ description="""Identifier of the sandbox used by this environment (e.g. "stupid", "isolate")""",
236
+ )
181
237
 
182
- # Timing configuration for the environment.
183
- timing: TimingConfig = Field(default_factory=TimingConfig)
238
+ timing: TimingConfig = Field(
239
+ default_factory=TimingConfig,
240
+ description="""Timing configuration for the environment.""",
241
+ )
184
242
 
185
- # Extensions to be added to the environment.
186
- extensions: Optional[Extensions] = None
243
+ extensions: Optional[Extensions] = Field(
244
+ default=None,
245
+ description="""Extensions to be added to the environment.""",
246
+ )
187
247
 
188
248
 
189
249
  def get_app_environment_path(env: str) -> pathlib.Path:
rbx/box/formatting.py CHANGED
@@ -2,6 +2,7 @@ import os
2
2
  import pathlib
3
3
  from typing import Any, Optional
4
4
 
5
+ from rbx import utils
5
6
  from rbx.box import setter_config
6
7
 
7
8
 
@@ -23,7 +24,7 @@ def href(url: os.PathLike[str], text: Optional[str] = None, style: str = 'item')
23
24
  return f'[{style}]{text}[/{style}]'
24
25
 
25
26
  if isinstance(url, pathlib.Path):
26
- url = url.resolve()
27
+ url = utils.abspath(url)
27
28
 
28
29
  url_str = str(url)
29
30
  if pathlib.Path(url_str).exists():
rbx/box/package.py CHANGED
@@ -39,7 +39,7 @@ TEMP_DIR = None
39
39
 
40
40
  @functools.cache
41
41
  def find_problem_yaml(root: pathlib.Path = pathlib.Path()) -> Optional[pathlib.Path]:
42
- root = root.resolve()
42
+ root = utils.abspath(root)
43
43
  problem_yaml_path = root / YAML_NAME
44
44
  while root != pathlib.PosixPath('/') and not problem_yaml_path.is_file():
45
45
  root = root.parent
@@ -152,8 +152,8 @@ def get_problem_iruns_dir(root: pathlib.Path = pathlib.Path()) -> pathlib.Path:
152
152
  def get_problem_preprocessed_path(
153
153
  item: pathlib.Path, root: pathlib.Path = pathlib.Path()
154
154
  ) -> pathlib.Path:
155
- root_resolved = root.resolve()
156
- item_resolved = item.resolve()
155
+ root_resolved = utils.abspath(root)
156
+ item_resolved = utils.abspath(item)
157
157
 
158
158
  if not item_resolved.is_relative_to(root_resolved):
159
159
  final_path = pathlib.Path('remote') / item_resolved.name
@@ -360,11 +360,11 @@ def get_test_groups_by_name(
360
360
  # Return each compilation file and to where it should be moved inside
361
361
  # the sandbox.
362
362
  def get_compilation_files(code: CodeItem) -> List[Tuple[pathlib.Path, pathlib.Path]]:
363
- code_dir = code.path.parent.resolve()
363
+ code_dir = utils.abspath(code.path.parent)
364
364
 
365
365
  res = []
366
366
  for compilation_file in code.compilationFiles or []:
367
- compilation_file_path = pathlib.Path(compilation_file).resolve()
367
+ compilation_file_path = utils.abspath(pathlib.Path(compilation_file))
368
368
  if not compilation_file_path.is_file():
369
369
  console.console.print(
370
370
  f'[error]Compilation file [item]{compilation_file}[/item] for '
File without changes
File without changes
@@ -4,7 +4,7 @@ from typing import List, Optional
4
4
 
5
5
  import typer
6
6
 
7
- from rbx import console
7
+ from rbx import console, utils
8
8
  from rbx.box import header, package
9
9
  from rbx.box.lang import code_to_langs, is_valid_lang_code
10
10
  from rbx.box.packaging.packager import (
@@ -129,7 +129,7 @@ class PolygonPackager(BasePackager):
129
129
  shutil.copyfile(built_statement.path, final_path)
130
130
 
131
131
  return polygon_schema.Statement(
132
- path=str(final_path.resolve().relative_to(into_path.resolve())),
132
+ path=str(utils.abspath(final_path).relative_to(utils.abspath(into_path))),
133
133
  language=language,
134
134
  type=self._statement_application_type(built_statement), # type: ignore
135
135
  )
@@ -238,7 +238,7 @@ class PolygonContestPackager(BaseContestPackager):
238
238
  shutil.copyfile(built_statement.path, final_path)
239
239
 
240
240
  return polygon_schema.Statement(
241
- path=str(final_path.resolve().relative_to(into_path.resolve())),
241
+ path=str(utils.abspath(final_path).relative_to(utils.abspath(into_path))),
242
242
  language=language,
243
243
  type='application/pdf', # type: ignore
244
244
  )