markdown-to-confluence 0.4.5__tar.gz → 0.4.6__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.
Files changed (103) hide show
  1. {markdown_to_confluence-0.4.5/markdown_to_confluence.egg-info → markdown_to_confluence-0.4.6}/PKG-INFO +35 -13
  2. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/README.md +32 -12
  3. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6/markdown_to_confluence.egg-info}/PKG-INFO +35 -13
  4. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/markdown_to_confluence.egg-info/SOURCES.txt +3 -2
  5. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/markdown_to_confluence.egg-info/requires.txt +6 -0
  6. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/__init__.py +1 -1
  7. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/__main__.py +16 -35
  8. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/api.py +84 -20
  9. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/converter.py +69 -34
  10. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/csf.py +1 -1
  11. markdown_to_confluence-0.4.6/md2conf/emoticon.py +22 -0
  12. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/mermaid.py +18 -3
  13. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/processor.py +1 -1
  14. markdown_to_confluence-0.4.5/md2conf/application.py → markdown_to_confluence-0.4.6/md2conf/publisher.py +14 -11
  15. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/scanner.py +46 -0
  16. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/pyproject.toml +2 -0
  17. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/emoji.py +14 -3
  18. markdown_to_confluence-0.4.6/tests/source/missing.md +13 -0
  19. markdown_to_confluence-0.4.6/tests/target/missing.xml +16 -0
  20. markdown_to_confluence-0.4.6/tests/target/table.xml +81 -0
  21. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/tags.xml +8 -8
  22. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/test_conversion.py +3 -5
  23. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/test_scanner.py +40 -1
  24. markdown_to_confluence-0.4.5/tests/source/missing.md +0 -7
  25. markdown_to_confluence-0.4.5/tests/target/missing.xml +0 -13
  26. markdown_to_confluence-0.4.5/tests/target/table.xml +0 -81
  27. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/LICENSE +0 -0
  28. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/MANIFEST.in +0 -0
  29. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/markdown_to_confluence.egg-info/dependency_links.txt +0 -0
  30. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/markdown_to_confluence.egg-info/entry_points.txt +0 -0
  31. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/markdown_to_confluence.egg-info/top_level.txt +0 -0
  32. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/markdown_to_confluence.egg-info/zip-safe +0 -0
  33. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/collection.py +0 -0
  34. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/domain.py +0 -0
  35. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/drawio.py +0 -0
  36. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/entities.dtd +0 -0
  37. /markdown_to_confluence-0.4.5/md2conf/properties.py → /markdown_to_confluence-0.4.6/md2conf/environment.py +0 -0
  38. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/extra.py +0 -0
  39. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/latex.py +0 -0
  40. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/local.py +0 -0
  41. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/markdown.py +0 -0
  42. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/matcher.py +0 -0
  43. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/metadata.py +0 -0
  44. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/puppeteer-config.json +0 -0
  45. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/py.typed +0 -0
  46. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/text.py +0 -0
  47. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/toc.py +0 -0
  48. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/uri.py +0 -0
  49. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/md2conf/xml.py +0 -0
  50. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/setup.cfg +0 -0
  51. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/setup.py +0 -0
  52. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/__init__.py +0 -0
  53. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/admonition.md +0 -0
  54. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/alert.md +0 -0
  55. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/anchors.md +0 -0
  56. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/basic.md +0 -0
  57. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/code.md +0 -0
  58. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/collapsed.md +0 -0
  59. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/fenced.md +0 -0
  60. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/figure/diagram.drawio +0 -0
  61. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/figure/diagram.drawio.png +0 -0
  62. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/figure/diagram.drawio.svg +0 -0
  63. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/figure/raster.png +0 -0
  64. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/figure/vector.svg +0 -0
  65. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/footnote.md +0 -0
  66. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/ignore.md +0 -0
  67. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/images/images.md +0 -0
  68. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/images.md +0 -0
  69. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/macro.md +0 -0
  70. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/math.md +0 -0
  71. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/mermaid.md +0 -0
  72. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/sections.md +0 -0
  73. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/status.md +0 -0
  74. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/table.md +0 -0
  75. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/tags.md +0 -0
  76. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/tasklist.md +0 -0
  77. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/title.md +0 -0
  78. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/source/toc.md +0 -0
  79. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/admonition.xml +0 -0
  80. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/alert.xml +0 -0
  81. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/anchors.xml +0 -0
  82. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/basic.xml +0 -0
  83. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/code.xml +0 -0
  84. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/collapsed.xml +0 -0
  85. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/fenced.xml +0 -0
  86. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/footnote.xml +0 -0
  87. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/images/images.xml +0 -0
  88. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/images.xml +0 -0
  89. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/macro.xml +0 -0
  90. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/math.xml +0 -0
  91. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/mermaid.xml +0 -0
  92. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/sections.xml +0 -0
  93. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/status.xml +0 -0
  94. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/tasklist.xml +0 -0
  95. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/target/toc.xml +0 -0
  96. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/test_drawio.py +0 -0
  97. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/test_matcher.py +0 -0
  98. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/test_mermaid.py +0 -0
  99. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/test_processor.py +0 -0
  100. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/test_text.py +0 -0
  101. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/test_unit.py +0 -0
  102. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/test_xml.py +0 -0
  103. {markdown_to_confluence-0.4.5 → markdown_to_confluence-0.4.6}/tests/utility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markdown-to-confluence
3
- Version: 0.4.5
3
+ Version: 0.4.6
4
4
  Summary: Publish Markdown files to Confluence wiki
5
5
  Author-email: Levente Hunyadi <hunyadi@gmail.com>
6
6
  Maintainer-email: Levente Hunyadi <hunyadi@gmail.com>
@@ -23,12 +23,14 @@ Classifier: Typing :: Typed
23
23
  Requires-Python: >=3.9
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE
26
+ Requires-Dist: certifi>=2025.8.3; python_version < "3.10"
26
27
  Requires-Dist: json_strong_typing>=0.4
27
28
  Requires-Dist: lxml>=6.0
28
29
  Requires-Dist: markdown>=3.8
29
30
  Requires-Dist: pymdown-extensions>=10.16
30
31
  Requires-Dist: PyYAML>=6.0
31
32
  Requires-Dist: requests>=2.32
33
+ Requires-Dist: truststore>=0.10; python_version >= "3.10"
32
34
  Requires-Dist: typing-extensions>=4.14; python_version < "3.12"
33
35
  Provides-Extra: dev
34
36
  Requires-Dist: markdown_doc>=0.1.4; python_version >= "3.10" and extra == "dev"
@@ -143,7 +145,7 @@ export CONFLUENCE_SPACE_KEY='SPACE'
143
145
 
144
146
  On Windows, these can be set via system properties.
145
147
 
146
- If you use Atlassian scoped API tokens, you should set API URL, substituting `CLOUD_ID` with your own Cloud ID:
148
+ If you use Atlassian scoped API tokens, you may want to set API URL directly, substituting `CLOUD_ID` with your own Cloud ID:
147
149
 
148
150
  ```sh
149
151
  export CONFLUENCE_API_URL='https://api.atlassian.com/ex/confluence/CLOUD_ID/'
@@ -151,20 +153,27 @@ export CONFLUENCE_API_URL='https://api.atlassian.com/ex/confluence/CLOUD_ID/'
151
153
 
152
154
  In this case, *md2conf* can automatically determine `CONFLUENCE_DOMAIN` and `CONFLUENCE_PATH`.
153
155
 
156
+ If you can't find your `CLOUD_ID` but assign both `CONFLUENCE_DOMAIN` and `CONFLUENCE_PATH`, *md2conf* makes a best-effort attempt to determine `CONFLUENCE_API_URL`.
157
+
154
158
  ### Permissions
155
159
 
156
160
  The tool requires appropriate permissions in Confluence in order to invoke endpoints.
157
161
 
158
- Required scopes for scoped API tokens are as follows:
162
+ We recommend the following scopes for scoped API tokens:
159
163
 
164
+ * `read:attachment:confluence`
165
+ * `read:content:confluence`
166
+ * `read:content-details:confluence`
167
+ * `read:label:confluence`
160
168
  * `read:page:confluence`
161
- * `write:page:confluence`
162
169
  * `read:space:confluence`
163
- * `write:space:confluence`
164
- * `read:attachment:confluence`
165
170
  * `write:attachment:confluence`
166
- * `read:label:confluence`
171
+ * `write:content:confluence`
167
172
  * `write:label:confluence`
173
+ * `write:page:confluence`
174
+ * `delete:attachment:confluence`
175
+ * `delete:content:confluence`
176
+ * `delete:page:confluence`
168
177
 
169
178
  If a Confluence username is set, the tool uses HTTP *Basic* authentication to pass the username and the API key to Confluence REST API endpoints. If no username is provided, the tool authenticates with HTTP *Bearer*, and passes the API key as the bearer token.
170
179
 
@@ -331,6 +340,21 @@ The following table shows standard highlight colors (CSS `background-color`) tha
331
340
 
332
341
  If your Markdown lists or tables don't appear in Confluence as expected, verify that the list or table is delimited by a blank line both before and after, as per strict Markdown syntax. While some previewers accept a more lenient syntax (e.g. an itemized list immediately following a paragraph), *md2conf* uses [Python-Markdown](https://python-markdown.github.io/) internally to convert Markdown into XHTML, which expects the Markdown document to adhere to the stricter syntax.
333
342
 
343
+ Likewise, if you have a nested list, make sure that nested items are indented by exactly ***four*** spaces as compared to the parent node:
344
+
345
+ ```markdown
346
+ 1. List item 1
347
+ * Nested item 1
348
+ 1. Item 1
349
+ 2. Item 2
350
+ * Nested item 2
351
+ - Item 3
352
+ - Item 4
353
+ 2. List item 2
354
+ 1. Nested item 3
355
+ 2. Nested item 4
356
+ ```
357
+
334
358
  ### Publishing images
335
359
 
336
360
  Local images referenced in a Markdown file are automatically published to Confluence as attachments to the page.
@@ -348,7 +372,7 @@ Inline formulas can be enclosed with `$` signs, or delimited with `\(` and `\)`,
348
372
 
349
373
  Block formulas can be enclosed with `$$`, or wrapped in code blocks specifying the language `math`:
350
374
 
351
- ```md
375
+ ```markdown
352
376
  $$\int _{a}^{b}f(x)dx=F(b)-F(a)$$
353
377
  ```
354
378
 
@@ -385,7 +409,7 @@ Displaying math formulas in Confluence requires the extension [LaTeX Math for Co
385
409
 
386
410
  Use the pseudo-language `csf` in a Markdown code block to pass content directly to Confluence. The content must be a single XML node that conforms to Confluence Storage Format (typically an `ac:structured-macro`) but is otherwise not validated. The following example shows how to create a panel similar to an *info panel* but with custom background color and emoji. Notice that `ac:rich-text-body` uses XHTML, not Markdown.
387
411
 
388
- ````md
412
+ ````markdown
389
413
  ```csf
390
414
  <ac:structured-macro ac:name="panel" ac:schema-version="1">
391
415
  <ac:parameter ac:name="panelIcon">:slight_smile:</ac:parameter>
@@ -496,7 +520,7 @@ If *md2conf* encounters a Markdown link that points to a file in the directory h
496
520
 
497
521
  *md2conf* implicitly defines some URLs, as if you included the following at the start of the Markdown document for each URL:
498
522
 
499
- ```md
523
+ ```markdown
500
524
  [CUSTOM-URL]: https://example.com/path/to/resource
501
525
  ```
502
526
 
@@ -531,7 +555,7 @@ options:
531
555
  --api-url API_URL Confluence API URL. Required for scoped tokens. Refer to documentation how to obtain one.
532
556
  -u, --username USERNAME
533
557
  Confluence user name.
534
- -a, --apikey, --api-key API_KEY
558
+ -a, --api-key API_KEY
535
559
  Confluence API key. Refer to documentation how to obtain one.
536
560
  -s, --space SPACE Confluence space key for pages to be published. If omitted, will default to user space.
537
561
  -l, --loglevel {debug,info,warning,error,critical}
@@ -550,8 +574,6 @@ options:
550
574
  --no-render-latex Inline LaTeX formulas in Confluence page. (Marketplace app required to display.)
551
575
  --diagram-output-format {png,svg}
552
576
  Format for rendering Mermaid and draw.io diagrams (default: 'png').
553
- --render-mermaid-format FORMAT
554
- Format for rendering Mermaid diagrams (default: 'png').
555
577
  --heading-anchors Place an anchor at each section heading with GitHub-style same-page identifiers.
556
578
  --no-heading-anchors Don't place an anchor at each section heading.
557
579
  --ignore-invalid-url Emit a warning but otherwise ignore relative URLs that point to ill-specified locations.
@@ -99,7 +99,7 @@ export CONFLUENCE_SPACE_KEY='SPACE'
99
99
 
100
100
  On Windows, these can be set via system properties.
101
101
 
102
- If you use Atlassian scoped API tokens, you should set API URL, substituting `CLOUD_ID` with your own Cloud ID:
102
+ If you use Atlassian scoped API tokens, you may want to set API URL directly, substituting `CLOUD_ID` with your own Cloud ID:
103
103
 
104
104
  ```sh
105
105
  export CONFLUENCE_API_URL='https://api.atlassian.com/ex/confluence/CLOUD_ID/'
@@ -107,20 +107,27 @@ export CONFLUENCE_API_URL='https://api.atlassian.com/ex/confluence/CLOUD_ID/'
107
107
 
108
108
  In this case, *md2conf* can automatically determine `CONFLUENCE_DOMAIN` and `CONFLUENCE_PATH`.
109
109
 
110
+ If you can't find your `CLOUD_ID` but assign both `CONFLUENCE_DOMAIN` and `CONFLUENCE_PATH`, *md2conf* makes a best-effort attempt to determine `CONFLUENCE_API_URL`.
111
+
110
112
  ### Permissions
111
113
 
112
114
  The tool requires appropriate permissions in Confluence in order to invoke endpoints.
113
115
 
114
- Required scopes for scoped API tokens are as follows:
116
+ We recommend the following scopes for scoped API tokens:
115
117
 
118
+ * `read:attachment:confluence`
119
+ * `read:content:confluence`
120
+ * `read:content-details:confluence`
121
+ * `read:label:confluence`
116
122
  * `read:page:confluence`
117
- * `write:page:confluence`
118
123
  * `read:space:confluence`
119
- * `write:space:confluence`
120
- * `read:attachment:confluence`
121
124
  * `write:attachment:confluence`
122
- * `read:label:confluence`
125
+ * `write:content:confluence`
123
126
  * `write:label:confluence`
127
+ * `write:page:confluence`
128
+ * `delete:attachment:confluence`
129
+ * `delete:content:confluence`
130
+ * `delete:page:confluence`
124
131
 
125
132
  If a Confluence username is set, the tool uses HTTP *Basic* authentication to pass the username and the API key to Confluence REST API endpoints. If no username is provided, the tool authenticates with HTTP *Bearer*, and passes the API key as the bearer token.
126
133
 
@@ -287,6 +294,21 @@ The following table shows standard highlight colors (CSS `background-color`) tha
287
294
 
288
295
  If your Markdown lists or tables don't appear in Confluence as expected, verify that the list or table is delimited by a blank line both before and after, as per strict Markdown syntax. While some previewers accept a more lenient syntax (e.g. an itemized list immediately following a paragraph), *md2conf* uses [Python-Markdown](https://python-markdown.github.io/) internally to convert Markdown into XHTML, which expects the Markdown document to adhere to the stricter syntax.
289
296
 
297
+ Likewise, if you have a nested list, make sure that nested items are indented by exactly ***four*** spaces as compared to the parent node:
298
+
299
+ ```markdown
300
+ 1. List item 1
301
+ * Nested item 1
302
+ 1. Item 1
303
+ 2. Item 2
304
+ * Nested item 2
305
+ - Item 3
306
+ - Item 4
307
+ 2. List item 2
308
+ 1. Nested item 3
309
+ 2. Nested item 4
310
+ ```
311
+
290
312
  ### Publishing images
291
313
 
292
314
  Local images referenced in a Markdown file are automatically published to Confluence as attachments to the page.
@@ -304,7 +326,7 @@ Inline formulas can be enclosed with `$` signs, or delimited with `\(` and `\)`,
304
326
 
305
327
  Block formulas can be enclosed with `$$`, or wrapped in code blocks specifying the language `math`:
306
328
 
307
- ```md
329
+ ```markdown
308
330
  $$\int _{a}^{b}f(x)dx=F(b)-F(a)$$
309
331
  ```
310
332
 
@@ -341,7 +363,7 @@ Displaying math formulas in Confluence requires the extension [LaTeX Math for Co
341
363
 
342
364
  Use the pseudo-language `csf` in a Markdown code block to pass content directly to Confluence. The content must be a single XML node that conforms to Confluence Storage Format (typically an `ac:structured-macro`) but is otherwise not validated. The following example shows how to create a panel similar to an *info panel* but with custom background color and emoji. Notice that `ac:rich-text-body` uses XHTML, not Markdown.
343
365
 
344
- ````md
366
+ ````markdown
345
367
  ```csf
346
368
  <ac:structured-macro ac:name="panel" ac:schema-version="1">
347
369
  <ac:parameter ac:name="panelIcon">:slight_smile:</ac:parameter>
@@ -452,7 +474,7 @@ If *md2conf* encounters a Markdown link that points to a file in the directory h
452
474
 
453
475
  *md2conf* implicitly defines some URLs, as if you included the following at the start of the Markdown document for each URL:
454
476
 
455
- ```md
477
+ ```markdown
456
478
  [CUSTOM-URL]: https://example.com/path/to/resource
457
479
  ```
458
480
 
@@ -487,7 +509,7 @@ options:
487
509
  --api-url API_URL Confluence API URL. Required for scoped tokens. Refer to documentation how to obtain one.
488
510
  -u, --username USERNAME
489
511
  Confluence user name.
490
- -a, --apikey, --api-key API_KEY
512
+ -a, --api-key API_KEY
491
513
  Confluence API key. Refer to documentation how to obtain one.
492
514
  -s, --space SPACE Confluence space key for pages to be published. If omitted, will default to user space.
493
515
  -l, --loglevel {debug,info,warning,error,critical}
@@ -506,8 +528,6 @@ options:
506
528
  --no-render-latex Inline LaTeX formulas in Confluence page. (Marketplace app required to display.)
507
529
  --diagram-output-format {png,svg}
508
530
  Format for rendering Mermaid and draw.io diagrams (default: 'png').
509
- --render-mermaid-format FORMAT
510
- Format for rendering Mermaid diagrams (default: 'png').
511
531
  --heading-anchors Place an anchor at each section heading with GitHub-style same-page identifiers.
512
532
  --no-heading-anchors Don't place an anchor at each section heading.
513
533
  --ignore-invalid-url Emit a warning but otherwise ignore relative URLs that point to ill-specified locations.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markdown-to-confluence
3
- Version: 0.4.5
3
+ Version: 0.4.6
4
4
  Summary: Publish Markdown files to Confluence wiki
5
5
  Author-email: Levente Hunyadi <hunyadi@gmail.com>
6
6
  Maintainer-email: Levente Hunyadi <hunyadi@gmail.com>
@@ -23,12 +23,14 @@ Classifier: Typing :: Typed
23
23
  Requires-Python: >=3.9
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE
26
+ Requires-Dist: certifi>=2025.8.3; python_version < "3.10"
26
27
  Requires-Dist: json_strong_typing>=0.4
27
28
  Requires-Dist: lxml>=6.0
28
29
  Requires-Dist: markdown>=3.8
29
30
  Requires-Dist: pymdown-extensions>=10.16
30
31
  Requires-Dist: PyYAML>=6.0
31
32
  Requires-Dist: requests>=2.32
33
+ Requires-Dist: truststore>=0.10; python_version >= "3.10"
32
34
  Requires-Dist: typing-extensions>=4.14; python_version < "3.12"
33
35
  Provides-Extra: dev
34
36
  Requires-Dist: markdown_doc>=0.1.4; python_version >= "3.10" and extra == "dev"
@@ -143,7 +145,7 @@ export CONFLUENCE_SPACE_KEY='SPACE'
143
145
 
144
146
  On Windows, these can be set via system properties.
145
147
 
146
- If you use Atlassian scoped API tokens, you should set API URL, substituting `CLOUD_ID` with your own Cloud ID:
148
+ If you use Atlassian scoped API tokens, you may want to set API URL directly, substituting `CLOUD_ID` with your own Cloud ID:
147
149
 
148
150
  ```sh
149
151
  export CONFLUENCE_API_URL='https://api.atlassian.com/ex/confluence/CLOUD_ID/'
@@ -151,20 +153,27 @@ export CONFLUENCE_API_URL='https://api.atlassian.com/ex/confluence/CLOUD_ID/'
151
153
 
152
154
  In this case, *md2conf* can automatically determine `CONFLUENCE_DOMAIN` and `CONFLUENCE_PATH`.
153
155
 
156
+ If you can't find your `CLOUD_ID` but assign both `CONFLUENCE_DOMAIN` and `CONFLUENCE_PATH`, *md2conf* makes a best-effort attempt to determine `CONFLUENCE_API_URL`.
157
+
154
158
  ### Permissions
155
159
 
156
160
  The tool requires appropriate permissions in Confluence in order to invoke endpoints.
157
161
 
158
- Required scopes for scoped API tokens are as follows:
162
+ We recommend the following scopes for scoped API tokens:
159
163
 
164
+ * `read:attachment:confluence`
165
+ * `read:content:confluence`
166
+ * `read:content-details:confluence`
167
+ * `read:label:confluence`
160
168
  * `read:page:confluence`
161
- * `write:page:confluence`
162
169
  * `read:space:confluence`
163
- * `write:space:confluence`
164
- * `read:attachment:confluence`
165
170
  * `write:attachment:confluence`
166
- * `read:label:confluence`
171
+ * `write:content:confluence`
167
172
  * `write:label:confluence`
173
+ * `write:page:confluence`
174
+ * `delete:attachment:confluence`
175
+ * `delete:content:confluence`
176
+ * `delete:page:confluence`
168
177
 
169
178
  If a Confluence username is set, the tool uses HTTP *Basic* authentication to pass the username and the API key to Confluence REST API endpoints. If no username is provided, the tool authenticates with HTTP *Bearer*, and passes the API key as the bearer token.
170
179
 
@@ -331,6 +340,21 @@ The following table shows standard highlight colors (CSS `background-color`) tha
331
340
 
332
341
  If your Markdown lists or tables don't appear in Confluence as expected, verify that the list or table is delimited by a blank line both before and after, as per strict Markdown syntax. While some previewers accept a more lenient syntax (e.g. an itemized list immediately following a paragraph), *md2conf* uses [Python-Markdown](https://python-markdown.github.io/) internally to convert Markdown into XHTML, which expects the Markdown document to adhere to the stricter syntax.
333
342
 
343
+ Likewise, if you have a nested list, make sure that nested items are indented by exactly ***four*** spaces as compared to the parent node:
344
+
345
+ ```markdown
346
+ 1. List item 1
347
+ * Nested item 1
348
+ 1. Item 1
349
+ 2. Item 2
350
+ * Nested item 2
351
+ - Item 3
352
+ - Item 4
353
+ 2. List item 2
354
+ 1. Nested item 3
355
+ 2. Nested item 4
356
+ ```
357
+
334
358
  ### Publishing images
335
359
 
336
360
  Local images referenced in a Markdown file are automatically published to Confluence as attachments to the page.
@@ -348,7 +372,7 @@ Inline formulas can be enclosed with `$` signs, or delimited with `\(` and `\)`,
348
372
 
349
373
  Block formulas can be enclosed with `$$`, or wrapped in code blocks specifying the language `math`:
350
374
 
351
- ```md
375
+ ```markdown
352
376
  $$\int _{a}^{b}f(x)dx=F(b)-F(a)$$
353
377
  ```
354
378
 
@@ -385,7 +409,7 @@ Displaying math formulas in Confluence requires the extension [LaTeX Math for Co
385
409
 
386
410
  Use the pseudo-language `csf` in a Markdown code block to pass content directly to Confluence. The content must be a single XML node that conforms to Confluence Storage Format (typically an `ac:structured-macro`) but is otherwise not validated. The following example shows how to create a panel similar to an *info panel* but with custom background color and emoji. Notice that `ac:rich-text-body` uses XHTML, not Markdown.
387
411
 
388
- ````md
412
+ ````markdown
389
413
  ```csf
390
414
  <ac:structured-macro ac:name="panel" ac:schema-version="1">
391
415
  <ac:parameter ac:name="panelIcon">:slight_smile:</ac:parameter>
@@ -496,7 +520,7 @@ If *md2conf* encounters a Markdown link that points to a file in the directory h
496
520
 
497
521
  *md2conf* implicitly defines some URLs, as if you included the following at the start of the Markdown document for each URL:
498
522
 
499
- ```md
523
+ ```markdown
500
524
  [CUSTOM-URL]: https://example.com/path/to/resource
501
525
  ```
502
526
 
@@ -531,7 +555,7 @@ options:
531
555
  --api-url API_URL Confluence API URL. Required for scoped tokens. Refer to documentation how to obtain one.
532
556
  -u, --username USERNAME
533
557
  Confluence user name.
534
- -a, --apikey, --api-key API_KEY
558
+ -a, --api-key API_KEY
535
559
  Confluence API key. Refer to documentation how to obtain one.
536
560
  -s, --space SPACE Confluence space key for pages to be published. If omitted, will default to user space.
537
561
  -l, --loglevel {debug,info,warning,error,critical}
@@ -550,8 +574,6 @@ options:
550
574
  --no-render-latex Inline LaTeX formulas in Confluence page. (Marketplace app required to display.)
551
575
  --diagram-output-format {png,svg}
552
576
  Format for rendering Mermaid and draw.io diagrams (default: 'png').
553
- --render-mermaid-format FORMAT
554
- Format for rendering Mermaid diagrams (default: 'png').
555
577
  --heading-anchors Place an anchor at each section heading with GitHub-style same-page identifiers.
556
578
  --no-heading-anchors Don't place an anchor at each section heading.
557
579
  --ignore-invalid-url Emit a warning but otherwise ignore relative URLs that point to ill-specified locations.
@@ -13,13 +13,14 @@ markdown_to_confluence.egg-info/zip-safe
13
13
  md2conf/__init__.py
14
14
  md2conf/__main__.py
15
15
  md2conf/api.py
16
- md2conf/application.py
17
16
  md2conf/collection.py
18
17
  md2conf/converter.py
19
18
  md2conf/csf.py
20
19
  md2conf/domain.py
21
20
  md2conf/drawio.py
21
+ md2conf/emoticon.py
22
22
  md2conf/entities.dtd
23
+ md2conf/environment.py
23
24
  md2conf/extra.py
24
25
  md2conf/latex.py
25
26
  md2conf/local.py
@@ -28,7 +29,7 @@ md2conf/matcher.py
28
29
  md2conf/mermaid.py
29
30
  md2conf/metadata.py
30
31
  md2conf/processor.py
31
- md2conf/properties.py
32
+ md2conf/publisher.py
32
33
  md2conf/puppeteer-config.json
33
34
  md2conf/py.typed
34
35
  md2conf/scanner.py
@@ -5,9 +5,15 @@ pymdown-extensions>=10.16
5
5
  PyYAML>=6.0
6
6
  requests>=2.32
7
7
 
8
+ [:python_version < "3.10"]
9
+ certifi>=2025.8.3
10
+
8
11
  [:python_version < "3.12"]
9
12
  typing-extensions>=4.14
10
13
 
14
+ [:python_version >= "3.10"]
15
+ truststore>=0.10
16
+
11
17
  [dev]
12
18
  types-lxml>=2025.3.30
13
19
  types-markdown>=3.8
@@ -5,7 +5,7 @@ Parses Markdown files, converts Markdown content into the Confluence Storage For
5
5
  Confluence API endpoints to upload images and content.
6
6
  """
7
7
 
8
- __version__ = "0.4.5"
8
+ __version__ = "0.4.6"
9
9
  __author__ = "Levente Hunyadi"
10
10
  __copyright__ = "Copyright 2022-2025, Levente Hunyadi"
11
11
  __license__ = "MIT"
@@ -14,14 +14,15 @@ import logging
14
14
  import os.path
15
15
  import sys
16
16
  import typing
17
+ from io import StringIO
17
18
  from pathlib import Path
18
19
  from typing import Any, Iterable, Literal, Optional, Sequence, Union
19
20
 
20
21
  from . import __version__
21
22
  from .domain import ConfluenceDocumentOptions, ConfluencePageID
23
+ from .environment import ArgumentError, ConfluenceConnectionProperties, ConfluenceSiteProperties
22
24
  from .extra import override
23
25
  from .metadata import ConfluenceSiteMetadata
24
- from .properties import ArgumentError, ConfluenceConnectionProperties, ConfluenceSiteProperties
25
26
 
26
27
 
27
28
  class Arguments(argparse.Namespace):
@@ -68,30 +69,6 @@ class KwargsAppendAction(argparse.Action):
68
69
  setattr(namespace, self.dest, d)
69
70
 
70
71
 
71
- def unsupported(prefer: str) -> type[argparse.Action]:
72
- class UnsupportedAction(argparse.Action):
73
- """Display an error for unsupported command-line options."""
74
-
75
- @override
76
- def __call__(
77
- self,
78
- parser: argparse.ArgumentParser,
79
- namespace: argparse.Namespace,
80
- values: Union[None, str, Sequence[Any]],
81
- option_string: Optional[str] = None,
82
- ) -> None:
83
- raise argparse.ArgumentError(
84
- self,
85
- f"this command-line option is no longer supported, use `--{prefer}`",
86
- )
87
-
88
- @override
89
- def __repr__(self) -> str:
90
- return f"{unsupported.__name__}({repr(prefer)})"
91
-
92
- return UnsupportedAction
93
-
94
-
95
72
  class PositionalOnlyHelpFormatter(argparse.HelpFormatter):
96
73
  def _format_usage(
97
74
  self,
@@ -112,7 +89,7 @@ class PositionalOnlyHelpFormatter(argparse.HelpFormatter):
112
89
  return usage_str
113
90
 
114
91
 
115
- def main() -> None:
92
+ def get_parser() -> argparse.ArgumentParser:
116
93
  parser = argparse.ArgumentParser(formatter_class=PositionalOnlyHelpFormatter)
117
94
  parser.prog = os.path.basename(os.path.dirname(__file__))
118
95
  parser.add_argument("--version", action="version", version=__version__)
@@ -127,7 +104,6 @@ def main() -> None:
127
104
  parser.add_argument("-u", "--username", help="Confluence user name.")
128
105
  parser.add_argument(
129
106
  "-a",
130
- "--apikey",
131
107
  "--api-key",
132
108
  dest="api_key",
133
109
  help="Confluence API key. Refer to documentation how to obtain one.",
@@ -228,12 +204,6 @@ def main() -> None:
228
204
  default="png",
229
205
  help="Format for rendering Mermaid and draw.io diagrams (default: 'png').",
230
206
  )
231
- parser.add_argument(
232
- "--render-mermaid-format",
233
- action=unsupported("diagram-output-format"),
234
- metavar="FORMAT",
235
- help="Format for rendering Mermaid diagrams (default: 'png').",
236
- )
237
207
  parser.add_argument(
238
208
  "--heading-anchors",
239
209
  action="store_true",
@@ -272,7 +242,18 @@ def main() -> None:
272
242
  default=False,
273
243
  help="Enable Confluence Web UI links. (Typically required for on-prem versions of Confluence.)",
274
244
  )
245
+ return parser
246
+
275
247
 
248
+ def get_help() -> str:
249
+ parser = get_parser()
250
+ with StringIO() as buf:
251
+ parser.print_help(file=buf)
252
+ return buf.getvalue()
253
+
254
+
255
+ def main() -> None:
256
+ parser = get_parser()
276
257
  args = Arguments()
277
258
  parser.parse_args(namespace=args)
278
259
 
@@ -316,7 +297,7 @@ def main() -> None:
316
297
  from requests import HTTPError, JSONDecodeError
317
298
 
318
299
  from .api import ConfluenceAPI
319
- from .application import Application
300
+ from .publisher import Publisher
320
301
 
321
302
  try:
322
303
  properties = ConfluenceConnectionProperties(
@@ -332,7 +313,7 @@ def main() -> None:
332
313
  parser.error(str(e))
333
314
  try:
334
315
  with ConfluenceAPI(properties) as api:
335
- Application(
316
+ Publisher(
336
317
  api,
337
318
  options,
338
319
  ).process(args.mdpath)