pytexmd 1.1__tar.gz
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.
- pytexmd-1.1/MANIFEST.in +3 -0
- pytexmd-1.1/PKG-INFO +208 -0
- pytexmd-1.1/README.md +187 -0
- pytexmd-1.1/pyproject.toml +31 -0
- pytexmd-1.1/pytexmd/__init__.py +4 -0
- pytexmd-1.1/pytexmd/cli.py +52 -0
- pytexmd-1.1/pytexmd/config.py +9 -0
- pytexmd-1.1/pytexmd/core.py +80 -0
- pytexmd-1.1/pytexmd/file_loader.py +300 -0
- pytexmd-1.1/pytexmd/filter/__init__.py +20 -0
- pytexmd-1.1/pytexmd/filter/antibugs.py +231 -0
- pytexmd-1.1/pytexmd/filter/bibtex/__init__.py +3 -0
- pytexmd-1.1/pytexmd/filter/bibtex/core.py +255 -0
- pytexmd-1.1/pytexmd/filter/core.py +967 -0
- pytexmd-1.1/pytexmd/filter/enumitem.py +503 -0
- pytexmd-1.1/pytexmd/filter/equations.py +522 -0
- pytexmd-1.1/pytexmd/filter/file_maker.py +574 -0
- pytexmd-1.1/pytexmd/filter/notworking_preprocessor.py +452 -0
- pytexmd-1.1/pytexmd/filter/preprocessor.py +243 -0
- pytexmd-1.1/pytexmd/filter/splitting.py +308 -0
- pytexmd-1.1/pytexmd/filter/text.py +803 -0
- pytexmd-1.1/pytexmd/sphinx_doc.py +284 -0
- pytexmd-1.1/pytexmd.egg-info/PKG-INFO +208 -0
- pytexmd-1.1/pytexmd.egg-info/SOURCES.txt +29 -0
- pytexmd-1.1/pytexmd.egg-info/dependency_links.txt +1 -0
- pytexmd-1.1/pytexmd.egg-info/entry_points.txt +2 -0
- pytexmd-1.1/pytexmd.egg-info/requires.txt +5 -0
- pytexmd-1.1/pytexmd.egg-info/top_level.txt +1 -0
- pytexmd-1.1/requirements.txt +8 -0
- pytexmd-1.1/setup.cfg +4 -0
- pytexmd-1.1/setup.py +33 -0
pytexmd-1.1/MANIFEST.in
ADDED
pytexmd-1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pytexmd
|
|
3
|
+
Version: 1.1
|
|
4
|
+
Summary: Translate LaTeX documents to Markdown/MyST and HTML, with CLI and Sphinx integration.
|
|
5
|
+
Author: Martin Pflaum
|
|
6
|
+
Author-email: Martin Pflaum <contact@martinpflaum.com>
|
|
7
|
+
Project-URL: Homepage, https://github.com/yourusername/pytexmd
|
|
8
|
+
Project-URL: Repository, https://github.com/yourusername/pytexmd
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.14
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: sphinx
|
|
15
|
+
Requires-Dist: myst-parser
|
|
16
|
+
Requires-Dist: sphinx-proof
|
|
17
|
+
Requires-Dist: furo
|
|
18
|
+
Requires-Dist: regex
|
|
19
|
+
Dynamic: author
|
|
20
|
+
Dynamic: requires-python
|
|
21
|
+
|
|
22
|
+
# PyTeXmd
|
|
23
|
+
|
|
24
|
+
Pytexmd is a Python package designed to translate LaTeX documents to Markdown MyST and HTML. It provides utilities for filtering content, loading files, and integrating with Sphinx documentation.
|
|
25
|
+
|
|
26
|
+
## Documentation
|
|
27
|
+
|
|
28
|
+
- **Full Documentation**: [pytexmd.readthedocs.io](https://pytexmd.readthedocs.io/en/latest/index.html)
|
|
29
|
+
- **GitHub Repository**: [github.com/martinpflaum/pytexmd](https://github.com/martinpflaum/pytexmd)
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
To install the required dependencies for pytexmd, run:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install -r requirements.txt
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
you also need texlive https://www.tug.org/texlive/ and ghostscript https://ghostscript.com/releases/gsdnld.html
|
|
40
|
+
|
|
41
|
+
## Python Usage Example
|
|
42
|
+
|
|
43
|
+
If you want to use pytexmd from a Python script, make sure your script is in the same folder (or a subfolder) as the pytexmd package, or add pytexmd to your Python path. The following example can also be found in the examples folder:
|
|
44
|
+
|
|
45
|
+
```project = 'My Project'
|
|
46
|
+
copyright = '2025, Author'
|
|
47
|
+
author = 'Author'
|
|
48
|
+
release = '1.0'
|
|
49
|
+
|
|
50
|
+
extensions = ['myst_parser',
|
|
51
|
+
"sphinx_proof"]
|
|
52
|
+
|
|
53
|
+
templates_path = ['_templates']
|
|
54
|
+
exclude_patterns = []
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
mathjax3_config = {
|
|
59
|
+
"tex": {
|
|
60
|
+
"macros": {
|
|
61
|
+
"ltortoise": "\\unicode{x3014}",
|
|
62
|
+
"rtortoise": "\\unicode{x3015}",
|
|
63
|
+
"ltsbrak": ["\\mathopen{\\ltortoise\\mspace{1mu}}", 0],
|
|
64
|
+
"rtsbrak": ["\\mathopen{\\mspace{1mu}\\rtortoise}", 0],
|
|
65
|
+
"mathbbm": ["\\mathbb{#1}", 1],
|
|
66
|
+
"widebar": ["\\overline{#1}", 1],
|
|
67
|
+
"C": "\\mathbb{C}",
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
myst_enable_extensions = [
|
|
73
|
+
"amsmath",
|
|
74
|
+
"attrs_inline",
|
|
75
|
+
"attrs_block",
|
|
76
|
+
"colon_fence",
|
|
77
|
+
"deflist",
|
|
78
|
+
"dollarmath",
|
|
79
|
+
"fieldlist",
|
|
80
|
+
"html_admonition",
|
|
81
|
+
"html_image",
|
|
82
|
+
"replacements",
|
|
83
|
+
"smartquotes",
|
|
84
|
+
"strikethrough",
|
|
85
|
+
"substitution",
|
|
86
|
+
"tasklist",
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
prf_realtyp_to_countertyp = {
|
|
91
|
+
"axiom": "theorem",
|
|
92
|
+
"theorem": "theorem",
|
|
93
|
+
"lemma": "theorem",
|
|
94
|
+
"algorithm": "theorem",
|
|
95
|
+
"definition": "theorem",
|
|
96
|
+
"remark": "theorem",
|
|
97
|
+
"conjecture": "theorem",
|
|
98
|
+
"corollary": "theorem",
|
|
99
|
+
"criterion": "theorem",
|
|
100
|
+
"example": "theorem",
|
|
101
|
+
"property": "theorem",
|
|
102
|
+
"observation": "theorem",
|
|
103
|
+
"proposition": "theorem",
|
|
104
|
+
"assumption": "theorem",
|
|
105
|
+
"notation": "theorem",
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#math_number_all = True # number *all* displayed equations
|
|
109
|
+
math_eqref_format = "({number})" # how equation refs look
|
|
110
|
+
|
|
111
|
+
html_theme = 'furo'
|
|
112
|
+
html_static_path = ['_static']
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
#math_number_all = True # number *all* displayed equations
|
|
116
|
+
math_eqref_format = "({number})" # how equation refs look
|
|
117
|
+
numfig = True # enable section-prefixed numbering
|
|
118
|
+
math_numfig = True # apply section prefix to equations
|
|
119
|
+
numfig_secnum_depth = 2 # use # and ## levels (e.g. 1.2.3)
|
|
120
|
+
|
|
121
|
+
html_theme = 'furo'
|
|
122
|
+
html_static_path = ['_static']
|
|
123
|
+
# Custom theorem types (auto-generated by pytexmd)
|
|
124
|
+
import sphinx_proof.nodes
|
|
125
|
+
import sphinx_proof.proof_type
|
|
126
|
+
import sphinx_proof.directive
|
|
127
|
+
import sphinx_proof.domain
|
|
128
|
+
from docutils import nodes
|
|
129
|
+
from sphinx_proof.directive import ElementDirective
|
|
130
|
+
|
|
131
|
+
class theorem_and_definition_node(nodes.Admonition, nodes.Element):
|
|
132
|
+
pass
|
|
133
|
+
|
|
134
|
+
class TheoremAndDefinitionDirective(ElementDirective):
|
|
135
|
+
name = "theorem_and_definition"
|
|
136
|
+
|
|
137
|
+
class proposition_and_definition_node(nodes.Admonition, nodes.Element):
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
class PropositionAndDefinitionDirective(ElementDirective):
|
|
141
|
+
name = "proposition_and_definition"
|
|
142
|
+
|
|
143
|
+
_CUSTOM_TYPES = {
|
|
144
|
+
"theorem_and_definition": (theorem_and_definition_node, TheoremAndDefinitionDirective),
|
|
145
|
+
"proposition_and_definition": (proposition_and_definition_node, PropositionAndDefinitionDirective),
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
for _name, (_node_cls, _directive_cls) in _CUSTOM_TYPES.items():
|
|
149
|
+
sphinx_proof.nodes.NODE_TYPES[_name] = _node_cls
|
|
150
|
+
sphinx_proof.proof_type.PROOF_TYPES[_name] = _directive_cls
|
|
151
|
+
sphinx_proof.directive.DEFAULT_REALTYP_TO_COUNTERTYP[_name] = _name
|
|
152
|
+
sphinx_proof.domain.ProofDomain.directives[_name] = _directive_cls
|
|
153
|
+
prf_realtyp_to_countertyp[_name] = "theorem"
|
|
154
|
+
|
|
155
|
+
# Monkey-patch the 4 realtyp.title() calls in sphinx_proof.nodes so that
|
|
156
|
+
# underscored names like 'theorem_and_definition' render as
|
|
157
|
+
# 'Theorem And Definition' instead of 'Theorem_And_Definition'.
|
|
158
|
+
import sphinx_proof.nodes as _spn
|
|
159
|
+
import sphinx_proof as _sp
|
|
160
|
+
from sphinx.writers.latex import LaTeXTranslator as _LaTeXTranslator
|
|
161
|
+
|
|
162
|
+
def _depart_enumerable_node(self, node):
|
|
163
|
+
countertyp = node.attributes.get("countertype", "")
|
|
164
|
+
realtyp = node.attributes.get("realtype", "")
|
|
165
|
+
display = realtyp.replace("_", " ").title()
|
|
166
|
+
if isinstance(self, _LaTeXTranslator):
|
|
167
|
+
number = _spn.get_node_number(self, node, countertyp)
|
|
168
|
+
idx = _spn.list_rindex(self.body, _spn.latex_admonition_start) + 2
|
|
169
|
+
self.body.insert(idx, f"{display} {number}")
|
|
170
|
+
self.body.append(_spn.latex_admonition_end)
|
|
171
|
+
else:
|
|
172
|
+
number = _spn.get_node_number(self, node, countertyp)
|
|
173
|
+
idx = self.body.index(f"{countertyp} {number} ")
|
|
174
|
+
self.body[idx] = f"{_spn._(display)} {number} "
|
|
175
|
+
self.body.append("</div>")
|
|
176
|
+
|
|
177
|
+
def _depart_unenumerable_node(self, node):
|
|
178
|
+
realtyp = node.attributes.get("realtype", "")
|
|
179
|
+
display = realtyp.replace("_", " ").title()
|
|
180
|
+
node_id = node.attributes.get("ids", [""])[0]
|
|
181
|
+
if isinstance(self, _LaTeXTranslator):
|
|
182
|
+
idx = _spn.list_rindex(self.body, _spn.latex_admonition_start) + 2
|
|
183
|
+
self.body.insert(idx, display)
|
|
184
|
+
self.body.append(_spn.latex_admonition_end)
|
|
185
|
+
else:
|
|
186
|
+
search_str = f'<p class="admonition-title" id="{node_id}">'
|
|
187
|
+
idx = _spn.list_rindex(self.body, search_str) + 1
|
|
188
|
+
element = f'<span class="caption-number">{_spn._(display)} </span>'
|
|
189
|
+
self.body.insert(idx, element)
|
|
190
|
+
self.body.append("</div>")
|
|
191
|
+
|
|
192
|
+
# Patch both the nodes module AND sphinx_proof's __init__ namespace.
|
|
193
|
+
# sphinx_proof/__init__.py does `from .nodes import depart_enumerable_node`
|
|
194
|
+
# which binds the name in its own globals. Sphinx's setup() looks up the name
|
|
195
|
+
# there, so patching only sphinx_proof.nodes has no effect.
|
|
196
|
+
_spn.depart_enumerable_node = _depart_enumerable_node
|
|
197
|
+
_spn.depart_unenumerable_node = _depart_unenumerable_node
|
|
198
|
+
_sp.depart_enumerable_node = _depart_enumerable_node
|
|
199
|
+
_sp.depart_unenumerable_node = _depart_unenumerable_node
|
|
200
|
+
|
|
201
|
+
numfig_format = {
|
|
202
|
+
"theorem_and_definition": "Theorem and Definition %s",
|
|
203
|
+
"proposition_and_definition": "Proposition and Definition %s",
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
also in the file loader make sure that all .bib files are found also in folder mentioned in the \input thingies than concatenate these .bib file but eliminate duplicated entries also copy this thing to the created sphinx project also use of sphinxcontrib-bibtex
|
pytexmd-1.1/README.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# PyTeXmd
|
|
2
|
+
|
|
3
|
+
Pytexmd is a Python package designed to translate LaTeX documents to Markdown MyST and HTML. It provides utilities for filtering content, loading files, and integrating with Sphinx documentation.
|
|
4
|
+
|
|
5
|
+
## Documentation
|
|
6
|
+
|
|
7
|
+
- **Full Documentation**: [pytexmd.readthedocs.io](https://pytexmd.readthedocs.io/en/latest/index.html)
|
|
8
|
+
- **GitHub Repository**: [github.com/martinpflaum/pytexmd](https://github.com/martinpflaum/pytexmd)
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
To install the required dependencies for pytexmd, run:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install -r requirements.txt
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
you also need texlive https://www.tug.org/texlive/ and ghostscript https://ghostscript.com/releases/gsdnld.html
|
|
19
|
+
|
|
20
|
+
## Python Usage Example
|
|
21
|
+
|
|
22
|
+
If you want to use pytexmd from a Python script, make sure your script is in the same folder (or a subfolder) as the pytexmd package, or add pytexmd to your Python path. The following example can also be found in the examples folder:
|
|
23
|
+
|
|
24
|
+
```project = 'My Project'
|
|
25
|
+
copyright = '2025, Author'
|
|
26
|
+
author = 'Author'
|
|
27
|
+
release = '1.0'
|
|
28
|
+
|
|
29
|
+
extensions = ['myst_parser',
|
|
30
|
+
"sphinx_proof"]
|
|
31
|
+
|
|
32
|
+
templates_path = ['_templates']
|
|
33
|
+
exclude_patterns = []
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
mathjax3_config = {
|
|
38
|
+
"tex": {
|
|
39
|
+
"macros": {
|
|
40
|
+
"ltortoise": "\\unicode{x3014}",
|
|
41
|
+
"rtortoise": "\\unicode{x3015}",
|
|
42
|
+
"ltsbrak": ["\\mathopen{\\ltortoise\\mspace{1mu}}", 0],
|
|
43
|
+
"rtsbrak": ["\\mathopen{\\mspace{1mu}\\rtortoise}", 0],
|
|
44
|
+
"mathbbm": ["\\mathbb{#1}", 1],
|
|
45
|
+
"widebar": ["\\overline{#1}", 1],
|
|
46
|
+
"C": "\\mathbb{C}",
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
myst_enable_extensions = [
|
|
52
|
+
"amsmath",
|
|
53
|
+
"attrs_inline",
|
|
54
|
+
"attrs_block",
|
|
55
|
+
"colon_fence",
|
|
56
|
+
"deflist",
|
|
57
|
+
"dollarmath",
|
|
58
|
+
"fieldlist",
|
|
59
|
+
"html_admonition",
|
|
60
|
+
"html_image",
|
|
61
|
+
"replacements",
|
|
62
|
+
"smartquotes",
|
|
63
|
+
"strikethrough",
|
|
64
|
+
"substitution",
|
|
65
|
+
"tasklist",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
prf_realtyp_to_countertyp = {
|
|
70
|
+
"axiom": "theorem",
|
|
71
|
+
"theorem": "theorem",
|
|
72
|
+
"lemma": "theorem",
|
|
73
|
+
"algorithm": "theorem",
|
|
74
|
+
"definition": "theorem",
|
|
75
|
+
"remark": "theorem",
|
|
76
|
+
"conjecture": "theorem",
|
|
77
|
+
"corollary": "theorem",
|
|
78
|
+
"criterion": "theorem",
|
|
79
|
+
"example": "theorem",
|
|
80
|
+
"property": "theorem",
|
|
81
|
+
"observation": "theorem",
|
|
82
|
+
"proposition": "theorem",
|
|
83
|
+
"assumption": "theorem",
|
|
84
|
+
"notation": "theorem",
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#math_number_all = True # number *all* displayed equations
|
|
88
|
+
math_eqref_format = "({number})" # how equation refs look
|
|
89
|
+
|
|
90
|
+
html_theme = 'furo'
|
|
91
|
+
html_static_path = ['_static']
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
#math_number_all = True # number *all* displayed equations
|
|
95
|
+
math_eqref_format = "({number})" # how equation refs look
|
|
96
|
+
numfig = True # enable section-prefixed numbering
|
|
97
|
+
math_numfig = True # apply section prefix to equations
|
|
98
|
+
numfig_secnum_depth = 2 # use # and ## levels (e.g. 1.2.3)
|
|
99
|
+
|
|
100
|
+
html_theme = 'furo'
|
|
101
|
+
html_static_path = ['_static']
|
|
102
|
+
# Custom theorem types (auto-generated by pytexmd)
|
|
103
|
+
import sphinx_proof.nodes
|
|
104
|
+
import sphinx_proof.proof_type
|
|
105
|
+
import sphinx_proof.directive
|
|
106
|
+
import sphinx_proof.domain
|
|
107
|
+
from docutils import nodes
|
|
108
|
+
from sphinx_proof.directive import ElementDirective
|
|
109
|
+
|
|
110
|
+
class theorem_and_definition_node(nodes.Admonition, nodes.Element):
|
|
111
|
+
pass
|
|
112
|
+
|
|
113
|
+
class TheoremAndDefinitionDirective(ElementDirective):
|
|
114
|
+
name = "theorem_and_definition"
|
|
115
|
+
|
|
116
|
+
class proposition_and_definition_node(nodes.Admonition, nodes.Element):
|
|
117
|
+
pass
|
|
118
|
+
|
|
119
|
+
class PropositionAndDefinitionDirective(ElementDirective):
|
|
120
|
+
name = "proposition_and_definition"
|
|
121
|
+
|
|
122
|
+
_CUSTOM_TYPES = {
|
|
123
|
+
"theorem_and_definition": (theorem_and_definition_node, TheoremAndDefinitionDirective),
|
|
124
|
+
"proposition_and_definition": (proposition_and_definition_node, PropositionAndDefinitionDirective),
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for _name, (_node_cls, _directive_cls) in _CUSTOM_TYPES.items():
|
|
128
|
+
sphinx_proof.nodes.NODE_TYPES[_name] = _node_cls
|
|
129
|
+
sphinx_proof.proof_type.PROOF_TYPES[_name] = _directive_cls
|
|
130
|
+
sphinx_proof.directive.DEFAULT_REALTYP_TO_COUNTERTYP[_name] = _name
|
|
131
|
+
sphinx_proof.domain.ProofDomain.directives[_name] = _directive_cls
|
|
132
|
+
prf_realtyp_to_countertyp[_name] = "theorem"
|
|
133
|
+
|
|
134
|
+
# Monkey-patch the 4 realtyp.title() calls in sphinx_proof.nodes so that
|
|
135
|
+
# underscored names like 'theorem_and_definition' render as
|
|
136
|
+
# 'Theorem And Definition' instead of 'Theorem_And_Definition'.
|
|
137
|
+
import sphinx_proof.nodes as _spn
|
|
138
|
+
import sphinx_proof as _sp
|
|
139
|
+
from sphinx.writers.latex import LaTeXTranslator as _LaTeXTranslator
|
|
140
|
+
|
|
141
|
+
def _depart_enumerable_node(self, node):
|
|
142
|
+
countertyp = node.attributes.get("countertype", "")
|
|
143
|
+
realtyp = node.attributes.get("realtype", "")
|
|
144
|
+
display = realtyp.replace("_", " ").title()
|
|
145
|
+
if isinstance(self, _LaTeXTranslator):
|
|
146
|
+
number = _spn.get_node_number(self, node, countertyp)
|
|
147
|
+
idx = _spn.list_rindex(self.body, _spn.latex_admonition_start) + 2
|
|
148
|
+
self.body.insert(idx, f"{display} {number}")
|
|
149
|
+
self.body.append(_spn.latex_admonition_end)
|
|
150
|
+
else:
|
|
151
|
+
number = _spn.get_node_number(self, node, countertyp)
|
|
152
|
+
idx = self.body.index(f"{countertyp} {number} ")
|
|
153
|
+
self.body[idx] = f"{_spn._(display)} {number} "
|
|
154
|
+
self.body.append("</div>")
|
|
155
|
+
|
|
156
|
+
def _depart_unenumerable_node(self, node):
|
|
157
|
+
realtyp = node.attributes.get("realtype", "")
|
|
158
|
+
display = realtyp.replace("_", " ").title()
|
|
159
|
+
node_id = node.attributes.get("ids", [""])[0]
|
|
160
|
+
if isinstance(self, _LaTeXTranslator):
|
|
161
|
+
idx = _spn.list_rindex(self.body, _spn.latex_admonition_start) + 2
|
|
162
|
+
self.body.insert(idx, display)
|
|
163
|
+
self.body.append(_spn.latex_admonition_end)
|
|
164
|
+
else:
|
|
165
|
+
search_str = f'<p class="admonition-title" id="{node_id}">'
|
|
166
|
+
idx = _spn.list_rindex(self.body, search_str) + 1
|
|
167
|
+
element = f'<span class="caption-number">{_spn._(display)} </span>'
|
|
168
|
+
self.body.insert(idx, element)
|
|
169
|
+
self.body.append("</div>")
|
|
170
|
+
|
|
171
|
+
# Patch both the nodes module AND sphinx_proof's __init__ namespace.
|
|
172
|
+
# sphinx_proof/__init__.py does `from .nodes import depart_enumerable_node`
|
|
173
|
+
# which binds the name in its own globals. Sphinx's setup() looks up the name
|
|
174
|
+
# there, so patching only sphinx_proof.nodes has no effect.
|
|
175
|
+
_spn.depart_enumerable_node = _depart_enumerable_node
|
|
176
|
+
_spn.depart_unenumerable_node = _depart_unenumerable_node
|
|
177
|
+
_sp.depart_enumerable_node = _depart_enumerable_node
|
|
178
|
+
_sp.depart_unenumerable_node = _depart_unenumerable_node
|
|
179
|
+
|
|
180
|
+
numfig_format = {
|
|
181
|
+
"theorem_and_definition": "Theorem and Definition %s",
|
|
182
|
+
"proposition_and_definition": "Proposition and Definition %s",
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
also in the file loader make sure that all .bib files are found also in folder mentioned in the \input thingies than concatenate these .bib file but eliminate duplicated entries also copy this thing to the created sphinx project also use of sphinxcontrib-bibtex
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=42", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pytexmd"
|
|
7
|
+
version = "1.1"
|
|
8
|
+
description = "Translate LaTeX documents to Markdown/MyST and HTML, with CLI and Sphinx integration."
|
|
9
|
+
authors = [
|
|
10
|
+
{ name = "Martin Pflaum", email = "contact@martinpflaum.com" }
|
|
11
|
+
]
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.8"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
"sphinx",
|
|
21
|
+
"myst-parser",
|
|
22
|
+
"sphinx-proof",
|
|
23
|
+
"furo",
|
|
24
|
+
"regex"
|
|
25
|
+
]
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/yourusername/pytexmd"
|
|
28
|
+
Repository = "https://github.com/yourusername/pytexmd"
|
|
29
|
+
|
|
30
|
+
[project.scripts]
|
|
31
|
+
pytexmd = "pytexmd.cli:main"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Command-line interface for pytexmd.
|
|
2
|
+
|
|
3
|
+
This module provides a CLI for processing LaTeX files and generating documentation.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
__all__ = ['process_file']
|
|
7
|
+
|
|
8
|
+
from .core import process_file
|
|
9
|
+
import argparse
|
|
10
|
+
|
|
11
|
+
def main() -> None:
|
|
12
|
+
"""Main entry point for the CLI.
|
|
13
|
+
|
|
14
|
+
Parses command-line arguments and processes the specified LaTeX file.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
input_file (str): File to process.
|
|
18
|
+
output_folder (str): Output folder.
|
|
19
|
+
depth (int): How many sub files should be created according to sections and paragraphs etc.
|
|
20
|
+
output_suffix (str): Suffix for output files.
|
|
21
|
+
project_name (str): Project name.
|
|
22
|
+
author (str): Author name.
|
|
23
|
+
version (str): Version string.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
None
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
python -m pytexmd.cli main.tex output_folder --depth 3 --output_suffix .md --project_name "My Project" --author "Author" --version "1.0"
|
|
30
|
+
"""
|
|
31
|
+
parser = argparse.ArgumentParser(description="My Library CLI")
|
|
32
|
+
parser.add_argument("input_file", help="File to process", type=str)
|
|
33
|
+
parser.add_argument("output_folder", help="Output folder", type=str)
|
|
34
|
+
parser.add_argument("--depth", help="(not supported yet)How many sub files should be created according to sections and paragraphs etc.", default=0, type=int)
|
|
35
|
+
parser.add_argument("--output_suffix", help="Suffix for output files", default=".md", type=str)
|
|
36
|
+
parser.add_argument("--project_name", help="Project name", default="My Project", type=str)
|
|
37
|
+
parser.add_argument("--author", help="Author name", default="Author", type=str)
|
|
38
|
+
parser.add_argument("--version", help="Version string", default="1.0", type=str)
|
|
39
|
+
args = parser.parse_args()
|
|
40
|
+
print(f"Processing {args.input_file}")
|
|
41
|
+
process_file(
|
|
42
|
+
args.input_file,
|
|
43
|
+
args.output_folder,
|
|
44
|
+
args.depth,
|
|
45
|
+
args.output_suffix,
|
|
46
|
+
args.project_name,
|
|
47
|
+
args.author,
|
|
48
|
+
args.version
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
if __name__ == "__main__":
|
|
52
|
+
main()
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Core utilities for processing LaTeX files and generating documentation.
|
|
2
|
+
|
|
3
|
+
This module provides the main entry point for converting LaTeX files to Markdown and generating Sphinx documentation.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
__all__ = ["process_file"]
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
from .filter import process_string
|
|
10
|
+
from .file_loader import load_tex_file, convert_bbl_to_bib
|
|
11
|
+
from .sphinx_doc import create_sphinx_documentation, make_html, create_config_file
|
|
12
|
+
from .filter.splitting import split_rename
|
|
13
|
+
from .filter.text import CUSTOM_THEOREM_TYPES
|
|
14
|
+
|
|
15
|
+
def process_file(
|
|
16
|
+
input_file: str,
|
|
17
|
+
output_folder: str,
|
|
18
|
+
depth: int = 3,
|
|
19
|
+
output_suffix: str = ".md",
|
|
20
|
+
project_name: str = "My Project",
|
|
21
|
+
author: str = "Author",
|
|
22
|
+
version: str = "1.0",
|
|
23
|
+
) -> None:
|
|
24
|
+
"""Process a LaTeX file and generate documentation.
|
|
25
|
+
|
|
26
|
+
Loads the LaTeX file, expands its content, generates Sphinx documentation, and converts the content to Markdown.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
input_file (str): Path to the input LaTeX file.
|
|
30
|
+
output_folder (str): Path to the output folder for documentation.
|
|
31
|
+
depth (int, optional): Depth for processing sections. Defaults to 3.
|
|
32
|
+
output_suffix (str, optional): Suffix for output files. Defaults to ".md".
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
None
|
|
36
|
+
|
|
37
|
+
Example:
|
|
38
|
+
process_file("main.tex", "docs")
|
|
39
|
+
"""
|
|
40
|
+
latex_content = load_tex_file(input_file)
|
|
41
|
+
file_string = latex_content.content
|
|
42
|
+
create_sphinx_documentation(output_folder,project_name,author,version)
|
|
43
|
+
source_folder = os.path.join(output_folder, "source")
|
|
44
|
+
|
|
45
|
+
# Copy every .bib file found in the project directly to the Sphinx
|
|
46
|
+
# source folder. For .bbl files (compiled bibliography output), convert
|
|
47
|
+
# them to .bib format first so sphinxcontrib.bibtex can parse them.
|
|
48
|
+
import shutil
|
|
49
|
+
copied_bib_names: list[str] = []
|
|
50
|
+
for abs_path in latex_content.bib_files.values():
|
|
51
|
+
ext = os.path.splitext(abs_path)[1].lower()
|
|
52
|
+
if ext == '.bbl':
|
|
53
|
+
# Convert \begin{thebibliography} format → BibTeX database format
|
|
54
|
+
dest_name = os.path.splitext(os.path.basename(abs_path))[0] + '.bib'
|
|
55
|
+
dest = os.path.join(source_folder, dest_name)
|
|
56
|
+
try:
|
|
57
|
+
with open(abs_path, 'r', encoding='utf-8', errors='replace') as f:
|
|
58
|
+
bbl_content = f.read()
|
|
59
|
+
bib_content = convert_bbl_to_bib(bbl_content)
|
|
60
|
+
with open(dest, 'w', encoding='utf-8') as f:
|
|
61
|
+
f.write(bib_content)
|
|
62
|
+
copied_bib_names.append(dest_name)
|
|
63
|
+
print(f"Bibliography converted .bbl → .bib: {dest}")
|
|
64
|
+
except OSError as exc:
|
|
65
|
+
print(f"Warning: could not convert {abs_path}: {exc}")
|
|
66
|
+
else:
|
|
67
|
+
dest = os.path.join(source_folder, os.path.basename(abs_path))
|
|
68
|
+
try:
|
|
69
|
+
shutil.copy2(abs_path, dest)
|
|
70
|
+
copied_bib_names.append(os.path.basename(abs_path))
|
|
71
|
+
print(f"Bibliography file copied: {dest}")
|
|
72
|
+
except OSError as exc:
|
|
73
|
+
print(f"Warning: could not copy {abs_path}: {exc}")
|
|
74
|
+
|
|
75
|
+
process_string(source_folder, file_string, depth, output_suffix)
|
|
76
|
+
# Re-write conf.py now that custom theorem types are known.
|
|
77
|
+
create_config_file(output_folder, project_name, author, version,
|
|
78
|
+
custom_types=CUSTOM_THEOREM_TYPES,
|
|
79
|
+
bib_filenames=copied_bib_names)
|
|
80
|
+
#make_html(output_folder)
|