rbx.cp 0.5.63__py3-none-any.whl → 0.5.64__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.
@@ -10,6 +10,7 @@ from rbx import console, testing_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
13
+ from rbx.box.formatting import href
13
14
  from rbx.box.schema import Package, Testcase
14
15
  from rbx.box.statements import build_statements
15
16
  from rbx.box.statements.build_statements import (
@@ -344,6 +345,6 @@ def build_statement(
344
345
  console.console.print(
345
346
  f'Statement built successfully for language '
346
347
  f'[item]{statement.language}[/item] at '
347
- f'[item]{statement_path.resolve()}[/item]'
348
+ f'{href(statement_path)}'
348
349
  )
349
350
  return statement_path
rbx/box/formatting.py CHANGED
@@ -1,3 +1,28 @@
1
+ import os
2
+ import pathlib
3
+ from typing import Optional
4
+
5
+ from rbx.box import setter_config
6
+
7
+
8
+ def href(url: os.PathLike[str], text: Optional[str] = None, style: str = 'item') -> str:
9
+ custom_text = False
10
+ if text is None:
11
+ text = str(url)
12
+ else:
13
+ custom_text = True
14
+
15
+ if not custom_text:
16
+ if not setter_config.get_setter_config().hyperlinks:
17
+ return f'[{style}]{text}[/{style}]'
18
+ if os.environ.get('TERM') in ['vscode']:
19
+ return f'[{style}]{text}[/{style}]'
20
+
21
+ if isinstance(url, pathlib.Path):
22
+ url = url.resolve()
23
+ return f'[{style}][link={url}]{text}[/link][/{style}]'
24
+
25
+
1
26
  def get_formatted_memory(memory_in_bytes: int, mib_decimal_places: int = 0) -> str:
2
27
  if memory_in_bytes < 1024 * 1024:
3
28
  if memory_in_bytes < 1024:
@@ -1,4 +1,5 @@
1
1
  import datetime
2
+ import functools
2
3
  import hashlib
3
4
  import os
4
5
  import pathlib
@@ -41,6 +42,8 @@ class BocaUploader:
41
42
  self.username = _parse_env_var('BOCA_USERNAME', username)
42
43
  self.password = _parse_env_var('BOCA_PASSWORD', password)
43
44
 
45
+ self.loggedIn = False
46
+
44
47
  self.br = mechanize.Browser()
45
48
  self.br.set_handle_robots(False)
46
49
  self.br.addheaders = [ # type: ignore
@@ -140,6 +143,9 @@ class BocaUploader:
140
143
  return self.log_response_alert(response, error_msg)
141
144
 
142
145
  def login(self):
146
+ if self.loggedIn:
147
+ return
148
+
143
149
  _, html = self.open(
144
150
  f'{self.base_url}', error_msg='Error while opening BOCA login page'
145
151
  )
@@ -157,6 +163,8 @@ class BocaUploader:
157
163
  login_url = f'{self.base_url}?name={self.username}&password={pwd_hash}'
158
164
  self.open(login_url, error_msg='Error while logging in to BOCA')
159
165
 
166
+ self.loggedIn = True
167
+
160
168
  def upload(self, file: pathlib.Path) -> bool:
161
169
  self.open(
162
170
  f'{self.base_url}/admin/problem.php',
@@ -226,6 +234,7 @@ class BocaUploader:
226
234
  console.console.print(
227
235
  f'[warning]Potentially transient error while uploading problem to BOCA. Retrying ({tries}/{RETRIES})...[/warning]'
228
236
  )
237
+ self.loggedIn = False
229
238
  continue
230
239
 
231
240
  ok = True
@@ -245,3 +254,12 @@ class BocaUploader:
245
254
  '[warning]Check [item]https://www.php.net/manual/en/ini.core.php#ini.sect.file-uploads[/item] for more information.[/warning]'
246
255
  )
247
256
  raise typer.Exit(1)
257
+
258
+
259
+ @functools.lru_cache
260
+ def get_boca_uploader(
261
+ base_url: Optional[str] = None,
262
+ username: Optional[str] = None,
263
+ password: Optional[str] = None,
264
+ ) -> BocaUploader:
265
+ return BocaUploader(base_url, username, password)
rbx/box/packaging/main.py CHANGED
@@ -7,6 +7,7 @@ import typer
7
7
 
8
8
  from rbx import annotations, console
9
9
  from rbx.box import environment, header, package
10
+ from rbx.box.formatting import href
10
11
  from rbx.box.naming import get_problem_name_with_contest_info
11
12
  from rbx.box.package import get_build_path
12
13
  from rbx.box.packaging.packager import BasePackager, BuiltStatement
@@ -62,7 +63,7 @@ async def run_packager(
62
63
  console.console.print(
63
64
  f'[success]Problem packaged for [item]{packager.name()}[/item]![/success]'
64
65
  )
65
- console.console.print(f'Package was saved at [item]{result_path.resolve()}[/item]')
66
+ console.console.print(f'Package was saved at {href(result_path)}')
66
67
  return result_path
67
68
 
68
69
 
@@ -105,9 +106,9 @@ async def boca(
105
106
  result_path = await run_packager(BocaPackager, verification=verification)
106
107
 
107
108
  if upload:
108
- from rbx.box.packaging.boca.upload import BocaUploader
109
+ from rbx.box.packaging.boca.upload import get_boca_uploader
109
110
 
110
- uploader = BocaUploader()
111
+ uploader = get_boca_uploader()
111
112
  uploader.login_and_upload(result_path)
112
113
 
113
114
 
rbx/box/setter_config.py CHANGED
@@ -71,6 +71,10 @@ class SetterConfig(BaseModel):
71
71
  default={},
72
72
  description='Substitutions to apply to commands before running them.',
73
73
  )
74
+ hyperlinks: bool = Field(
75
+ default=True,
76
+ description='Whether to use hyperlinks in the terminal output.',
77
+ )
74
78
 
75
79
  def substitute_command(self, command: str, sanitized: bool = False) -> str:
76
80
  exe = shlex.split(command)[0]
rbx/box/solutions.py CHANGED
@@ -26,7 +26,7 @@ from rbx.box.deferred import Deferred
26
26
  from rbx.box.environment import (
27
27
  VerificationLevel,
28
28
  )
29
- from rbx.box.formatting import get_formatted_memory, get_formatted_time
29
+ from rbx.box.formatting import get_formatted_memory, get_formatted_time, href
30
30
  from rbx.box.generators import (
31
31
  GenerationMetadata,
32
32
  expand_generator_call,
@@ -166,7 +166,7 @@ def compile_solutions(
166
166
  ):
167
167
  continue
168
168
  if progress:
169
- progress.update(f'Compiling solution [item]{solution.path}[/item]...')
169
+ progress.update(f'Compiling solution {href(solution.path)}...')
170
170
  try:
171
171
  compiled_solutions[solution.path] = compile_item(
172
172
  solution,
@@ -176,7 +176,7 @@ def compile_solutions(
176
176
  )
177
177
  except:
178
178
  console.console.print(
179
- f'[error]Failed compiling solution [item]{solution.path}[/item][/error]'
179
+ f'[error]Failed compiling solution {href(solution.path)}.[/error]'
180
180
  )
181
181
  raise
182
182
 
@@ -204,7 +204,7 @@ def _run_solution(
204
204
 
205
205
  if progress:
206
206
  progress.update(
207
- f'Running solution [item]{solution.path}[/item] on test [item]{group.name}[/item] / [item]{i}[/item]...'
207
+ f'Running solution {href(solution.path)} on test [item]{group.name}[/item] / [item]{i}[/item]...'
208
208
  )
209
209
 
210
210
  async def run_fn(i=i, testcase=testcase, output_path=output_path):
@@ -1026,8 +1026,8 @@ def _print_solution_header(
1026
1026
  solution: SolutionSkeleton,
1027
1027
  console: rich.console.Console,
1028
1028
  ):
1029
- console.print(f'[item]{solution.path}[/item]', end=' ')
1030
- console.print(f'({solution.runs_dir})')
1029
+ console.print(f'{href(solution.path)}', end=' ')
1030
+ console.print(f'({href(solution.runs_dir, style="info")})')
1031
1031
 
1032
1032
 
1033
1033
  @dataclasses.dataclass
@@ -1052,14 +1052,14 @@ class TimingSummary:
1052
1052
  def print(self, console: rich.console.Console, tl: Optional[int] = None):
1053
1053
  if self.slowest_good is not None:
1054
1054
  console.print(
1055
- f'Slowest [success]OK[/success] solution: {self.slowest_good.time} ms, [item]{self.slowest_good.solution.path}[/item]'
1055
+ f'Slowest [success]OK[/success] solution: {self.slowest_good.time} ms, {href(self.slowest_good.solution.path)}'
1056
1056
  )
1057
1057
  if self.fastest_slow is not None:
1058
1058
  fastest_slow = self.fastest_slow.time
1059
1059
  if tl is not None and self.fastest_slow.time > tl:
1060
1060
  fastest_slow = f'>{tl}'
1061
1061
  console.print(
1062
- f'Fastest [error]slow[/error] solution: {fastest_slow} ms, [item]{self.fastest_slow.solution.path}[/item]'
1062
+ f'Fastest [error]slow[/error] solution: {fastest_slow} ms, {href(self.fastest_slow.solution.path)}'
1063
1063
  )
1064
1064
 
1065
1065
 
@@ -1184,7 +1184,7 @@ async def _render_detailed_group_table(
1184
1184
  ) -> rich.table.Table:
1185
1185
  table = rich.table.Table()
1186
1186
  for solution in skeleton.solutions:
1187
- table.add_column(f'[item]{solution.path}[/item]', justify='full')
1187
+ table.add_column(f'{href(solution.path)}', justify='full')
1188
1188
 
1189
1189
  padded_rows = []
1190
1190
 
@@ -1424,7 +1424,7 @@ async def estimate_time_limit(
1424
1424
 
1425
1425
  if not timings:
1426
1426
  console.print(
1427
- f'[warning]No timings for solution [item]{solution.path}[/item].[/warning]'
1427
+ f'[warning]No timings for solution {href(solution.path)}.[/warning]'
1428
1428
  )
1429
1429
  continue
1430
1430
 
@@ -8,6 +8,7 @@ import typer
8
8
 
9
9
  from rbx import annotations, console
10
10
  from rbx.box import environment, naming, package
11
+ from rbx.box.formatting import href
11
12
  from rbx.box.schema import Package
12
13
  from rbx.box.statements.builders import (
13
14
  BUILDER_LIST,
@@ -302,7 +303,7 @@ def build_statement(
302
303
  console.console.print(
303
304
  f'Statement built successfully for language '
304
305
  f'[item]{statement.language}[/item] at '
305
- f'[item]{statement_path.resolve()}[/item]'
306
+ f'{href(statement_path)}'
306
307
  )
307
308
  return statement_path
308
309
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rbx.cp
3
- Version: 0.5.63
3
+ Version: 0.5.64
4
4
  Summary:
5
5
  Author: Roberto Sales
6
6
  Requires-Python: >=3.9,<4.0
@@ -10,7 +10,7 @@ rbx/box/code.py,sha256=2oC1JbZiwfeg53ZICPig-KJYchqFRIZz-inlM-cLc7Q,19911
10
10
  rbx/box/compile.py,sha256=OJLthDQ921w9vyoE6Gk1Df54i5RwtRJ2YG-8XEfefcs,2489
11
11
  rbx/box/conftest.py,sha256=sEmciXSeDC-wmrZ1JSxbsUenKNP_VWW32mrCun2pY3I,1070
12
12
  rbx/box/contest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- rbx/box/contest/build_contest_statements.py,sha256=H2MwmkiPO_cHUEenzfPxHuJ3XcwjHakGZwKojNJQt74,11380
13
+ rbx/box/contest/build_contest_statements.py,sha256=DtbzLShc8zzbjE-1sBFtPY3JGhSwm48q6eSOPYWSVxQ,11399
14
14
  rbx/box/contest/contest_package.py,sha256=OaUbpBtkhkgOPzJ1ccI_Vq4FMSaJvZm3gMOKfVY8oy4,3032
15
15
  rbx/box/contest/contest_utils.py,sha256=TDE7I6YQJlu4dQd68wzOp019bNgqiT0RlM-LMQMjL9w,301
16
16
  rbx/box/contest/main.py,sha256=u76kAQSVWEuyGLqVgyjXwYxJwHXAeEHMwbM7MfenKvE,7574
@@ -22,7 +22,7 @@ rbx/box/download.py,sha256=DxAiAk4lDYWEz1C9UTvZzHTq6hgm4fxGezApm2IkCTM,2601
22
22
  rbx/box/dump_schemas.py,sha256=3j5t47_vJmXj0BCczxDX6ByOcsfolGEDNCBXlPpk86w,593
23
23
  rbx/box/environment.py,sha256=Kp69MekUwwoVpupnafUcN5KAbP-ZTCwe0OQXt1h0FN8,11859
24
24
  rbx/box/extensions.py,sha256=Von8kIeXvNFTkGlMRMTvL2HIHPwlkuiMswr-ydbGV1w,519
25
- rbx/box/formatting.py,sha256=3phFRHzqVXj4Ok1yDhCq6Clbw6KlqwJNpMhs--oTWFI,405
25
+ rbx/box/formatting.py,sha256=csscjgWrTa6zjs2ueVCFRzA3WxdUFbzkzOxHWyQVerw,1049
26
26
  rbx/box/generators.py,sha256=RE0-D91BB-3rNDQXvCFWzU9iMhKIc_ALp960oGfM-rY,13780
27
27
  rbx/box/generators_test.py,sha256=J7aBfuJhU84MWDWzgReRoOuQw_hVa09B8gTKAvL2XVo,1987
28
28
  rbx/box/git_utils.py,sha256=VlUgzuHOCnrjjiJQnDB32qDHbHw_zkwgA7wm4bloibc,750
@@ -34,9 +34,9 @@ rbx/box/naming.py,sha256=pOG37X_wQM9CCSYwJIUf-b-ZHEs_nchO7wQEdP_quJg,1367
34
34
  rbx/box/package.py,sha256=pRsA5UsKNnD2uJcm8x01uQHUbCxoLbJvhoeqf3nyrew,14290
35
35
  rbx/box/packaging/boca/extension.py,sha256=EQALNEOv4zVDXSKs_dk11n92y7cBZVn8TogIK683lE0,890
36
36
  rbx/box/packaging/boca/packager.py,sha256=kiCcP9roRCiDU0Xr5PDKO83W1yN6cyg-EKMF9fxE0EY,11950
37
- rbx/box/packaging/boca/upload.py,sha256=ORJytNTZ5uZw9Tk2cEhXa9UItGloFmC5pytsZavP6V8,8871
37
+ rbx/box/packaging/boca/upload.py,sha256=y3DNMLNZyAwMdfBLUZRzxnr8cHwLegpH_NtgKW2Zwvw,9260
38
38
  rbx/box/packaging/contest_main.py,sha256=UsRfIdNmOf0iLUbzgjxzyECfMuCQINstG1SCClGHaUQ,2808
39
- rbx/box/packaging/main.py,sha256=b7DAotZkn1EO6_2cSHoGegMqHa4ZE3moWncGXkF7f3c,3797
39
+ rbx/box/packaging/main.py,sha256=kLFcMz0xOTZgtJh6P0Rr-zfq0NCbvx7HiQQ_0YmsvGg,3826
40
40
  rbx/box/packaging/moj/packager.py,sha256=FjghOe5CPlaF1GqK0NZgWVV_eYWpdTmz88bh04yeAyI,8708
41
41
  rbx/box/packaging/packager.py,sha256=da2haC1L9cG30myneMrRIAdGubtid0Xmy38BHKPCZZ4,3633
42
42
  rbx/box/packaging/polygon/packager.py,sha256=GfZ-Dc2TDKkb3QNnfOy8yxldho2L401Ao06oWg--Gcs,11714
@@ -51,12 +51,12 @@ rbx/box/presets/schema.py,sha256=mZmSPkQsw7eQM0lQN6er1MO_LiW1ObwwAZFDK0F5fxE,196
51
51
  rbx/box/retries.py,sha256=cZcNYLVHFDbhbeqMzxITgo8SYY8qzyxm0tIYcmWl1Ek,4877
52
52
  rbx/box/sanitizers/warning_stack.py,sha256=RI97_GJgdjTKIXY_r0EKp5h0qQQSDSdNDh5K7zINrqs,2861
53
53
  rbx/box/schema.py,sha256=y736-wZdGw56T6eDC_m7NAm2XRUdauBXJRQkQO79fpc,16264
54
- rbx/box/setter_config.py,sha256=s53talhwM6FTGDCcBhY7IlZ6_6mJ3PMp6V4kTtaSs50,4262
55
- rbx/box/solutions.py,sha256=tMG72QbdexEsfiw70Ryn6hcnXiiNbHIKMAZX0_6uYEY,49078
54
+ rbx/box/setter_config.py,sha256=9iObg6BwxQhFAhIOk31Jc0BDDpRYVGf3SyLIOsWIltM,4393
55
+ rbx/box/solutions.py,sha256=pQG_4HVpFds6C0gcxmvKr557s7IhYmLoYB_s_1GgtAI,49049
56
56
  rbx/box/solutions_test.py,sha256=PX1TQoRzNd9mi1SGsG7WFrpqFgNrNX5Kwt0mkwFdoOA,1749
57
57
  rbx/box/state.py,sha256=MMf3DvfQji0jKEliCHct2Tpp_0epL1tvP8HbHNArQIc,166
58
58
  rbx/box/statements/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
- rbx/box/statements/build_statements.py,sha256=6przkQWy70ixDbqWMZmBgncaoWg67RY1gPdQ4TPjaTE,12150
59
+ rbx/box/statements/build_statements.py,sha256=lu3mwm-ZID0N_t_6FIrCcMFjlqa5JR49PQ28dq2C3s8,12169
60
60
  rbx/box/statements/builders.py,sha256=6lYV-cnC-NXMnJf1wasbq_AMbjdIuPpMirm7QsjZI6s,11825
61
61
  rbx/box/statements/joiners.py,sha256=jItNXkAbTjFQpPMgfDMW86n3vMTbaE8sgo9I8Yf4Txg,2886
62
62
  rbx/box/statements/latex.py,sha256=LkcHwXjMFxbw--Gj9T1VkFKQFsXhY9dN7xZHpZycNW8,1346
@@ -212,8 +212,8 @@ rbx/testcase.py,sha256=yKOq3CAJZ1YTmInvnoIs0u1iJnRj_X85XiWbLI-p9d8,1951
212
212
  rbx/testcase_rendering.py,sha256=nfmv6dSEqd4aR3TsaODwkKGK6AXty_DDKtWf_ejiQpI,2084
213
213
  rbx/testing_utils.py,sha256=x_PqD8Zd2PkN91NxVHUnSTs044-1WK5KKtttKQBXpFs,2083
214
214
  rbx/utils.py,sha256=SfR844_i0ebRDMkmS_w1YdZiWPc6h2RGADygewlWRbA,4845
215
- rbx_cp-0.5.63.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
216
- rbx_cp-0.5.63.dist-info/METADATA,sha256=dgNReBRlMvN09iAcedaaGLwPJ69PEfhET7Ml9yaGwpo,3604
217
- rbx_cp-0.5.63.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
218
- rbx_cp-0.5.63.dist-info/entry_points.txt,sha256=qBTLBOeifT1F00LWaEewRRE_jQPgvH7BUdJfZ-dYsFU,57
219
- rbx_cp-0.5.63.dist-info/RECORD,,
215
+ rbx_cp-0.5.64.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
216
+ rbx_cp-0.5.64.dist-info/METADATA,sha256=rBpsAACES-Q_TSMl1doYvu3m29ymEtfkYx62vfrI75E,3604
217
+ rbx_cp-0.5.64.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
218
+ rbx_cp-0.5.64.dist-info/entry_points.txt,sha256=qBTLBOeifT1F00LWaEewRRE_jQPgvH7BUdJfZ-dYsFU,57
219
+ rbx_cp-0.5.64.dist-info/RECORD,,