markdown_convert 1.2.39__py3-none-any.whl → 1.2.41__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.
@@ -5,7 +5,6 @@ CLI interface to convert markdown files to pdf.
5
5
  Author: @julynx
6
6
  """
7
7
 
8
-
9
8
  from sys import exit as sys_exit
10
9
 
11
10
  from argsdict import args
@@ -78,7 +77,6 @@ def main():
78
77
 
79
78
  # pylint: disable=W0718
80
79
  except Exception as err:
81
-
82
80
  asked_for_help = "--help" in arg or "-h" in arg
83
81
  show_usage = isinstance(err, (IndexError, ValueError)) or asked_for_help
84
82
 
@@ -154,11 +154,13 @@ blockquote>blockquote {
154
154
  padding-left: var(--left-margin-small);
155
155
  }
156
156
 
157
- /* Figures */
158
157
  img {
158
+ max-width: 80vw;
159
+ max-height: 80vh;
160
+ width: auto;
161
+ height: auto;
159
162
  display: block;
160
163
  margin: 2em auto 1em auto;
161
- max-width: 80%;
162
164
  }
163
165
 
164
166
  /* -- Figure footer */
@@ -23,3 +23,34 @@ MARKDOWN_EXTENSIONS = {
23
23
  "mermaid": None,
24
24
  "strike": None,
25
25
  }
26
+
27
+ BROWSER_ARGS = [
28
+ "--disable-dev-shm-usage",
29
+ "--disable-extensions",
30
+ "--disable-plugins",
31
+ "--disable-gpu",
32
+ "--no-first-run",
33
+ "--no-default-browser-check",
34
+ ]
35
+
36
+ CSP_TEMPLATE = (
37
+ "default-src 'none'; "
38
+ "script-src 'nonce-{nonce}' https://cdn.jsdelivr.net; " # <- Script for Mermaid diagrams
39
+ "script-src-elem 'nonce-{nonce}' https://cdn.jsdelivr.net; "
40
+ "style-src 'unsafe-inline'; "
41
+ "img-src data: https: file:; "
42
+ "font-src data: https:; "
43
+ "connect-src https://cdn.jsdelivr.net;"
44
+ )
45
+
46
+ PDF_PARAMS = {
47
+ "format": "A4",
48
+ "print_background": True,
49
+ "margin": {
50
+ "top": "20mm",
51
+ "bottom": "20mm",
52
+ "left": "20mm",
53
+ "right": "20mm",
54
+ },
55
+ "path": None, # <- Replace with actual output path when used
56
+ }
@@ -12,7 +12,7 @@ from pathlib import Path
12
12
  import markdown2
13
13
  from playwright.sync_api import sync_playwright
14
14
 
15
- from .constants import MARKDOWN_EXTENSIONS
15
+ from .constants import MARKDOWN_EXTENSIONS, BROWSER_ARGS, CSP_TEMPLATE, PDF_PARAMS
16
16
  from .resources import get_code_css_path, get_css_path, get_output_path
17
17
  from .transform import (
18
18
  create_sections,
@@ -41,39 +41,17 @@ def _generate_pdf_with_playwright(
41
41
  css_content (str, optional): CSS content to inject.
42
42
  base_dir (Path, optional): Base directory for resolving relative paths in HTML.
43
43
  dump_html (bool, optional): Whether to dump the HTML content to a file.
44
+ nonce (str, optional): Nonce for Content Security Policy.
44
45
  """
45
- # Generate a cryptographic nonce for the Mermaid script
46
+ if nonce is None:
47
+ raise ValueError("A nonce must be provided for CSP generation.")
46
48
 
47
- # Content Security Policy using nonce to whitelist only the Mermaid initialization script
48
49
  # This prevents arbitrary JavaScript injection while allowing Mermaid to work
49
- csp = (
50
- "default-src 'none'; "
51
- f"script-src 'nonce-{nonce}' https://cdn.jsdelivr.net; "
52
- f"script-src-elem 'nonce-{nonce}' https://cdn.jsdelivr.net; "
53
- "style-src 'unsafe-inline'; "
54
- "img-src data: https: file:; "
55
- "font-src data: https:; "
56
- "connect-src https://cdn.jsdelivr.net;"
57
- )
58
-
59
- # Wrap HTML content with CSP and CSS
60
- if css_content:
61
- full_html = create_html_document(html_content, css_content, csp)
62
- else:
63
- full_html = html_content
50
+ csp = CSP_TEMPLATE.format(nonce=nonce)
51
+ full_html = create_html_document(html_content, css_content, csp)
64
52
 
65
53
  with sync_playwright() as playwright:
66
- browser = playwright.chromium.launch(
67
- headless=True,
68
- args=[
69
- "--disable-dev-shm-usage",
70
- "--disable-extensions",
71
- "--disable-plugins",
72
- "--disable-gpu",
73
- "--no-first-run",
74
- "--no-default-browser-check",
75
- ],
76
- )
54
+ browser = playwright.chromium.launch(headless=True, args=BROWSER_ARGS)
77
55
  context = browser.new_context(
78
56
  java_script_enabled=True,
79
57
  permissions=[],
@@ -82,7 +60,6 @@ def _generate_pdf_with_playwright(
82
60
  )
83
61
  page = context.new_page()
84
62
 
85
- # Handle loading based on presence of base_dir
86
63
  temp_html = None
87
64
  try:
88
65
  if base_dir:
@@ -93,16 +70,9 @@ def _generate_pdf_with_playwright(
93
70
  page.set_content(full_html, wait_until="networkidle", timeout=30000)
94
71
 
95
72
  pdf_params = {
96
- "format": "A4",
97
- "print_background": True,
98
- "margin": {
99
- "top": "20mm",
100
- "bottom": "20mm",
101
- "left": "20mm",
102
- "right": "20mm",
103
- },
73
+ **PDF_PARAMS,
104
74
  "path": output_path,
105
- } # Playwright ignores None paths
75
+ }
106
76
 
107
77
  pdf_bytes = page.pdf(**pdf_params)
108
78
  return None if output_path else pdf_bytes
@@ -240,7 +210,7 @@ def convert_text(markdown_text, css_text=None, *, extend_default_css=True):
240
210
  return _generate_pdf_with_playwright(
241
211
  html,
242
212
  None,
243
- css_content=_get_css_content(css_sources),
213
+ css_content="\n".join(css_sources),
244
214
  nonce=nonce,
245
215
  )
246
216
 
@@ -317,7 +287,6 @@ class LiveConverter:
317
287
 
318
288
  try:
319
289
  while True:
320
-
321
290
  markdown_modified = self.get_last_modified_date(self.md_path)
322
291
  css_modified = self.get_last_modified_date(self.css_path)
323
292
 
@@ -325,7 +294,6 @@ class LiveConverter:
325
294
  markdown_modified != self.md_last_modified
326
295
  or css_modified != self.css_last_modified
327
296
  ):
328
-
329
297
  self.write_pdf()
330
298
 
331
299
  self.md_last_modified = markdown_modified
@@ -21,13 +21,13 @@ def create_html_document(html_content, css_content, csp):
21
21
  <html>
22
22
  <head>
23
23
  <meta charset="UTF-8">
24
- <meta http-equiv="Content-Security-Policy" content="{csp}">
24
+ <meta http-equiv="Content-Security-Policy" content="{csp or ""}">
25
25
  <style>
26
- {css_content}
26
+ {css_content or ""}
27
27
  </style>
28
28
  </head>
29
29
  <body>
30
- {html_content}
30
+ {html_content or ""}
31
31
  </body>
32
32
  </html>"""
33
33
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markdown_convert
3
- Version: 1.2.39
3
+ Version: 1.2.41
4
4
  Summary: Convert Markdown files to PDF from your command line.
5
5
  Project-URL: homepage, https://github.com/Julynx/markdown_convert
6
6
  Author-email: Julio Cabria <juliocabria@tutanota.com>
@@ -9,7 +9,7 @@ License-File: LICENSE
9
9
  Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
10
10
  Classifier: Operating System :: OS Independent
11
11
  Classifier: Programming Language :: Python :: 3
12
- Requires-Python: <3.15,>=3.9
12
+ Requires-Python: <3.15,>=3.11
13
13
  Requires-Dist: argsdict==1.0.0
14
14
  Requires-Dist: beautifulsoup4>=4.14.3
15
15
  Requires-Dist: latex2mathml>=3.78.1
@@ -0,0 +1,16 @@
1
+ markdown_convert/__init__.py,sha256=ysW3pXsDGGK4PzZHcIBTpfVW58IkDUwHffDkf_GM6UU,303
2
+ markdown_convert/__main__.py,sha256=w6sHfJcJQpMOERPqiNoKgoRM38YUwK22eGBmVkpZj1g,2807
3
+ markdown_convert/code.css,sha256=Wt4FqFqJcpT-jwY3GN-o4ZRCCXU8DQj-9lqKdGiuoyw,4935
4
+ markdown_convert/default.css,sha256=rIwRao7l7Rq6rkOaxVMfZ4yGQc2D68eJ7URLQ597GcY,3530
5
+ markdown_convert/modules/__init__.py,sha256=PFPgiQhMXgyfjD8BkfLC_X8AR1jz-dCxfif2qmNofJs,65
6
+ markdown_convert/modules/constants.py,sha256=eUeIFRxZerP3E0Rgp_Nsl0Q38IBELwca5UO3fbUcxRA,1280
7
+ markdown_convert/modules/convert.py,sha256=02N_Iz4TLKWR1xseNv8hyCTujCJdYepWZlxjXw9tsj0,8876
8
+ markdown_convert/modules/resources.py,sha256=tnW8JmCrJNBRbzOcaOVG6GX5jPC8Kzj3dA7gX0B935A,2488
9
+ markdown_convert/modules/transform.py,sha256=p7J8LJKBjMA_EtUYIfXqw_Tc1eean7EbM6KW5Tv4AOs,3138
10
+ markdown_convert/modules/utils.py,sha256=NX0WegM8e8MPKNNmweTujAWO8ZghdB8LSGDx20K2E44,655
11
+ markdown_convert/modules/validate.py,sha256=XV_k7cHeifEKDaltF26tCmabs2-Me5msP3enI_eVwfA,1517
12
+ markdown_convert-1.2.41.dist-info/METADATA,sha256=ATlu-Biqp5xWcJgxvd9YtO72VtglXtREg2T5JvN0pTw,3940
13
+ markdown_convert-1.2.41.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
14
+ markdown_convert-1.2.41.dist-info/entry_points.txt,sha256=RCmzC7C0sX-SpzIP2Cr34rhg3lMd7BRx-exaZPfK8bU,68
15
+ markdown_convert-1.2.41.dist-info/licenses/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
16
+ markdown_convert-1.2.41.dist-info/RECORD,,
@@ -1,16 +0,0 @@
1
- markdown_convert/__init__.py,sha256=ysW3pXsDGGK4PzZHcIBTpfVW58IkDUwHffDkf_GM6UU,303
2
- markdown_convert/__main__.py,sha256=hO7AO0GnzPMPNqls8r5aF2C-7l9aFHDf1m8mXSy1GBE,2809
3
- markdown_convert/code.css,sha256=Wt4FqFqJcpT-jwY3GN-o4ZRCCXU8DQj-9lqKdGiuoyw,4935
4
- markdown_convert/default.css,sha256=4S8lVclp-GMvpalFRS2Q-_7fDNhnweWE_UQDVbpTYng,3492
5
- markdown_convert/modules/__init__.py,sha256=PFPgiQhMXgyfjD8BkfLC_X8AR1jz-dCxfif2qmNofJs,65
6
- markdown_convert/modules/constants.py,sha256=_h6N0fhG9K1hQPmp3eYu53TfQnAPe7RtmMj-2FCD7VU,495
7
- markdown_convert/modules/convert.py,sha256=R1xIKW6UVGP7a6VK5C6qLK278wBlHZV9X6Y9q73mz_k,9843
8
- markdown_convert/modules/resources.py,sha256=tnW8JmCrJNBRbzOcaOVG6GX5jPC8Kzj3dA7gX0B935A,2488
9
- markdown_convert/modules/transform.py,sha256=uQbTtiSKDTXRs49OuDazpD2nSya4fpghzMS4BZ9zm_8,3120
10
- markdown_convert/modules/utils.py,sha256=NX0WegM8e8MPKNNmweTujAWO8ZghdB8LSGDx20K2E44,655
11
- markdown_convert/modules/validate.py,sha256=XV_k7cHeifEKDaltF26tCmabs2-Me5msP3enI_eVwfA,1517
12
- markdown_convert-1.2.39.dist-info/METADATA,sha256=OwYd5H8EW8YWWK2-Nx2CrCYDDssUwmw6A_hJXc2UlQ8,3939
13
- markdown_convert-1.2.39.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
14
- markdown_convert-1.2.39.dist-info/entry_points.txt,sha256=RCmzC7C0sX-SpzIP2Cr34rhg3lMd7BRx-exaZPfK8bU,68
15
- markdown_convert-1.2.39.dist-info/licenses/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
16
- markdown_convert-1.2.39.dist-info/RECORD,,