rbx.cp 0.9.1__py3-none-any.whl → 0.10.0rc0__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/cli.py CHANGED
@@ -110,7 +110,7 @@ app.add_typer(
110
110
  @app.callback()
111
111
  def main(
112
112
  cache: Annotated[
113
- int,
113
+ grading_context.CacheLevel,
114
114
  typer.Option(
115
115
  '-c',
116
116
  '--cache',
@@ -4,8 +4,9 @@ import re
4
4
  import shutil
5
5
  import typing
6
6
  from abc import ABC, abstractmethod
7
- from typing import Any, Dict, List, Optional, Tuple
7
+ from typing import Any, Dict, List, Literal, Optional, Tuple
8
8
 
9
+ import pypandoc
9
10
  import typer
10
11
  from pydantic import BaseModel
11
12
 
@@ -15,6 +16,7 @@ from rbx.box.statements.latex_jinja import (
15
16
  JinjaDictWrapper,
16
17
  render_latex_template,
17
18
  render_latex_template_blocks,
19
+ render_markdown_template_blocks,
18
20
  )
19
21
  from rbx.box.statements.schema import (
20
22
  ConversionStep,
@@ -23,6 +25,7 @@ from rbx.box.statements.schema import (
23
25
  Statement,
24
26
  StatementType,
25
27
  TexToPDF,
28
+ rbxMarkdownToTeX,
26
29
  rbxToTeX,
27
30
  )
28
31
  from rbx.box.testcase_utils import (
@@ -207,13 +210,24 @@ def render_jinja(root: pathlib.Path, content: bytes, **kwargs) -> bytes:
207
210
 
208
211
 
209
212
  def render_jinja_blocks(
210
- root: pathlib.Path, content: bytes, **kwargs
213
+ root: pathlib.Path,
214
+ content: bytes,
215
+ mode: Literal['latex', 'markdown'] = 'latex',
216
+ **kwargs,
211
217
  ) -> StatementBlocks:
212
- temp_file = '__input__.tex'
218
+ if mode == 'latex':
219
+ temp_file = '__input__.tex'
220
+ renderer = render_latex_template_blocks
221
+ elif mode == 'markdown':
222
+ temp_file = '__input__.md'
223
+ renderer = render_markdown_template_blocks
224
+ else:
225
+ raise ValueError(f'Invalid mode: {mode}')
226
+
213
227
  temp_path = root / temp_file
214
228
  temp_path.write_bytes(content)
215
229
 
216
- result: Dict[str, str] = render_latex_template_blocks(
230
+ result: Dict[str, str] = renderer(
217
231
  str(root),
218
232
  temp_file,
219
233
  kwargs,
@@ -356,6 +370,45 @@ class rbxTeXBuilder(StatementBuilder):
356
370
  )
357
371
 
358
372
 
373
+ class rbxMarkdownToTeXBuilder(StatementBuilder):
374
+ def name(self) -> ConversionType:
375
+ return ConversionType.rbxMarkdownToTeX
376
+
377
+ def default_params(self) -> ConversionStep:
378
+ return rbxMarkdownToTeX(type=ConversionType.rbxMarkdownToTeX)
379
+
380
+ def input_type(self) -> StatementType:
381
+ return StatementType.rbxMarkdown
382
+
383
+ def output_type(self) -> StatementType:
384
+ return StatementType.rbxTeX
385
+
386
+ def handles_contest(self) -> bool:
387
+ # This builder cannot build contest statements.
388
+ return False
389
+
390
+ def build(
391
+ self,
392
+ input: bytes,
393
+ context: StatementBuilderContext,
394
+ item: StatementBuilderItem,
395
+ verbose: bool = False,
396
+ ) -> bytes:
397
+ problem = typing.cast(StatementBuilderProblem, item)
398
+
399
+ statement_blocks = render_jinja_blocks(
400
+ context.root, input, mode='markdown', **problem.build_inner_jinja_kwargs()
401
+ )
402
+ blocks = statement_blocks.blocks
403
+
404
+ result_str = ''
405
+ for name, content in blocks.items():
406
+ converted_content = pypandoc.convert_text(content, 'latex', 'markdown')
407
+ result_str += f'%- block {name}\n{converted_content}\n%- endblock\n\n'
408
+
409
+ return result_str.encode()
410
+
411
+
359
412
  class TeX2PDFBuilder(StatementBuilder):
360
413
  def name(self) -> ConversionType:
361
414
  return ConversionType.TexToPDF
@@ -413,6 +466,7 @@ BUILDER_LIST: List[StatementBuilder] = [
413
466
  TeX2PDFBuilder(),
414
467
  JinjaTeXBuilder(),
415
468
  rbxTeXBuilder(),
469
+ rbxMarkdownToTeXBuilder(),
416
470
  ]
417
471
  PROBLEM_BUILDER_LIST = [
418
472
  builder for builder in BUILDER_LIST if builder.handles_problem()
@@ -32,6 +32,12 @@ J2_ARGS = {
32
32
  'autoescape': False,
33
33
  }
34
34
 
35
+ J2_MD_ARGS = {
36
+ 'trim_blocks': True,
37
+ 'autoescape': False,
38
+ }
39
+
40
+
35
41
  ######################################################################
36
42
  # Latex escape regex constants
37
43
  ######################################################################
@@ -269,3 +275,35 @@ def render_latex_template_blocks(
269
275
  '[warning]This usually happens when accessing an undefined variable.[/warning]'
270
276
  )
271
277
  raise typer.Abort() from err
278
+
279
+
280
+ def render_markdown_template_blocks(
281
+ path_templates, template_filename, template_vars=None
282
+ ) -> Dict[str, str]:
283
+ """Render a markdown template, filling in its template variables
284
+
285
+ :param path_templates: the path to the template directory
286
+ :param template_filename: the name, rooted at the path_template_directory,
287
+ of the desired template for rendering
288
+ :param template_vars: dictionary of key:val for jinja2 variables
289
+ defaults to None for case when no values need to be passed
290
+ """
291
+ var_dict = template_vars if template_vars else {}
292
+ j2_env = jinja2.Environment(
293
+ loader=jinja2.FileSystemLoader(path_templates),
294
+ **J2_MD_ARGS, # type: ignore
295
+ undefined=StrictChainableUndefined,
296
+ )
297
+ add_builtin_filters(j2_env)
298
+ add_builtin_tests(j2_env)
299
+ template = j2_env.get_template(template_filename)
300
+ ctx = template.new_context(var_dict) # type: ignore
301
+ try:
302
+ return {key: ''.join(value(ctx)) for key, value in template.blocks.items()}
303
+ except jinja2.UndefinedError as err:
304
+ console.console.print('[error]Error while rendering Jinja2 template:', end=' ')
305
+ console.console.print(err)
306
+ console.console.print(
307
+ '[warning]This usually happens when accessing an undefined variable.[/warning]'
308
+ )
309
+ raise typer.Abort() from err
@@ -27,6 +27,8 @@ class ConversionType(str, Enum):
27
27
  rbxToTex = 'rbx-tex'
28
28
  """Conversion from rbxTeX to LaTeX."""
29
29
 
30
+ rbxMarkdownToTeX = 'rbx-md-tex'
31
+ """Conversion from rbxMarkdown to LaTeX."""
30
32
  TexToPDF = 'tex2pdf'
31
33
  """Conversion from LaTeX to PDF using pdfLaTeX."""
32
34
 
@@ -38,6 +40,12 @@ class ConversionType(str, Enum):
38
40
 
39
41
 
40
42
  ### Conversion nodes.
43
+ class rbxMarkdownToTeX(BaseModel):
44
+ """Configures the conversion between rbxMarkdown and LaTeX."""
45
+
46
+ type: Literal[ConversionType.rbxMarkdownToTeX]
47
+
48
+
41
49
  class rbxToTeX(BaseModel):
42
50
  """Configures the conversion between rbxTeX and LaTeX."""
43
51
 
@@ -75,15 +83,18 @@ class JoinTexToPDF(BaseModel):
75
83
  type: Literal[JoinerType.TexToPDF]
76
84
 
77
85
 
78
- ConversionStep = Union[TexToPDF, JinjaTeX, rbxToTeX]
86
+ ConversionStep = Union[TexToPDF, JinjaTeX, rbxToTeX, rbxMarkdownToTeX]
79
87
  Joiner = JoinTexToPDF
80
88
 
81
89
 
82
90
  ### Statement types
83
91
  class StatementType(AutoEnum):
84
- rbxTeX = alias('rbx-tex', 'rbx-tex', 'rbx') # type: ignore
92
+ rbxTeX = alias('rbx-tex') # type: ignore
85
93
  """Statement written in rbxTeX format."""
86
94
 
95
+ rbxMarkdown = alias('rbxMd', 'rbx-markdown', 'rbx-md') # type: ignore
96
+ """Statement written in rbxMarkdown format."""
97
+
87
98
  TeX = alias('tex')
88
99
  """Statement written in pure LaTeX format."""
89
100
 
@@ -98,6 +109,8 @@ class StatementType(AutoEnum):
98
109
  return '.tex'
99
110
  if self == StatementType.rbxTeX:
100
111
  return '.rbx.tex'
112
+ if self == StatementType.rbxMarkdown:
113
+ return '.rbx.md'
101
114
  if self == StatementType.JinjaTeX:
102
115
  return '.jinja.tex'
103
116
  if self == StatementType.PDF:
@@ -1,7 +1,8 @@
1
1
  import contextvars
2
- from enum import Enum
3
2
  from typing import Callable, Optional, Union
4
3
 
4
+ from rbx.autoenum import AutoEnum, alias
5
+
5
6
  Condition = Union[bool, Callable[[], bool]]
6
7
 
7
8
 
@@ -15,11 +16,11 @@ class ConditionedContext:
15
16
  return self.when()
16
17
 
17
18
 
18
- class CacheLevel(Enum):
19
- NO_CACHE = 0
20
- CACHE_TRANSIENTLY = 1
21
- CACHE_COMPILATION = 2
22
- CACHE_ALL = 3
19
+ class CacheLevel(AutoEnum):
20
+ NO_CACHE = alias('none')
21
+ CACHE_TRANSIENTLY = alias('transient')
22
+ CACHE_COMPILATION = alias('compilation')
23
+ CACHE_ALL = alias('all')
23
24
 
24
25
 
25
26
  cache_level_var = contextvars.ContextVar('cache_level', default=CacheLevel.CACHE_ALL)
@@ -30,11 +31,11 @@ def is_compilation_only() -> bool:
30
31
 
31
32
 
32
33
  def is_transient() -> bool:
33
- return cache_level_var.get().value <= CacheLevel.CACHE_TRANSIENTLY.value
34
+ return cache_level_var.get() == CacheLevel.CACHE_TRANSIENTLY or is_no_cache()
34
35
 
35
36
 
36
37
  def is_no_cache() -> bool:
37
- return cache_level_var.get().value <= CacheLevel.NO_CACHE.value
38
+ return cache_level_var.get() == CacheLevel.NO_CACHE
38
39
 
39
40
 
40
41
  class cache_level(ConditionedContext):
@@ -25,6 +25,41 @@
25
25
  \usepackage{pdftexcmds}
26
26
  \usepackage{amsmath}
27
27
 
28
+ % Additional pandoc packages
29
+ %\usepackage{lmodern} % or 'libertine' / 'times' for different fonts
30
+ \usepackage{amssymb}
31
+ \usepackage{microtype}
32
+ \usepackage{graphicx}
33
+ \usepackage{longtable}
34
+ \usepackage{booktabs}
35
+ \usepackage{array}
36
+ \usepackage{multirow}
37
+ \usepackage{tabularx}
38
+ \usepackage{fancyhdr}
39
+ \usepackage{listings}
40
+ \usepackage{parskip}
41
+
42
+ % Links
43
+ \hypersetup{
44
+ colorlinks=true,
45
+ linkcolor=blue,
46
+ urlcolor=blue,
47
+ citecolor=blue,
48
+ pdfborder={0 0 0}
49
+ }
50
+
51
+ % Pandoc shenanigans
52
+ \newsavebox\pandoc@box
53
+ \newcommand*\pandocbounded[1]{% scales image to fit in text height/width
54
+ \sbox\pandoc@box{#1}%
55
+ \Gscale@div\@tempa{\textheight}{\dimexpr\ht\pandoc@box+\dp\pandoc@box\relax}%
56
+ \Gscale@div\@tempb{\linewidth}{\wd\pandoc@box}%
57
+ \ifdim\@tempb\p@<\@tempa\p@\let\@tempa\@tempb\fi% select the smaller of both
58
+ \ifdim\@tempa\p@<\p@\scalebox{\@tempa}{\usebox\pandoc@box}%Add commentMore actions
59
+ \else\usebox{\pandoc@box}%
60
+ \fi%
61
+ }
62
+
28
63
  \captionsetup[figure]{labelformat=empty}
29
64
  \setlist[itemize]{noitemsep, nolistsep}
30
65
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rbx.cp
3
- Version: 0.9.1
3
+ Version: 0.10.0rc0
4
4
  Summary:
5
5
  Author: Roberto Sales
6
6
  Requires-Python: >=3.9.1,<4.0.0
@@ -31,6 +31,7 @@ Requires-Dist: ordered-set (>=4.1.0,<5.0.0)
31
31
  Requires-Dist: psutil (>=7.0.0,<8.0.0)
32
32
  Requires-Dist: pydantic (==2.8.2)
33
33
  Requires-Dist: pydantic-xml[lxml] (>=2.11.0,<3.0.0)
34
+ Requires-Dist: pypandoc (>=1.15,<2.0)
34
35
  Requires-Dist: pyte (>=0.8.2,<0.9.0)
35
36
  Requires-Dist: python-iso639 (>=2024.4.27,<2025.0.0)
36
37
  Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
@@ -5,7 +5,7 @@ rbx/box/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  rbx/box/builder.py,sha256=MDm2qqmhedAbhn3rWP6cDwbBsGhV6sz_2sg1zLkPDw0,3613
6
6
  rbx/box/cd.py,sha256=_XAzb3kV1NUaaRs8hc9SGDo10O1yh2_gr1EiAKzfUjI,2711
7
7
  rbx/box/checkers.py,sha256=2eLfMOzJajoca26M4rOBxUxve3-BpxcMu_q2upI1Pcg,13017
8
- rbx/box/cli.py,sha256=yksizw3ukyQL4xcF1oRlIR8Zt5JMqxAul7Y1T206Kwo,29755
8
+ rbx/box/cli.py,sha256=a_tjWct-pin60cZ3OIg3SsyCjIoSWR0m6_lepFxDbDE,29778
9
9
  rbx/box/code.py,sha256=4GChCeUaHjT7stvtPAURbCL1_V238geG3xmXQjbdV20,26708
10
10
  rbx/box/compile.py,sha256=Kzn5mEQu4vb91W9vjyt0DS6cfPJzFLTUoowFj7uHLUo,2539
11
11
  rbx/box/conftest.py,sha256=sEmciXSeDC-wmrZ1JSxbsUenKNP_VWW32mrCun2pY3I,1070
@@ -64,12 +64,12 @@ rbx/box/solutions_test.py,sha256=PX1TQoRzNd9mi1SGsG7WFrpqFgNrNX5Kwt0mkwFdoOA,174
64
64
  rbx/box/state.py,sha256=MMf3DvfQji0jKEliCHct2Tpp_0epL1tvP8HbHNArQIc,166
65
65
  rbx/box/statements/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
66
  rbx/box/statements/build_statements.py,sha256=DgEuhhbu-LJAMFJhmVuBR44o4Mq2odue9pRaG-I5OJY,12711
67
- rbx/box/statements/builders.py,sha256=_HQs67mEHyUxZo-fSrSvvpYHpaJYRIHyGRTtg9YSGU8,12105
67
+ rbx/box/statements/builders.py,sha256=Qb_rfkFOqghFZfEf2zPSEoDPc-lCBNb5CcPoOkV7HMk,13747
68
68
  rbx/box/statements/expander.py,sha256=sdbMtNcJQCbXGIkFIl9h24pGr77vhFLnM31V5AfuduI,1715
69
69
  rbx/box/statements/joiners.py,sha256=jItNXkAbTjFQpPMgfDMW86n3vMTbaE8sgo9I8Yf4Txg,2886
70
70
  rbx/box/statements/latex.py,sha256=LkcHwXjMFxbw--Gj9T1VkFKQFsXhY9dN7xZHpZycNW8,1346
71
- rbx/box/statements/latex_jinja.py,sha256=6whLCIHzPjq7oeDwzUgdvirpLA4Y3G-w319DhzPwPUI,8960
72
- rbx/box/statements/schema.py,sha256=QIUkQhrLb3rqAdvzDSwL3r4uAvDv-mKsWRtfCEH2L7Y,4685
71
+ rbx/box/statements/latex_jinja.py,sha256=iMx47ynKMjLNcfymzHV24jtWrRVnit0Va9H8yTfgmiA,10379
72
+ rbx/box/statements/schema.py,sha256=5_qrY1KztCLSe4t-rJ7zdv3cBjcaO-FnFc45ZRUotfs,5127
73
73
  rbx/box/stats.py,sha256=rUAnmp7kTgUvIQ56NLpQaIQkazB37MVcUos5en3xUQw,3258
74
74
  rbx/box/stresses.py,sha256=IqlmbIdXydxLW55YEJ3N_jFdXpEshm5iib1pgGf3WRY,12073
75
75
  rbx/box/stressing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -124,7 +124,7 @@ rbx/grading/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
124
124
  rbx/grading/caching.py,sha256=X20v-ZCmcT6OXvWzq2VBdACi6_cEYWB2phkiJ34CNeg,15306
125
125
  rbx/grading/conftest.py,sha256=820Uw3AE-dwAfwLhXjgq_PixpDI1-JEXsOPYf4VT5H8,971
126
126
  rbx/grading/debug_context.py,sha256=kuAXEI8yRG8xfhS9WKKIRh9X0e5JUD8zvl_cpczJTC8,699
127
- rbx/grading/grading_context.py,sha256=DFEG7dUK6acjE1c49i91BCWXqhD36DVU0gVbD-77gCU,3340
127
+ rbx/grading/grading_context.py,sha256=TaRyLwPkkxvspQIFUFk8Ok0T8EST2pHMMNoVDx9lbFU,3416
128
128
  rbx/grading/judge/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
129
129
  rbx/grading/judge/cacher.py,sha256=wtRnVE_Es9xcqIgrhn6WzUoB90aihUuKaFyuVsusngg,20323
130
130
  rbx/grading/judge/digester.py,sha256=gtOIe_iL4PEWA7OKelW1gjSI-nBvbOpDPJGV8VQyjSg,912
@@ -224,7 +224,7 @@ rbx/resources/presets/default/problem/testplan/random.txt,sha256=2BA_AM8IAKEcrUT
224
224
  rbx/resources/presets/default/problem/validator.cpp,sha256=w4gl1u30Dx1N9oRTVtIg_rPlIyL6QdN_Bi5FDpp4gyw,317
225
225
  rbx/resources/presets/default/problem/wcmp.cpp,sha256=gbjJe3Vf9-YzHCEqBUq30aI3jMZXhqBDn3jjecYOn-w,902
226
226
  rbx/resources/presets/default/shared/contest_template.rbx.tex,sha256=p7fb3pNh9l-0gSXrsjuJ_4c11X2CFPp_Ef6sYtr7bc0,1285
227
- rbx/resources/presets/default/shared/icpc.sty,sha256=YIZfUV1-HOyW6qj5_2XEx06_vsDtm1lNkuVFUGAxoUg,7114
227
+ rbx/resources/presets/default/shared/icpc.sty,sha256=A_bSsldpeyzxRCYWpc6k55P5zrDZFpHaIcvZ_WOVW30,8043
228
228
  rbx/resources/presets/default/shared/problem_template.rbx.tex,sha256=p7fb3pNh9l-0gSXrsjuJ_4c11X2CFPp_Ef6sYtr7bc0,1285
229
229
  rbx/resources/templates/rbx.h,sha256=Iwtmr2gdDYmZ2VlIurmleBb_uEpriWd4EX0dJta8xUA,2179
230
230
  rbx/resources/templates/template.cpp,sha256=xXWpWo7fa7HfmPNqkmHcmv3i46Wm0ZL-gPmkRfGvLn4,317
@@ -239,8 +239,8 @@ rbx/testcase.py,sha256=yKOq3CAJZ1YTmInvnoIs0u1iJnRj_X85XiWbLI-p9d8,1951
239
239
  rbx/testcase_rendering.py,sha256=nfmv6dSEqd4aR3TsaODwkKGK6AXty_DDKtWf_ejiQpI,2084
240
240
  rbx/testing_utils.py,sha256=x_PqD8Zd2PkN91NxVHUnSTs044-1WK5KKtttKQBXpFs,2083
241
241
  rbx/utils.py,sha256=YvN0q1vaLR9HxUfXKOTx1iN6Bp_fI8YNTQiJ8TNq7eM,4957
242
- rbx_cp-0.9.1.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
243
- rbx_cp-0.9.1.dist-info/METADATA,sha256=Pn1vVMzkP6Kv11iw_UMCy5CMfYjz_FJD92yiB0fuoQQ,4586
244
- rbx_cp-0.9.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
245
- rbx_cp-0.9.1.dist-info/entry_points.txt,sha256=qBTLBOeifT1F00LWaEewRRE_jQPgvH7BUdJfZ-dYsFU,57
246
- rbx_cp-0.9.1.dist-info/RECORD,,
242
+ rbx_cp-0.10.0rc0.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
243
+ rbx_cp-0.10.0rc0.dist-info/METADATA,sha256=EHyOY6PqaUM-PolY0_5ZmX_cNKqD3T6tFq-C95FYfZ0,4628
244
+ rbx_cp-0.10.0rc0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
245
+ rbx_cp-0.10.0rc0.dist-info/entry_points.txt,sha256=qBTLBOeifT1F00LWaEewRRE_jQPgvH7BUdJfZ-dYsFU,57
246
+ rbx_cp-0.10.0rc0.dist-info/RECORD,,