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.
@@ -0,0 +1,3 @@
1
+ include README.md
2
+ include requirements.txt
3
+ include LICENSE
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,4 @@
1
+ __all__ = ['filter','file_loader','sphinx_doc','process_file',"config"]
2
+
3
+ from . import filter,file_loader,sphinx_doc,config
4
+ from .core import process_file
@@ -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,9 @@
1
+ __all__ = ["set_latex_replacements"]
2
+
3
+ LATEX_REPLACEMENTS = []
4
+
5
+
6
+ def set_latex_replacements(replacements):
7
+ global LATEX_REPLACEMENTS
8
+ LATEX_REPLACEMENTS = replacements
9
+
@@ -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)