rbx.cp 0.5.39__py3-none-any.whl → 0.5.40__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/box/checkers.py CHANGED
@@ -17,11 +17,15 @@ from rbx.grading.steps import (
17
17
  Outcome,
18
18
  RunLog,
19
19
  )
20
+ from rbx.utils import StatusProgress
20
21
 
21
22
 
22
- def compile_checker() -> str:
23
+ def compile_checker(progress: Optional[StatusProgress] = None) -> str:
23
24
  checker = package.get_checker()
24
25
 
26
+ if progress:
27
+ progress.update('Compiling checker...')
28
+
25
29
  try:
26
30
  digest = compile_item(checker, sanitized=SanitizationLevel.PREFER)
27
31
  except Exception as e:
rbx/box/main.py CHANGED
@@ -741,6 +741,18 @@ def validate(
741
741
  validators.print_validation_report([info])
742
742
 
743
743
 
744
+ @app.command(
745
+ 'unit',
746
+ rich_help_panel='Testing',
747
+ help='Run unit tests for the validator and checker.',
748
+ )
749
+ def unit_tests():
750
+ from rbx.box import unit
751
+
752
+ with utils.StatusProgress('Running unit tests...') as s:
753
+ unit.run_unit_tests(s)
754
+
755
+
744
756
  @app.command(
745
757
  'environment, env',
746
758
  rich_help_panel='Configuration',
rbx/box/packaging/main.py CHANGED
@@ -70,3 +70,12 @@ def boca(
70
70
  from rbx.box.packaging.boca.packager import BocaPackager
71
71
 
72
72
  run_packager(BocaPackager, verification=verification)
73
+
74
+
75
+ @app.command('moj', help='Build a package for MOJ.')
76
+ def moj(
77
+ verification: environment.VerificationParam,
78
+ ):
79
+ from rbx.box.packaging.moj.packager import MojPackager
80
+
81
+ run_packager(MojPackager, verification=verification)
@@ -0,0 +1,125 @@
1
+ import pathlib
2
+ import shutil
3
+ from typing import List
4
+
5
+ import typer
6
+
7
+ from rbx import console
8
+ from rbx.box import package
9
+ from rbx.box.environment import get_extension_or_default
10
+ from rbx.box.packaging.boca.extension import BocaExtension
11
+ from rbx.box.packaging.boca.packager import BocaPackager
12
+ from rbx.box.packaging.packager import BuiltStatement
13
+ from rbx.config import get_default_app_path
14
+ from rbx.grading.judge.digester import digest_cooperatively
15
+
16
+
17
+ class MojPackager(BocaPackager):
18
+ def _get_problem_info(self) -> str:
19
+ statement = self._get_main_statement()
20
+ return (
21
+ f'basename={self._get_problem_name()}\n'
22
+ f'fullname={statement.title}\n'
23
+ f'descfile={self._get_problem_name()}.pdf\n'
24
+ )
25
+
26
+ def _get_limits(self) -> str:
27
+ extension = get_extension_or_default('boca', BocaExtension)
28
+
29
+ pkg = package.find_problem_package_or_die()
30
+ tl = pkg.timeLimit
31
+ ml = pkg.memoryLimit
32
+ ol = pkg.outputLimit
33
+ conf = f'ULIMITS[-f]={ol}\n' f'ULIMITS[-v]={ml}\n' f'TL[default]={tl / 1000}\n'
34
+ for language in extension.languages:
35
+ conf += f'TL[{language}]={self._get_pkg_timelimit(language) / 1000}\n'
36
+ return conf
37
+
38
+ def _get_compare(self) -> str:
39
+ extension = get_extension_or_default('boca', BocaExtension)
40
+
41
+ compare_path = (
42
+ get_default_app_path() / 'packagers' / 'moj' / 'scripts' / 'compare.sh'
43
+ )
44
+ if not compare_path.exists():
45
+ console.console.print(
46
+ '[error]MOJ template compare script not found.[/error]'
47
+ )
48
+ raise typer.Exit(1)
49
+ with package.get_checker().path.open('rb') as f:
50
+ checker_hash = digest_cooperatively(f)
51
+ return (
52
+ compare_path.read_text()
53
+ .replace('{{rbxFlags}}', extension.flags_with_defaults()['cc'])
54
+ .replace('{{checkerHash}}', checker_hash)
55
+ )
56
+
57
+ def _get_checker(self) -> str:
58
+ return package.get_checker().path.read_text()
59
+
60
+ def name(self) -> str:
61
+ return 'moj'
62
+
63
+ def package(
64
+ self,
65
+ build_path: pathlib.Path,
66
+ into_path: pathlib.Path,
67
+ built_statements: List[BuiltStatement],
68
+ ) -> pathlib.Path:
69
+ # Prepare dummy files
70
+ author_path = into_path / 'author'
71
+ author_path.parent.mkdir(parents=True, exist_ok=True)
72
+ author_path.write_text('Unknown\n')
73
+
74
+ tags_path = into_path / 'tags'
75
+ tags_path.parent.mkdir(parents=True, exist_ok=True)
76
+ tags_path.write_text('')
77
+
78
+ # Prepare limits
79
+ limits_path = into_path / 'conf'
80
+ limits_path.parent.mkdir(parents=True, exist_ok=True)
81
+ limits_path.write_text(self._get_limits())
82
+
83
+ # Prepare compare
84
+ compare_path = into_path / 'scripts' / 'compare.sh'
85
+ compare_path.parent.mkdir(parents=True, exist_ok=True)
86
+ compare_path.write_text(self._get_compare())
87
+
88
+ # Prepare checker
89
+ checker_path = into_path / 'scripts' / 'checker.cpp'
90
+ checker_path.parent.mkdir(parents=True, exist_ok=True)
91
+ checker_path.write_text(self._get_checker())
92
+
93
+ # Problem statement
94
+ enunciado_path = into_path / 'docs' / 'enunciado.pdf'
95
+ enunciado_path.parent.mkdir(parents=True, exist_ok=True)
96
+ shutil.copyfile(
97
+ self._get_main_built_statement(built_statements).path,
98
+ enunciado_path,
99
+ )
100
+
101
+ # Copy solutions
102
+ solutions_path = into_path / 'solutions'
103
+ solutions_path.mkdir(parents=True, exist_ok=True)
104
+ self._copy_solutions(solutions_path)
105
+
106
+ # Prepare IO
107
+ inputs_path = into_path / 'tests' / 'input'
108
+ inputs_path.mkdir(parents=True, exist_ok=True)
109
+ outputs_path = into_path / 'tests' / 'output'
110
+ outputs_path.mkdir(parents=True, exist_ok=True)
111
+
112
+ testcases = self.get_flattened_built_testcases()
113
+ for i, testcase in enumerate(testcases):
114
+ shutil.copyfile(testcase.inputPath, inputs_path / f'{i+1:03d}')
115
+ if testcase.outputPath is not None:
116
+ shutil.copyfile(testcase.outputPath, outputs_path / f'{i+1:03d}')
117
+ else:
118
+ (outputs_path / f'{i+1:03d}').touch()
119
+
120
+ # Zip all.
121
+ shutil.make_archive(
122
+ str(build_path / self._get_problem_name()), 'zip', into_path
123
+ )
124
+
125
+ return (build_path / self._get_problem_name()).with_suffix('.zip')
rbx/box/schema.py CHANGED
@@ -148,6 +148,14 @@ class ExpectedOutcome(AutoEnum):
148
148
  return bool(set(self.get_matches()) & set(rhs.get_matches()))
149
149
 
150
150
 
151
+ class ValidatorOutcome(AutoEnum):
152
+ VALID = alias('valid') # type: ignore
153
+ """Expected outcome for valid tests."""
154
+
155
+ INVALID = alias('invalid') # type: ignore
156
+ """Expected outcome for invalid tests."""
157
+
158
+
151
159
  class CodeItem(BaseModel):
152
160
  model_config = ConfigDict(extra='forbid')
153
161
 
@@ -337,6 +345,59 @@ class LimitModifiers(BaseModel):
337
345
  )
338
346
 
339
347
 
348
+ class ValidatorTest(BaseModel):
349
+ model_config = ConfigDict(extra='forbid')
350
+
351
+ input: pathlib.Path = Field(
352
+ description='The input file to be used as unit test input for the validator.'
353
+ )
354
+ outcome: ValidatorOutcome = Field(
355
+ default=ValidatorOutcome.VALID,
356
+ description='The expected outcome of the validator.',
357
+ )
358
+
359
+ validator: Optional[CodeItem] = Field(
360
+ default=None,
361
+ description='The validator to use for this test. If not specified, will use the package-level validator.',
362
+ )
363
+
364
+
365
+ class CheckerTest(BaseModel):
366
+ model_config = ConfigDict(extra='forbid')
367
+
368
+ input: Optional[pathlib.Path] = Field(
369
+ default=None,
370
+ description='The input file to be used as unit test input for the checker. If not specified, will pass an empty file.',
371
+ )
372
+ output: Optional[pathlib.Path] = Field(
373
+ default=None,
374
+ description='The solution output file to be used as unit test output for the checker. If not specified, will pass an empty file.',
375
+ )
376
+ answer: Optional[pathlib.Path] = Field(
377
+ default=None,
378
+ description='The answer file to be used as unit test answer for the checker. If not specified, will pass an empty file.',
379
+ )
380
+
381
+ outcome: ExpectedOutcome = Field(
382
+ default=ExpectedOutcome.ACCEPTED,
383
+ description='The expected outcome of the checker.',
384
+ )
385
+
386
+
387
+ class UnitTests(BaseModel):
388
+ model_config = ConfigDict(extra='forbid')
389
+
390
+ validator: List[ValidatorTest] = Field(
391
+ default=[],
392
+ description='Unit tests for the validator.',
393
+ )
394
+
395
+ checker: List[CheckerTest] = Field(
396
+ default=[],
397
+ description='Unit tests for the checker.',
398
+ )
399
+
400
+
340
401
  class Package(BaseModel):
341
402
  model_config = ConfigDict(extra='forbid')
342
403
 
@@ -399,6 +460,11 @@ that is correct and used as reference -- and should have the `accepted` outcome.
399
460
  default={}, description='Variables to be re-used across the package.'
400
461
  )
401
462
 
463
+ unitTests: UnitTests = Field(
464
+ default_factory=UnitTests,
465
+ description='Unit tests for components of this problem.',
466
+ )
467
+
402
468
  @property
403
469
  def expanded_vars(self) -> Dict[str, Primitive]:
404
470
  return {key: expand_var(value) for key, value in self.vars.items()}
rbx/box/unit.py ADDED
@@ -0,0 +1,113 @@
1
+ from typing import List, Optional
2
+
3
+ from rbx import console
4
+ from rbx.box import checkers, package, validators
5
+ from rbx.box.schema import CodeItem, Testcase, ValidatorOutcome, ValidatorTest
6
+ from rbx.utils import StatusProgress
7
+
8
+
9
+ def _get_validator_for_test(test: ValidatorTest) -> Optional[CodeItem]:
10
+ pkg = package.find_problem_package_or_die()
11
+ if test.validator is not None:
12
+ return test.validator
13
+ return pkg.validator
14
+
15
+
16
+ def run_validator_unit_tests(progress: StatusProgress):
17
+ pkg = package.find_problem_package_or_die()
18
+
19
+ vals: List[CodeItem] = []
20
+ for test in pkg.unitTests.validator:
21
+ val = _get_validator_for_test(test)
22
+ if val is not None:
23
+ vals.append(val)
24
+
25
+ compiled_validators = validators.compile_validators(vals, progress=progress)
26
+
27
+ if progress:
28
+ progress.update('Running validator unit tests...')
29
+
30
+ console.console.rule('Validator tests', style='info')
31
+
32
+ for i, test in enumerate(pkg.unitTests.validator):
33
+ val = _get_validator_for_test(test)
34
+ if val is None:
35
+ console.console.print(
36
+ f'[warning]No validator found for test [item]#{i + 1}[/item], skipping.[/warning]'
37
+ )
38
+ continue
39
+
40
+ compiled_digest = compiled_validators[str(val.path)]
41
+ info = validators.validate_one_off(
42
+ test.input,
43
+ val,
44
+ compiled_digest,
45
+ )
46
+
47
+ is_valid = test.outcome == ValidatorOutcome.VALID
48
+
49
+ markup = (
50
+ '[success]OK[/success]' if info.ok == is_valid else '[error]FAIL[/error]'
51
+ )
52
+
53
+ console.console.print(
54
+ f'{markup} Unit test [item]#{i + 1}[/item] for [item]{test.input}[/item]'
55
+ )
56
+ console.console.print(f' [status]Expected[/status] {test.outcome.value}')
57
+ if info.ok != is_valid:
58
+ if info.ok:
59
+ console.console.print(' [status]Actual[/status] VALID')
60
+ else:
61
+ console.console.print(f' [status]Actual[/status] {info.message}')
62
+
63
+
64
+ def run_checker_unit_tests(progress: StatusProgress):
65
+ pkg = package.find_problem_package_or_die()
66
+ if not pkg.unitTests.checker:
67
+ return
68
+
69
+ if not package.get_checker():
70
+ console.console.print(
71
+ '[warning]No checker found, skipping checker unit tests.[/warning]'
72
+ )
73
+ return
74
+
75
+ compiled_digest = checkers.compile_checker(progress=progress)
76
+
77
+ if progress:
78
+ progress.update('Running checker unit tests...')
79
+
80
+ console.console.rule('Checker tests', style='info')
81
+
82
+ empty_file = package.get_empty_sentinel_path()
83
+
84
+ for i, test in enumerate(pkg.unitTests.checker):
85
+ result = checkers.check(
86
+ compiled_digest,
87
+ run_log=None,
88
+ testcase=Testcase(
89
+ inputPath=test.input or empty_file,
90
+ outputPath=test.answer or empty_file,
91
+ ),
92
+ program_output=test.output or empty_file,
93
+ skip_run_log=True,
94
+ )
95
+
96
+ markup = (
97
+ '[success]OK[/success]'
98
+ if test.outcome.match(result.outcome)
99
+ else '[error]FAIL[/error]'
100
+ )
101
+
102
+ console.console.print(f'{markup} Unit test [item]#{i + 1}[/item]')
103
+ console.console.print(f' [status]Expected[/status] {test.outcome.name}')
104
+
105
+ if not test.outcome.match(result.outcome):
106
+ console.console.print(f' [status]Actual[/status] {result.outcome.name}')
107
+ if result.message:
108
+ console.console.print(f' [status]Message[/status] {result.message}')
109
+
110
+
111
+ def run_unit_tests(progress: StatusProgress):
112
+ run_validator_unit_tests(progress)
113
+ run_checker_unit_tests(progress)
rbx/box/validators.py CHANGED
@@ -177,15 +177,10 @@ def validate_one_off(
177
177
 
178
178
 
179
179
  def compile_validators(
180
- validation_entries: List[GenerationTestcaseEntry],
180
+ validators: List[CodeItem],
181
181
  progress: Optional[StatusProgress] = None,
182
182
  ) -> Dict[str, str]:
183
- validators = []
184
-
185
- for entry in validation_entries:
186
- if entry.validator is not None:
187
- validators.append(entry.validator)
188
- validators.extend(entry.extra_validators)
183
+ validator_to_compiled_digest = {}
189
184
 
190
185
  validator_to_compiled_digest = {}
191
186
 
@@ -202,6 +197,20 @@ def compile_validators(
202
197
  return validator_to_compiled_digest
203
198
 
204
199
 
200
+ def compile_validators_for_entries(
201
+ validation_entries: List[GenerationTestcaseEntry],
202
+ progress: Optional[StatusProgress] = None,
203
+ ) -> Dict[str, str]:
204
+ validators = []
205
+
206
+ for entry in validation_entries:
207
+ if entry.validator is not None:
208
+ validators.append(entry.validator)
209
+ validators.extend(entry.extra_validators)
210
+
211
+ return compile_validators(validators, progress=progress)
212
+
213
+
205
214
  def validate_testcases(
206
215
  progress: Optional[StatusProgress] = None,
207
216
  groups: Optional[Set[str]] = None,
@@ -211,7 +220,7 @@ def validate_testcases(
211
220
  progress.step()
212
221
 
213
222
  validation_entries = extract_generation_testcases_from_groups(groups)
214
- validator_to_compiled_digest = compile_validators(
223
+ validator_to_compiled_digest = compile_validators_for_entries(
215
224
  validation_entries, progress=progress
216
225
  )
217
226
 
@@ -0,0 +1,82 @@
1
+ #!/bin/bash
2
+ # ////////////////////////////////////////////////////////////////////////////////
3
+ # //BOCA Online Contest Administrator
4
+ # // Copyright (C) 2003-2012 by BOCA Development Team (bocasystem@gmail.com)
5
+ # //
6
+ # // This program is free software: you can redistribute it and/or modify
7
+ # // it under the terms of the GNU General Public License as published by
8
+ # // the Free Software Foundation, either version 3 of the License, or
9
+ # // (at your option) any later version.
10
+ # //
11
+ # // This program is distributed in the hope that it will be useful,
12
+ # // but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # // GNU General Public License for more details.
15
+ # // You should have received a copy of the GNU General Public License
16
+ # // along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ # ////////////////////////////////////////////////////////////////////////////////
18
+ # // Last modified 21/jul/2012 by cassio@ime.usp.br
19
+ #
20
+ # This script receives:
21
+ # $1 team_output
22
+ # $2 sol_output
23
+ # $3 problem_input (might be used by some specific checkers, here it is not)
24
+ #
25
+ # BOCA reads the last line of the standard output
26
+ # and pass it to judges
27
+ #
28
+ if [ ! -r "$1" -o ! -r "$2" ]; then
29
+ echo "Parameter problem"
30
+ exit 43
31
+ fi
32
+
33
+ CHECKERSOURCE=$(dirname "$0")/checker.cpp
34
+
35
+ if [ ! -r "$CHECKERSOURCE" ]; then
36
+ echo "Checker source not found"
37
+ exit 47
38
+ fi
39
+
40
+ CHECKERHASH={{checkerHash}}
41
+ CHECKERPATH=/tmp/boca-chk/$CHECKERHASH
42
+
43
+ compile_checker() {
44
+ mkdir -p /tmp/boca-chk
45
+
46
+ cc=$(which g++)
47
+ [ -x "$cc" ] || cc=/usr/bin/g++
48
+ if [ ! -x "$cc" ]; then
49
+ echo "$cc not found or it's not executable"
50
+ exit 47
51
+ fi
52
+
53
+ $cc {{rbxFlags}} $CHECKERSOURCE -o $CHECKERPATH
54
+
55
+ chmod 0755 "$CHECKERPATH"
56
+ }
57
+
58
+ if [ ! -x "$CHECKERPATH" ]; then
59
+ compile_checker
60
+ fi
61
+
62
+ # Next lines of this script just compares team_output and sol_output,
63
+ # although it is possible to change them to more complex evaluations.
64
+ output=$($CHECKERPATH $3 $1 $2 2>&1 >/dev/null)
65
+ EC=$?
66
+
67
+ echo "checker exitcode = $EC"
68
+ echo "$output"
69
+
70
+ if [ $EC -eq 0 ]; then
71
+ echo "checker found no differences"
72
+ exit 4
73
+ elif [ $EC -eq 1 ]; then
74
+ echo "checker found differences"
75
+ exit 6
76
+ elif [ $EC -eq 2 ]; then
77
+ echo "checker failed"
78
+ exit 5
79
+ elif [ $EC -ne 3 ]; then
80
+ echo "unkown compare error $EC"
81
+ exit 43
82
+ fi
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rbx.cp
3
- Version: 0.5.39
3
+ Version: 0.5.40
4
4
  Summary:
5
5
  Author: Roberto Sales
6
6
  Requires-Python: >=3.9,<4.0
@@ -4,7 +4,7 @@ rbx/autoenum.py,sha256=cusv8ClXRlDVvhZ8eDrtYcL_2peXlHugAey_ht8roXk,12025
4
4
  rbx/box/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  rbx/box/builder.py,sha256=qIXgV-div21Tw8knwCrTtHyDCgYwBrJc0I5b9KhZuKM,3577
6
6
  rbx/box/cd.py,sha256=9a_SOnzoJBXxxffp4Wbf3UKXIwKuN3Hvj7K6SocALwE,1194
7
- rbx/box/checkers.py,sha256=VpgDzevOK7hrffG2zJGxquNiu-a9Fl3wquLn7xadcK0,6285
7
+ rbx/box/checkers.py,sha256=lB0Lx-8xwbtmgzGxQ0Y0Z3v-QUNmy1wOhHI31h43Jkw,6429
8
8
  rbx/box/code.py,sha256=zkYWHXV4PxuAm3_4VtW9fptLQ34euI8BTAKNukXWCig,13437
9
9
  rbx/box/compile.py,sha256=OJLthDQ921w9vyoE6Gk1Df54i5RwtRJ2YG-8XEfefcs,2489
10
10
  rbx/box/conftest.py,sha256=sEmciXSeDC-wmrZ1JSxbsUenKNP_VWW32mrCun2pY3I,1070
@@ -25,12 +25,13 @@ rbx/box/generators.py,sha256=6hm1G4BHmq6Nmbbm2aXHewgVntEjQ5HJtPu6z-sTVrY,12163
25
25
  rbx/box/generators_test.py,sha256=ZRqdolU7YE8HXjxr0met5oGn4DCJ5erdsMt5cSOoXIw,1945
26
26
  rbx/box/lazy_importing_main.py,sha256=6Z8As7qVFFT619xHH9Xt8VCH57NjC4aDxfAgkWiUwT8,116
27
27
  rbx/box/lazy_importing_test.py,sha256=B0-b3y_DkxEmtVfu4NfmVsgVdFl6kRCsEL6GLMHJISo,628
28
- rbx/box/main.py,sha256=fvT4tslHFKOvOebcukrhKc4-E1OT4hkvlObuzGuOJ4I,25975
28
+ rbx/box/main.py,sha256=vfFAN6XVSHGsIiiPhTAIZVbnBs3TstuswptZAqqbqHs,26234
29
29
  rbx/box/package.py,sha256=80SDHvSzfraCUYutMn_kwsFsmmrSZiaeRHhhrWGmIY4,12081
30
30
  rbx/box/packaging/boca/extension.py,sha256=hQhcbocNfW2ESv5RalS1wf6uvOoOfOnR_gHvbXUbSzY,852
31
31
  rbx/box/packaging/boca/packager.py,sha256=FOhSRg5K5Y4qNB0WyTR3DKgrpObf9I0JbyGpJHOtxpo,10673
32
32
  rbx/box/packaging/contest_main.py,sha256=nMdgPE4OK_tsnUMdRI1cJwLpgxGrwW_mJjox0oOALWw,2757
33
- rbx/box/packaging/main.py,sha256=xd6nohKwkKH1ltyVO_uWwydlx47NkJOpkuTtIk46GVw,2271
33
+ rbx/box/packaging/main.py,sha256=DC6t1OPObhqmnGRjDpS1tLi7a5HuBKMvxbrVpS6n2oA,2504
34
+ rbx/box/packaging/moj/packager.py,sha256=SzCskP3VmVsTGxexe_uvG1aDo379UfjMShNtH3l4xzw,4452
34
35
  rbx/box/packaging/packager.py,sha256=suCT_SLnWa915rV2j8VFqzH43HGKRTr9mGGlrvj45aw,3267
35
36
  rbx/box/packaging/polygon/packager.py,sha256=HNpxP2nclLChSnrQtkT7tLwDdXHl1dzXMIF5RZwr9M4,10811
36
37
  rbx/box/packaging/polygon/test.py,sha256=bgEju5PwudgyfwxXJagm8fM6CJVlWM6l_-2q1V-oKaQ,3069
@@ -41,7 +42,7 @@ rbx/box/presets/lock_schema.py,sha256=6sRPnyePOC8yy-5WcD5JRZdDJHf8loqbvpQ1IPiOU9
41
42
  rbx/box/presets/schema.py,sha256=mZmSPkQsw7eQM0lQN6er1MO_LiW1ObwwAZFDK0F5fxE,1962
42
43
  rbx/box/retries.py,sha256=z7cIh1QmLVUsTr3Attt_28dbwNg6KWTwpulcWCFwMPo,4667
43
44
  rbx/box/sanitizers/warning_stack.py,sha256=RI97_GJgdjTKIXY_r0EKp5h0qQQSDSdNDh5K7zINrqs,2861
44
- rbx/box/schema.py,sha256=I7Uh_KXBqAX8fHZr4s9LGPEFHxyBttoLSq_hYJefwto,14581
45
+ rbx/box/schema.py,sha256=wl0kPYovG4X6vG4uiGOrPFp3udYHwidd2f8dxIGw7DY,16636
45
46
  rbx/box/setter_config.py,sha256=s53talhwM6FTGDCcBhY7IlZ6_6mJ3PMp6V4kTtaSs50,4262
46
47
  rbx/box/solutions.py,sha256=IggS2QdOkHuz6G7i2eI32ILT7G5FZL0cy49xnPtAGb8,44818
47
48
  rbx/box/solutions_test.py,sha256=txjAg-n_pkHHolw4WF4foBrpJAL-llAXw6fUIrGURMc,1716
@@ -66,7 +67,8 @@ rbx/box/ui/captured_log.py,sha256=ptICDPViVnz-_2NfrcB0SSBXNW5L74zI-vAZNN7kSok,11
66
67
  rbx/box/ui/css/app.tcss,sha256=apd5PkPEvl5jK3kE2qrxPyVED1VnvSsj08QQwzUPwEA,786
67
68
  rbx/box/ui/main.py,sha256=b0rHcBF42W4AOCv7WhtiGf_rUnY0yxpqO5oj3wfR4R4,984
68
69
  rbx/box/ui/run.py,sha256=wMEXrEFdQvMHz2hRKAFIithTnTtaL0kNQZu0jKmb8jI,7060
69
- rbx/box/validators.py,sha256=WX6PR-eVXm9ghv0cJYYhoe9eyQJDZrkXoK6p_Ya_BY0,10106
70
+ rbx/box/unit.py,sha256=hkgsLf-vyIdOKY1bFELfCXFzp6sMIO0_t0ZSOvv8IcU,3685
71
+ rbx/box/validators.py,sha256=eOmflDiIs7IiNa9KnlQ4QqtyTFWL3IAGI-Q5VMiFM2I,10356
70
72
  rbx/box/validators_test.py,sha256=hriR6rD32Ouu64eKYYTPLZVvqMxXj7Q2h1l_JAefL7U,344
71
73
  rbx/checker.py,sha256=pj1jO3my48ru-qugbER5onccANCjoR0-PaFe3H3VGEY,4118
72
74
  rbx/clone.py,sha256=wpHyED0_7ST7LD3vj7HjXhzqEzlwh6dRQvKQVDYhGeU,6744
@@ -122,6 +124,7 @@ rbx/resources/packagers/boca/run/java,sha256=raJu_-wdc-KTvWgFoQsW2Zxp70PoLvitSyi
122
124
  rbx/resources/packagers/boca/run/kt,sha256=D1KbwscStaawlesXgQICP2oRaXBevO4XcUd8RrT0whk,4655
123
125
  rbx/resources/packagers/boca/run/py2,sha256=6xjPmoIEblvbM5k9Gm_fwxU-RmrihMX9j3LSUMyXws4,4908
124
126
  rbx/resources/packagers/boca/run/py3,sha256=-TRTRMBiiIhVz5EAfXM_3IKC8u49VUHSfyHbWWiW5-w,4908
127
+ rbx/resources/packagers/moj/scripts/compare.sh,sha256=UCYU7hVm8JADbvYLIQTWr6sP9zyIq9eMJ7LA5o59xN4,2370
125
128
  rbx/resources/presets/default/contest/contest.rbx.yml,sha256=aThSvWG0Nv4BKoucQG6Q0KpS20hsT46BHyVCQTdvtUM,424
126
129
  rbx/resources/presets/default/contest/statement/contest.rbx.tex,sha256=3YDQo5c-SGbwXcd4uytyY_Mc7UriAditgdJnbN8UdHg,3062
127
130
  rbx/resources/presets/default/contest/statement/olymp.sty,sha256=k4TCQz1IeXV75oZ2_dcWEQ3ziTDegOEdnYn4Xb4vzsU,6766
@@ -170,8 +173,8 @@ rbx/testdata/caching/executable.py,sha256=WKRHNf_fprFJd1Fq1ubmQtR3mZzTYVNwKPLWuZ
170
173
  rbx/testdata/compatible,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
171
174
  rbx/testing_utils.py,sha256=ZXMysGXpTtvS1lfLL38FuD5iSIyxi3ARjQePDrUmEtc,2067
172
175
  rbx/utils.py,sha256=6e1eXRzNE-52D0UVtqclePxqR4Haiqt8qWCrSVjnGuE,4585
173
- rbx_cp-0.5.39.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
174
- rbx_cp-0.5.39.dist-info/METADATA,sha256=Rwolc3QtBp6a9xSnOTeCjDO_yLy4JTB9CG5IAL2GTFE,3263
175
- rbx_cp-0.5.39.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
176
- rbx_cp-0.5.39.dist-info/entry_points.txt,sha256=qBTLBOeifT1F00LWaEewRRE_jQPgvH7BUdJfZ-dYsFU,57
177
- rbx_cp-0.5.39.dist-info/RECORD,,
176
+ rbx_cp-0.5.40.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
177
+ rbx_cp-0.5.40.dist-info/METADATA,sha256=vDQjvdmQwfC4-wkoIO8FoyrZAJGVGw2Io5lxzuLuBu0,3263
178
+ rbx_cp-0.5.40.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
179
+ rbx_cp-0.5.40.dist-info/entry_points.txt,sha256=qBTLBOeifT1F00LWaEewRRE_jQPgvH7BUdJfZ-dYsFU,57
180
+ rbx_cp-0.5.40.dist-info/RECORD,,