markdown_convert 1.2.15__py3-none-any.whl → 1.2.17__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.
- markdown_convert/__main__.py +95 -96
- markdown_convert/code.css +73 -73
- markdown_convert/default.css +378 -372
- markdown_convert/modules/__init__.py +4 -4
- markdown_convert/modules/constants.py +23 -26
- markdown_convert/modules/convert.py +251 -247
- markdown_convert/modules/resources.py +98 -92
- markdown_convert/modules/utils.py +38 -38
- markdown_convert/modules/validate.py +61 -61
- {markdown_convert-1.2.15.dist-info → markdown_convert-1.2.17.dist-info}/METADATA +6 -7
- markdown_convert-1.2.17.dist-info/RECORD +14 -0
- {markdown_convert-1.2.15.dist-info → markdown_convert-1.2.17.dist-info}/WHEEL +1 -1
- {markdown_convert-1.2.15.dist-info → markdown_convert-1.2.17.dist-info}/licenses/LICENSE +339 -339
- markdown_convert-1.2.15.dist-info/RECORD +0 -14
- {markdown_convert-1.2.15.dist-info → markdown_convert-1.2.17.dist-info}/entry_points.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Empty file to make the folder a package.
|
|
3
|
-
Author: @julynx
|
|
4
|
-
"""
|
|
1
|
+
"""
|
|
2
|
+
Empty file to make the folder a package.
|
|
3
|
+
Author: @julynx
|
|
4
|
+
"""
|
|
@@ -1,26 +1,23 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module contains the constants used in the markdown_convert package.
|
|
3
|
-
Author: @julynx
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
RED =
|
|
7
|
-
GREEN =
|
|
8
|
-
YELLOW =
|
|
9
|
-
BLUE =
|
|
10
|
-
MAGENTA =
|
|
11
|
-
CYAN =
|
|
12
|
-
|
|
13
|
-
OPTIONS = (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
"breaks": {"on_newline": True},
|
|
25
|
-
"tables": None
|
|
26
|
-
}
|
|
1
|
+
"""
|
|
2
|
+
This module contains the constants used in the markdown_convert package.
|
|
3
|
+
Author: @julynx
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
RED = "31"
|
|
7
|
+
GREEN = "32"
|
|
8
|
+
YELLOW = "33"
|
|
9
|
+
BLUE = "34"
|
|
10
|
+
MAGENTA = "35"
|
|
11
|
+
CYAN = "36"
|
|
12
|
+
|
|
13
|
+
OPTIONS = ("markdown_file_path", "--mode", "--css", "--out", "-h", "--help")
|
|
14
|
+
|
|
15
|
+
OPTIONS_MODES = ("once", "live", "debug")
|
|
16
|
+
|
|
17
|
+
MD_EXTENSIONS = {
|
|
18
|
+
"fenced-code-blocks": None,
|
|
19
|
+
"header-ids": None,
|
|
20
|
+
"breaks": {"on_newline": True},
|
|
21
|
+
"tables": None,
|
|
22
|
+
"latex": True,
|
|
23
|
+
}
|
|
@@ -1,247 +1,251 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Module to convert a markdown file to a pdf file.
|
|
3
|
-
Author: @julynx
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import os
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
from
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
"""
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
self.
|
|
189
|
-
self.
|
|
190
|
-
self.
|
|
191
|
-
self.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
self.
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
"""
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
self.
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
self.
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
1
|
+
"""
|
|
2
|
+
Module to convert a markdown file to a pdf file.
|
|
3
|
+
Author: @julynx
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import time
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import markdown2
|
|
12
|
+
from playwright.sync_api import sync_playwright
|
|
13
|
+
|
|
14
|
+
from .resources import get_css_path, get_code_css_path, get_output_path
|
|
15
|
+
from .utils import drop_duplicates
|
|
16
|
+
from .constants import MD_EXTENSIONS
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _generate_pdf_with_playwright(html_content, output_path):
|
|
20
|
+
"""
|
|
21
|
+
Generate a PDF from HTML content using Playwright.
|
|
22
|
+
"""
|
|
23
|
+
with sync_playwright() as p:
|
|
24
|
+
browser = p.chromium.launch(headless=True)
|
|
25
|
+
page = browser.new_page()
|
|
26
|
+
page.set_content(html_content)
|
|
27
|
+
# Wait for any potential resources to load
|
|
28
|
+
page.wait_for_load_state("networkidle")
|
|
29
|
+
|
|
30
|
+
pdf_params = {
|
|
31
|
+
"format": "A4",
|
|
32
|
+
"print_background": True,
|
|
33
|
+
"margin": {
|
|
34
|
+
"top": "20mm",
|
|
35
|
+
"bottom": "20mm",
|
|
36
|
+
"left": "20mm",
|
|
37
|
+
"right": "20mm",
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if output_path:
|
|
42
|
+
page.pdf(path=output_path, **pdf_params)
|
|
43
|
+
browser.close()
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
pdf_bytes = page.pdf(**pdf_params)
|
|
47
|
+
browser.close()
|
|
48
|
+
return pdf_bytes
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _embed_css_in_html(html, css_sources):
|
|
52
|
+
"""
|
|
53
|
+
Embed CSS styles into HTML content.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
html (str): HTML content.
|
|
57
|
+
css_sources (list): List of CSS file paths.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
HTML content with embedded CSS styles.
|
|
61
|
+
"""
|
|
62
|
+
css_buffer = ""
|
|
63
|
+
for css_file in css_sources:
|
|
64
|
+
css_buffer += Path(css_file).read_text(encoding="utf-8") + "\n"
|
|
65
|
+
|
|
66
|
+
style_tag = f"<style>\n{css_buffer}\n</style>\n"
|
|
67
|
+
return f"<!DOCTYPE html>\n<html>\n<head>\n{style_tag}</head>\n<body>\n{html}\n</body>\n</html>"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def convert(
|
|
71
|
+
md_path,
|
|
72
|
+
css_path=None,
|
|
73
|
+
output_path=None,
|
|
74
|
+
*,
|
|
75
|
+
extend_default_css=True,
|
|
76
|
+
dump_html=False,
|
|
77
|
+
):
|
|
78
|
+
"""
|
|
79
|
+
Convert a markdown file to a pdf file.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
md_path (str): Path to the markdown file.
|
|
83
|
+
css_path (str=None): Path to the CSS file.
|
|
84
|
+
output_path (str=None): Path to the output file.
|
|
85
|
+
extend_default_css (bool=True): Extend the default CSS file.
|
|
86
|
+
dump_html (bool=False): Dump the intermediate HTML to a file.
|
|
87
|
+
"""
|
|
88
|
+
if css_path is None:
|
|
89
|
+
css_path = get_css_path()
|
|
90
|
+
|
|
91
|
+
if output_path is None:
|
|
92
|
+
output_path = get_output_path(md_path, None)
|
|
93
|
+
|
|
94
|
+
if extend_default_css:
|
|
95
|
+
css_sources = [get_code_css_path(), get_css_path(), css_path]
|
|
96
|
+
else:
|
|
97
|
+
css_sources = [get_code_css_path(), css_path]
|
|
98
|
+
|
|
99
|
+
css_sources = drop_duplicates(css_sources)
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
html = markdown2.markdown_path(md_path, extras=MD_EXTENSIONS)
|
|
103
|
+
html = _embed_css_in_html(html, css_sources)
|
|
104
|
+
|
|
105
|
+
if dump_html:
|
|
106
|
+
html_dump_path = Path(output_path).with_suffix(".html")
|
|
107
|
+
html_dump_path.write_text(html, encoding="utf-8")
|
|
108
|
+
|
|
109
|
+
_generate_pdf_with_playwright(html, output_path)
|
|
110
|
+
|
|
111
|
+
except Exception as exc:
|
|
112
|
+
raise RuntimeError(exc) from exc
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def live_convert(md_path, css_path=None, output_path=None, *, extend_default_css=True):
|
|
116
|
+
"""
|
|
117
|
+
Convert a markdown file to a pdf file and watch for changes.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
md_path (str): Path to the markdown file.
|
|
121
|
+
css_path (str=None): Path to the CSS file.
|
|
122
|
+
output_path (str=None): Path to the output file.
|
|
123
|
+
extend_default_css (bool=True): Extend the default CSS file.
|
|
124
|
+
"""
|
|
125
|
+
if css_path is None:
|
|
126
|
+
css_path = get_css_path()
|
|
127
|
+
|
|
128
|
+
if output_path is None:
|
|
129
|
+
output_path = get_output_path(md_path, None)
|
|
130
|
+
|
|
131
|
+
live_converter = LiveConverter(
|
|
132
|
+
md_path, css_path, output_path, extend_default_css=extend_default_css, loud=True
|
|
133
|
+
)
|
|
134
|
+
live_converter.observe()
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def convert_text(md_text, css_text=None, *, extend_default_css=True):
|
|
138
|
+
"""
|
|
139
|
+
Convert markdown text to a pdf file.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
md_text (str): Markdown text.
|
|
143
|
+
css_text (str=None): CSS text.
|
|
144
|
+
extend_default_css (bool=True): Extend the default CSS file.
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
PDF file as bytes.
|
|
148
|
+
"""
|
|
149
|
+
default_css = Path(get_css_path()).read_text(encoding="utf-8")
|
|
150
|
+
code_css = Path(get_code_css_path()).read_text(encoding="utf-8")
|
|
151
|
+
|
|
152
|
+
if css_text is None:
|
|
153
|
+
css_text = default_css
|
|
154
|
+
|
|
155
|
+
if extend_default_css:
|
|
156
|
+
css_sources = [code_css, default_css, css_text]
|
|
157
|
+
else:
|
|
158
|
+
css_sources = [code_css, css_text]
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
html = markdown2.markdown(md_text, extras=MD_EXTENSIONS)
|
|
162
|
+
html = _embed_css_in_html(html, css_sources)
|
|
163
|
+
|
|
164
|
+
return _generate_pdf_with_playwright(html, None)
|
|
165
|
+
|
|
166
|
+
except Exception as exc:
|
|
167
|
+
raise RuntimeError(exc) from exc
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class LiveConverter:
|
|
171
|
+
"""
|
|
172
|
+
Class to convert a markdown file to a pdf file and watch for changes.
|
|
173
|
+
"""
|
|
174
|
+
|
|
175
|
+
def __init__(
|
|
176
|
+
self, md_path, css_path, output_path, *, extend_default_css=True, loud=False
|
|
177
|
+
):
|
|
178
|
+
"""
|
|
179
|
+
Initialize the LiveConverter class.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
md_path (str): Path to the markdown file.
|
|
183
|
+
css_path (str): Path to the CSS file.
|
|
184
|
+
output_path (str): Path to the output file.
|
|
185
|
+
extend_default_css (bool): Extend the default CSS file.
|
|
186
|
+
"""
|
|
187
|
+
self.md_path = Path(md_path).absolute()
|
|
188
|
+
self.css_path = Path(css_path).absolute()
|
|
189
|
+
self.output_path = output_path
|
|
190
|
+
self.extend_default_css = extend_default_css
|
|
191
|
+
self.loud = loud
|
|
192
|
+
|
|
193
|
+
self.md_last_modified = None
|
|
194
|
+
self.css_last_modified = None
|
|
195
|
+
|
|
196
|
+
def get_last_modified_date(self, file_path):
|
|
197
|
+
"""
|
|
198
|
+
Get the last modified date of a file.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
file_path (str): Path to the file.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
Last modified date of the file.
|
|
205
|
+
"""
|
|
206
|
+
return os.path.getmtime(file_path)
|
|
207
|
+
|
|
208
|
+
def write_pdf(self):
|
|
209
|
+
"""
|
|
210
|
+
Write the pdf file.
|
|
211
|
+
"""
|
|
212
|
+
convert(
|
|
213
|
+
self.md_path,
|
|
214
|
+
self.css_path,
|
|
215
|
+
self.output_path,
|
|
216
|
+
extend_default_css=self.extend_default_css,
|
|
217
|
+
)
|
|
218
|
+
if self.loud:
|
|
219
|
+
print(f"- PDF file updated: {datetime.now()}", flush=True)
|
|
220
|
+
|
|
221
|
+
def observe(self, poll_interval=1):
|
|
222
|
+
"""
|
|
223
|
+
Observe the markdown and CSS files. Calls write_pdf() when a file is
|
|
224
|
+
modified.
|
|
225
|
+
"""
|
|
226
|
+
self.write_pdf()
|
|
227
|
+
|
|
228
|
+
self.md_last_modified = self.get_last_modified_date(self.md_path)
|
|
229
|
+
self.css_last_modified = self.get_last_modified_date(self.css_path)
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
while True:
|
|
233
|
+
|
|
234
|
+
md_modified = self.get_last_modified_date(self.md_path)
|
|
235
|
+
css_modified = self.get_last_modified_date(self.css_path)
|
|
236
|
+
|
|
237
|
+
if (
|
|
238
|
+
md_modified != self.md_last_modified
|
|
239
|
+
or css_modified != self.css_last_modified
|
|
240
|
+
):
|
|
241
|
+
|
|
242
|
+
self.write_pdf()
|
|
243
|
+
|
|
244
|
+
self.md_last_modified = md_modified
|
|
245
|
+
self.css_last_modified = css_modified
|
|
246
|
+
|
|
247
|
+
time.sleep(poll_interval)
|
|
248
|
+
|
|
249
|
+
except KeyboardInterrupt:
|
|
250
|
+
if self.loud:
|
|
251
|
+
print("\nInterrupted by user.\n", flush=True)
|