markdown-to-confluence 0.4.5__py3-none-any.whl → 0.4.7__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.
@@ -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.7
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.
@@ -559,6 +581,9 @@ options:
559
581
  --headers KEY=VALUE [KEY=VALUE ...]
560
582
  Apply custom headers to all Confluence API requests.
561
583
  --webui-links Enable Confluence Web UI links. (Typically required for on-prem versions of Confluence.)
584
+ --alignment {center,left,right}
585
+ Alignment for block-level images and formulas (default: 'center').
586
+ --use-panel Transform admonitions and alerts into a Confluence custom panel.
562
587
  ```
563
588
 
564
589
  ### Using the Docker container
@@ -0,0 +1,34 @@
1
+ markdown_to_confluence-0.4.7.dist-info/licenses/LICENSE,sha256=56L-Y0dyZwyVlINRJRz3PNw-ka-oLVaAq-7d8zo6qlc,1077
2
+ md2conf/__init__.py,sha256=3R4-8WktKk6Q4JGEjAHqEU8S4u_w39RdcpBl-yL-0Tc,402
3
+ md2conf/__main__.py,sha256=pp3Zi60gmhXRqK0uoR4lZMVLlOO8ryAmk8UMPiI-Cew,11527
4
+ md2conf/api.py,sha256=uEPMcR4B-07MMFM96m92z7Znnj7pzhkLLAGcOIseERY,41398
5
+ md2conf/collection.py,sha256=EobgMRJgkYloWlY03NZJ52MRC_SGLpTVCHkltDbQyt0,837
6
+ md2conf/converter.py,sha256=wghwaa_07cN-xXY1DIOJgy6VJjfnJWDjbT4aB5NAL08,68845
7
+ md2conf/csf.py,sha256=rugs3qC2aJQCJSTczeBw9WhqSZZtMq14LjwT0V1b6Hc,6476
8
+ md2conf/domain.py,sha256=rN6QSuoP3JMj-WE8BAggHqHEO8nJbnQDf0b0uhStNZk,2221
9
+ md2conf/drawio.py,sha256=0FoCl0BWxyxO-KLPlDZPyYvSTRpgu9Z6yFKl10TGGMI,8594
10
+ md2conf/emoticon.py,sha256=P2L5oQvnRXeVifJQ3sJ2Ck-6ptbxumq2vsT-rM0W0Ms,484
11
+ md2conf/entities.dtd,sha256=M6NzqL5N7dPs_eUA_6sDsiSLzDaAacrx9LdttiufvYU,30215
12
+ md2conf/environment.py,sha256=RC1jY_TKVbOv2bJxXn27Fj4fNWzyoNUQt6ltgUyVQAQ,3987
13
+ md2conf/extra.py,sha256=VuMxuOnnC2Qwy6y52ukIxsaYhrZArRqMmRHRE4QZl8g,687
14
+ md2conf/latex.py,sha256=i5C_ZqsBG_Df1bNoMJpAKpiYMFcMEn5aoAv6bdSsE1k,7674
15
+ md2conf/local.py,sha256=mvp2kA_eo6JUQ_rlM7zDdEFgBPVxMr3VKP_X1nsLjHE,3747
16
+ md2conf/markdown.py,sha256=czabU17tUfhSX1JQGiI_TrMrTmtoVThOwFu_To_Oi_w,3176
17
+ md2conf/matcher.py,sha256=8g2yiKXfEkYJPIvKD2cswTG9BxFY24BtVcPgKaEVAs8,6812
18
+ md2conf/mermaid.py,sha256=hGrITJVvhHprjQVoezQ1nQeo6a_lqNihF8L-oJ4t5rc,2633
19
+ md2conf/metadata.py,sha256=LzZM-oPNnzCULmLhF516tPlV5zZBknccwMHt8Nan-xg,1007
20
+ md2conf/processor.py,sha256=G1icOxYsPAOjK4fnVdA-vwTsRiZMBpEAmMPOwfOebtQ,9733
21
+ md2conf/publisher.py,sha256=V4TzmrJ5LAv61EPpDYUGWv_6KHb-BcDjtYdByNt6su8,8665
22
+ md2conf/puppeteer-config.json,sha256=-dMTAN_7kNTGbDlfXzApl0KJpAWna9YKZdwMKbpOb60,159
23
+ md2conf/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ md2conf/scanner.py,sha256=O4iOgmSqTe1CYgmdaiF1QyAESzA4SRNEKVY9gOodXDY,7035
25
+ md2conf/text.py,sha256=fHOrUaPXAjE4iRhHqFq-CiI-knpo4wvyHCWp0crewqA,1736
26
+ md2conf/toc.py,sha256=hpqqDbFgNJg5-ul8qWjOglI3Am0sbwR-TLwGN5G9Qo0,2447
27
+ md2conf/uri.py,sha256=KbLBdRFtZTQTZd8b4j0LtE8Pb68Ly0WkemF4iW-EAB4,1158
28
+ md2conf/xml.py,sha256=SpFfcfZm1BPbB4zZM2UC1K-GkzHRhFiotiPMPt5_XPI,5541
29
+ markdown_to_confluence-0.4.7.dist-info/METADATA,sha256=iHeyUxkIuoI9_g9dvCLlxC4BCqnH3JStloGAfP-bWsY,34628
30
+ markdown_to_confluence-0.4.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
+ markdown_to_confluence-0.4.7.dist-info/entry_points.txt,sha256=F1zxa1wtEObtbHS-qp46330WVFLHdMnV2wQ-ZorRmX0,50
32
+ markdown_to_confluence-0.4.7.dist-info/top_level.txt,sha256=_FJfl_kHrHNidyjUOuS01ngu_jDsfc-ZjSocNRJnTzU,8
33
+ markdown_to_confluence-0.4.7.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
34
+ markdown_to_confluence-0.4.7.dist-info/RECORD,,
md2conf/__init__.py CHANGED
@@ -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.7"
9
9
  __author__ = "Levente Hunyadi"
10
10
  __copyright__ = "Copyright 2022-2025, Levente Hunyadi"
11
11
  __license__ = "MIT"
md2conf/__main__.py CHANGED
@@ -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):
@@ -45,6 +46,8 @@ class Arguments(argparse.Namespace):
45
46
  local: bool
46
47
  headers: dict[str, str]
47
48
  webui_links: bool
49
+ alignment: Literal["center", "left", "right"]
50
+ use_panel: bool
48
51
 
49
52
 
50
53
  class KwargsAppendAction(argparse.Action):
@@ -68,36 +71,12 @@ class KwargsAppendAction(argparse.Action):
68
71
  setattr(namespace, self.dest, d)
69
72
 
70
73
 
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
74
  class PositionalOnlyHelpFormatter(argparse.HelpFormatter):
96
75
  def _format_usage(
97
76
  self,
98
77
  usage: Optional[str],
99
78
  actions: Iterable[argparse.Action],
100
- groups: Iterable[argparse._MutuallyExclusiveGroup],
79
+ groups: Iterable[argparse._MutuallyExclusiveGroup], # pyright: ignore[reportPrivateUsage]
101
80
  prefix: Optional[str],
102
81
  ) -> str:
103
82
  # filter only positional arguments
@@ -112,7 +91,7 @@ class PositionalOnlyHelpFormatter(argparse.HelpFormatter):
112
91
  return usage_str
113
92
 
114
93
 
115
- def main() -> None:
94
+ def get_parser() -> argparse.ArgumentParser:
116
95
  parser = argparse.ArgumentParser(formatter_class=PositionalOnlyHelpFormatter)
117
96
  parser.prog = os.path.basename(os.path.dirname(__file__))
118
97
  parser.add_argument("--version", action="version", version=__version__)
@@ -127,7 +106,6 @@ def main() -> None:
127
106
  parser.add_argument("-u", "--username", help="Confluence user name.")
128
107
  parser.add_argument(
129
108
  "-a",
130
- "--apikey",
131
109
  "--api-key",
132
110
  dest="api_key",
133
111
  help="Confluence API key. Refer to documentation how to obtain one.",
@@ -228,12 +206,6 @@ def main() -> None:
228
206
  default="png",
229
207
  help="Format for rendering Mermaid and draw.io diagrams (default: 'png').",
230
208
  )
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
209
  parser.add_argument(
238
210
  "--heading-anchors",
239
211
  action="store_true",
@@ -272,7 +244,31 @@ def main() -> None:
272
244
  default=False,
273
245
  help="Enable Confluence Web UI links. (Typically required for on-prem versions of Confluence.)",
274
246
  )
247
+ parser.add_argument(
248
+ "--alignment",
249
+ dest="alignment",
250
+ choices=["center", "left", "right"],
251
+ default="center",
252
+ help="Alignment for block-level images and formulas (default: 'center').",
253
+ )
254
+ parser.add_argument(
255
+ "--use-panel",
256
+ action="store_true",
257
+ default=False,
258
+ help="Transform admonitions and alerts into a Confluence custom panel.",
259
+ )
260
+ return parser
261
+
262
+
263
+ def get_help() -> str:
264
+ parser = get_parser()
265
+ with StringIO() as buf:
266
+ parser.print_help(file=buf)
267
+ return buf.getvalue()
275
268
 
269
+
270
+ def main() -> None:
271
+ parser = get_parser()
276
272
  args = Arguments()
277
273
  parser.parse_args(namespace=args)
278
274
 
@@ -294,6 +290,8 @@ def main() -> None:
294
290
  render_latex=args.render_latex,
295
291
  diagram_output_format=args.diagram_output_format,
296
292
  webui_links=args.webui_links,
293
+ alignment=args.alignment,
294
+ use_panel=args.use_panel,
297
295
  )
298
296
  if args.local:
299
297
  from .local import LocalConverter
@@ -316,7 +314,7 @@ def main() -> None:
316
314
  from requests import HTTPError, JSONDecodeError
317
315
 
318
316
  from .api import ConfluenceAPI
319
- from .application import Application
317
+ from .publisher import Publisher
320
318
 
321
319
  try:
322
320
  properties = ConfluenceConnectionProperties(
@@ -332,7 +330,7 @@ def main() -> None:
332
330
  parser.error(str(e))
333
331
  try:
334
332
  with ConfluenceAPI(properties) as api:
335
- Application(
333
+ Publisher(
336
334
  api,
337
335
  options,
338
336
  ).process(args.mdpath)