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.
- obsitex/parser/__init__.py +5 -2
- obsitex/parser/blocks.py +38 -24
- obsitex-0.0.6.dist-info/LICENSE +21 -0
- {obsitex-0.0.5.dist-info → obsitex-0.0.6.dist-info}/METADATA +29 -1
- {obsitex-0.0.5.dist-info → obsitex-0.0.6.dist-info}/RECORD +8 -7
- {obsitex-0.0.5.dist-info → obsitex-0.0.6.dist-info}/WHEEL +0 -0
- {obsitex-0.0.5.dist-info → obsitex-0.0.6.dist-info}/entry_points.txt +0 -0
- {obsitex-0.0.5.dist-info → obsitex-0.0.6.dist-info}/top_level.txt +0 -0
obsitex/parser/__init__.py
CHANGED
@@ -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
|
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
|
446
|
-
def __init__(self, content):
|
447
|
-
super().__init__(content, in_latex=
|
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],
|
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("```
|
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
|
465
|
+
return instance_class("\n".join(raw_lines), language), end_index
|
459
466
|
|
460
467
|
return None
|
461
468
|
|
462
469
|
|
463
|
-
class
|
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
|
-
|
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
|
-
|
483
|
-
|
484
|
-
|
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
|
-
|
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
|
-
|
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.
|
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=
|
6
|
-
obsitex/parser/blocks.py,sha256=
|
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.
|
12
|
-
obsitex-0.0.
|
13
|
-
obsitex-0.0.
|
14
|
-
obsitex-0.0.
|
15
|
-
obsitex-0.0.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|