obsitex 0.0.5__py3-none-any.whl → 0.0.6__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.
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  from pathlib import Path
3
- from typing import Optional, Sequence
3
+ from typing import Optional, Sequence, Type
4
4
 
5
5
  import bibtexparser
6
6
  from jinja2 import Environment
@@ -39,6 +39,8 @@ class ObsidianParser:
39
39
  appendix_marker: str = DEFAULT_APPENDIX_MARKER,
40
40
  bibliography_marker: str = DEFAULT_BIBLIOGRAPHY_MARKER,
41
41
  base_hlevel: int = 0,
42
+ custom_blocks: Sequence[Type[LaTeXBlock]] = [],
43
+ default_parseable_blocks: Sequence[Type[LaTeXBlock]] = PARSEABLE_BLOCKS,
42
44
  ):
43
45
  self.job_template = job_template
44
46
  self.main_template = main_template
@@ -46,6 +48,7 @@ class ObsidianParser:
46
48
  self.appendix_marker = appendix_marker
47
49
  self.bibliography_marker = bibliography_marker
48
50
  self.out_bitex_path = out_bitex_path
51
+ self.parseable_blocks = custom_blocks + default_parseable_blocks
49
52
 
50
53
  # Construct an execution plan, which will collect the jobs to run from
51
54
  # the files and pths provided
@@ -154,7 +157,7 @@ class ObsidianParser:
154
157
  while curr_i < len(lines):
155
158
  found_block = False
156
159
 
157
- for block_class in PARSEABLE_BLOCKS:
160
+ for block_class in self.parseable_blocks:
158
161
  block_instance = block_class.detect_block(lines, curr_i)
159
162
 
160
163
  if block_instance is not None:
obsitex/parser/blocks.py CHANGED
@@ -442,50 +442,63 @@ class Figure(AbstractCallout):
442
442
  return AbstractCallout.detect_block(lines, index, "figure", Figure)
443
443
 
444
444
 
445
- class RawLaTeXBlock(LaTeXBlock):
446
- def __init__(self, content):
447
- super().__init__(content, in_latex=True)
445
+ class AbstractCodeBlock(LaTeXBlock):
446
+ def __init__(self, content: str, language: str, in_latex: bool = True):
447
+ super().__init__(content, in_latex=in_latex)
448
+ self.language = language
449
+
450
+ def __repr__(self):
451
+ return f'{self.__class__.__name__}(content="{self.content}", language="{self.language}")'
448
452
 
449
453
  @staticmethod
450
454
  def detect_block(
451
- lines: Sequence[str], index: int
455
+ lines: Sequence[str],
456
+ index: int,
457
+ language: str,
458
+ instance_class: Type["LaTeXBlock"],
452
459
  ) -> Optional[Tuple["LaTeXBlock", int]]:
453
- if lines[index].startswith("```latex"):
460
+ if lines[index].startswith(f"```{language}"):
454
461
  end_index = find_next_index(
455
462
  lines, lambda line: line.startswith("```"), index + 1
456
463
  )
457
464
  raw_lines = lines[index + 1 : end_index]
458
- return RawLaTeXBlock(raw_lines), end_index
465
+ return instance_class("\n".join(raw_lines), language), end_index
459
466
 
460
467
  return None
461
468
 
462
469
 
463
- class TikZBlock(LaTeXBlock):
464
- def __init__(self, content):
465
- super().__init__(content, in_latex=True)
466
-
470
+ class RawLaTeXBlock(AbstractCodeBlock):
467
471
  @staticmethod
468
472
  def detect_block(
469
473
  lines: Sequence[str], index: int
470
474
  ) -> Optional[Tuple["LaTeXBlock", int]]:
471
- if lines[index].startswith("```tikz"):
472
- end_index = find_next_index(
473
- lines, lambda line: line.startswith("```"), index + 1
474
- )
475
- raw_lines = lines[index + 1 : end_index]
476
- tikz_content = "\n".join(raw_lines)
475
+ return AbstractCodeBlock.detect_block(lines, index, "latex", RawLaTeXBlock)
477
476
 
478
- # Remove tikz directive that are necessary to render in obsidian
479
- tikz_content = tikz_content.replace("\\begin{document}", "")
480
- tikz_content = tikz_content.replace("\\end{document}", "")
481
477
 
482
- # Filter out any sort of usepackage
483
- tikz_content = re.sub(r"\\usepackage.*\n", "", tikz_content)
484
- tikz_content = re.sub(r"\\usetikzlibrary.*\n", "", tikz_content)
478
+ class TikZBlock(AbstractCodeBlock):
479
+ def formatted_text(self, **kwargs):
480
+ self.content = self.content.replace("\\begin{document}", "")
481
+ self.content = self.content.replace("\\end{document}", "")
482
+ self.content = re.sub(r"\\usepackage.*\n", "", self.content)
483
+ self.content = re.sub(r"\\usetikzlibrary.*\n", "", self.content)
484
+ return super().formatted_text(**kwargs)
485
485
 
486
- return TikZBlock(tikz_content), end_index
486
+ @staticmethod
487
+ def detect_block(
488
+ lines: Sequence[str], index: int
489
+ ) -> Optional[Tuple["LaTeXBlock", int]]:
490
+ return AbstractCodeBlock.detect_block(lines, index, "tikz", TikZBlock)
487
491
 
488
- return None
492
+
493
+ class PythonBlock(AbstractCodeBlock):
494
+ def formatted_text(self, **kwargs):
495
+ return f"\\begin{{lstlisting}}[language=Python,breaklines=true]\n{self.content}\n\\end{{lstlisting}}\n"
496
+
497
+ @staticmethod
498
+ def detect_block(
499
+ lines: Sequence[str], index: int
500
+ ) -> Optional[Tuple["LaTeXBlock", int]]:
501
+ return AbstractCodeBlock.detect_block(lines, index, "python", PythonBlock)
489
502
 
490
503
 
491
504
  PARSEABLE_BLOCKS: Sequence[Type[LaTeXBlock]] = [
@@ -498,4 +511,5 @@ PARSEABLE_BLOCKS: Sequence[Type[LaTeXBlock]] = [
498
511
  Figure,
499
512
  RawLaTeXBlock,
500
513
  TikZBlock,
514
+ PythonBlock,
501
515
  ]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Rui Reis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: obsitex
3
- Version: 0.0.5
3
+ Version: 0.0.6
4
4
  Summary: A Python package to convert Obsidian Markdown files and folders into structured LaTeX documents.
5
5
  Home-page: UNKNOWN
6
6
  Author: Rui Reis
@@ -30,6 +30,23 @@ ObsiTex is a Python package that automates the conversion of Obsidian Markdown f
30
30
  - Uses **Jinja2 templates**, allowing full customization of the LaTeX output.
31
31
 
32
32
 
33
+ ## Table of Contents
34
+
35
+ - [Quick Start](#quick-start)
36
+ - [Supported Elements](#supported-elements)
37
+ - [Citations](#citations)
38
+ - [Callouts](#callouts)
39
+ - [Figure](#figure)
40
+ - [Table](#table)
41
+ - [Styling](#styling)
42
+ - [Samples](#samples)
43
+ - [Single File - Motivation Letter](#single-file---motivation-letter-for-willy-wonkas-chocolate-factory)
44
+ - [Single File - Research Paper on Socks](#single-file---research-paper-on-socks)
45
+ - [Folder - MSc Thesis on Ducks](#folder---msc-thesis-on-ducks)
46
+ - [Bring Your Own Blocks](#bring-your-own-blocks)
47
+ - [Acknowledgments](#acknowledgments)
48
+ - [License](#license)
49
+
33
50
  ## Quick Start
34
51
 
35
52
  To install ObsiTex, use pip:
@@ -233,6 +250,17 @@ obsitex --input obsidian-folder \
233
250
  - [main.bib](https://github.com/ruipreis/obsitex/tree/main/samples/msc-dissertation/output/main.bib)
234
251
  - [main.pdf](https://github.com/ruipreis/obsitex/tree/main/samples/msc-dissertation/output/main.pdf)
235
252
 
253
+ ### Bring Your Own Blocks
254
+
255
+ Learn how to create parsers for custom blocks in the `samples/byob` folder. This will allow you to add custom blocks to the parser, and thus customize the LaTeX output to your needs.
256
+
257
+ This example adds support for line breaks and warnings in the LaTeX output, by creating custom blocks for these elements.
258
+
259
+ #### Output Files
260
+
261
+ - [main.tex](https://github.com/ruipreis/obsitex/tree/main/samples/byob/output/main.tex)
262
+ - [main.pdf](https://github.com/ruipreis/obsitex/tree/main/samples/byob/output/main.pdf)
263
+
236
264
  ## Acknowledgments
237
265
 
238
266
  This work was inspired by:
@@ -2,14 +2,15 @@ obsitex/__init__.py,sha256=w-YmpYAdbQPyJqO1JLEaRApy1M_FzAH7nN4VvlQku-U,42
2
2
  obsitex/cli.py,sha256=otjRQIoidXecJFQs6WCPFRUv8njgieEULQzJfMZMLYY,2797
3
3
  obsitex/constants.py,sha256=dgMZjokPOYHLLOvDbsOM4XiQvOK26BAHmRdeWHn8DTE,970
4
4
  obsitex/utils.py,sha256=hqLRvuaQx_Y5rVY8B8lD6rbkMagoc3MBtswwdt_34f0,481
5
- obsitex/parser/__init__.py,sha256=FPcfq6MaVpxyrhrdfWRVNSzdE9Gz9DUOh_DPlahYsEc,7494
6
- obsitex/parser/blocks.py,sha256=q7LJcctsM32sh5iR5Bp5aa2e1kLucRwT4IGnlEsqOyA,15525
5
+ obsitex/parser/__init__.py,sha256=EgJHjIjc2fg-VyAgYf63iAbV5wIsxUSYixWyTpl0WHE,7715
6
+ obsitex/parser/blocks.py,sha256=PZv9cjmMXQzQNHHO1Lzm-qk2Gr6m-ULHNiGqewCcqyA,16107
7
7
  obsitex/parser/formatting.py,sha256=kfb_7PbdbW1QwE4HDbFrxkINejTOzwZqilgY1JCEZVE,4204
8
8
  obsitex/planner/__init__.py,sha256=4yf4scYeQ_jNO6nQZ0BboyILoA7su0LOe0KIrnCzn6U,9207
9
9
  obsitex/planner/jobs.py,sha256=UOnGMBlQFWy2nl7Zo_LcwNUiN9eqmdmhu8KeJnKWDjI,882
10
10
  obsitex/planner/links.py,sha256=SJqnJzyg2EtiZgtfZhzVBpqTVUSy87YZRObgltDv10M,1045
11
- obsitex-0.0.5.dist-info/METADATA,sha256=JsYOJA8coBOspeg28p_ac-B6hW5_9EPFir2wm9K8CNo,9189
12
- obsitex-0.0.5.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
13
- obsitex-0.0.5.dist-info/entry_points.txt,sha256=TuUDmSt5DcUZCojJvpfweHX4Be9DKms74KOOdvRj7J0,46
14
- obsitex-0.0.5.dist-info/top_level.txt,sha256=Mi24FWCjxDXVa3wNtCN0NuT_dRgyN5haGA4IE8oHeLQ,8
15
- obsitex-0.0.5.dist-info/RECORD,,
11
+ obsitex-0.0.6.dist-info/LICENSE,sha256=pVQkEXo8dC1gbK-5Qpmr2ZjHzb2ShD0Ppu4of962VfE,1065
12
+ obsitex-0.0.6.dist-info/METADATA,sha256=l8H1U8nee4cujZ2ly_YNbqK_shLhD2geJhzcWUXM8oU,10335
13
+ obsitex-0.0.6.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
14
+ obsitex-0.0.6.dist-info/entry_points.txt,sha256=TuUDmSt5DcUZCojJvpfweHX4Be9DKms74KOOdvRj7J0,46
15
+ obsitex-0.0.6.dist-info/top_level.txt,sha256=Mi24FWCjxDXVa3wNtCN0NuT_dRgyN5haGA4IE8oHeLQ,8
16
+ obsitex-0.0.6.dist-info/RECORD,,