markdown-to-confluence 0.4.6__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.6
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>
@@ -581,6 +581,9 @@ options:
581
581
  --headers KEY=VALUE [KEY=VALUE ...]
582
582
  Apply custom headers to all Confluence API requests.
583
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.
584
587
  ```
585
588
 
586
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.6"
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
@@ -46,6 +46,8 @@ class Arguments(argparse.Namespace):
46
46
  local: bool
47
47
  headers: dict[str, str]
48
48
  webui_links: bool
49
+ alignment: Literal["center", "left", "right"]
50
+ use_panel: bool
49
51
 
50
52
 
51
53
  class KwargsAppendAction(argparse.Action):
@@ -74,7 +76,7 @@ class PositionalOnlyHelpFormatter(argparse.HelpFormatter):
74
76
  self,
75
77
  usage: Optional[str],
76
78
  actions: Iterable[argparse.Action],
77
- groups: Iterable[argparse._MutuallyExclusiveGroup],
79
+ groups: Iterable[argparse._MutuallyExclusiveGroup], # pyright: ignore[reportPrivateUsage]
78
80
  prefix: Optional[str],
79
81
  ) -> str:
80
82
  # filter only positional arguments
@@ -242,6 +244,19 @@ def get_parser() -> argparse.ArgumentParser:
242
244
  default=False,
243
245
  help="Enable Confluence Web UI links. (Typically required for on-prem versions of Confluence.)",
244
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
+ )
245
260
  return parser
246
261
 
247
262
 
@@ -275,6 +290,8 @@ def main() -> None:
275
290
  render_latex=args.render_latex,
276
291
  diagram_output_format=args.diagram_output_format,
277
292
  webui_links=args.webui_links,
293
+ alignment=args.alignment,
294
+ use_panel=args.use_panel,
278
295
  )
279
296
  if args.local:
280
297
  from .local import LocalConverter
md2conf/api.py CHANGED
@@ -17,7 +17,7 @@ import typing
17
17
  from dataclasses import dataclass
18
18
  from pathlib import Path
19
19
  from types import TracebackType
20
- from typing import Any, Optional, TypeVar
20
+ from typing import Any, Optional, TypeVar, overload
21
21
  from urllib.parse import urlencode, urlparse, urlunparse
22
22
 
23
23
  import requests
@@ -71,16 +71,24 @@ def build_url(base_url: str, query: Optional[dict[str, str]] = None) -> str:
71
71
  LOGGER = logging.getLogger(__name__)
72
72
 
73
73
 
74
- def response_cast(response_type: type[T], response: requests.Response) -> T:
74
+ @overload
75
+ def response_cast(response_type: None, response: requests.Response) -> None: ...
76
+
77
+
78
+ @overload
79
+ def response_cast(response_type: type[T], response: requests.Response) -> T: ...
80
+
81
+
82
+ def response_cast(response_type: Optional[type[T]], response: requests.Response) -> Optional[T]:
75
83
  "Converts a response body into the expected type."
76
84
 
77
85
  if response.text:
78
86
  LOGGER.debug("Received HTTP payload:\n%s", response.text)
79
87
  response.raise_for_status()
80
- if response_type is not type(None):
81
- return _json_to_object(response_type, response.json())
82
- else:
88
+ if response_type is None:
83
89
  return None
90
+ else:
91
+ return _json_to_object(response_type, response.json())
84
92
 
85
93
 
86
94
  @enum.unique
@@ -450,7 +458,7 @@ class ConfluenceSession:
450
458
 
451
459
  if not domain or not base_path:
452
460
  data = self._get(ConfluenceVersion.VERSION_2, "/spaces", ConfluenceResultSet, query={"limit": "1"})
453
- base_url = data._links.base
461
+ base_url = data._links.base # pyright: ignore[reportPrivateUsage]
454
462
 
455
463
  _, domain, base_path, _, _, _ = urlparse(base_url)
456
464
  if not base_path.endswith("/"):
@@ -548,23 +556,23 @@ class ConfluenceSession:
548
556
 
549
557
  return items
550
558
 
551
- def _build_request(self, version: ConfluenceVersion, path: str, body: Any, response_type: type[T]) -> tuple[str, dict[str, str], bytes]:
559
+ def _build_request(self, version: ConfluenceVersion, path: str, body: Any, response_type: Optional[type[T]]) -> tuple[str, dict[str, str], bytes]:
552
560
  "Generates URL, headers and raw payload for a typed request/response."
553
561
 
554
562
  url = self._build_url(version, path)
555
- if response_type is not type(None):
556
- headers = {
557
- "Content-Type": "application/json; charset=utf-8",
558
- "Accept": "application/json",
559
- }
560
- else:
561
- headers = {
562
- "Content-Type": "application/json; charset=utf-8",
563
- }
563
+ headers = {"Content-Type": "application/json"}
564
+ if response_type is not None:
565
+ headers["Accept"] = "application/json"
564
566
  data = json_dump_string(object_to_json(body)).encode("utf-8")
565
567
  return url, headers, data
566
568
 
567
- def _post(self, version: ConfluenceVersion, path: str, body: Any, response_type: type[T]) -> T:
569
+ @overload
570
+ def _post(self, version: ConfluenceVersion, path: str, body: Any, response_type: None) -> None: ...
571
+
572
+ @overload
573
+ def _post(self, version: ConfluenceVersion, path: str, body: Any, response_type: type[T]) -> T: ...
574
+
575
+ def _post(self, version: ConfluenceVersion, path: str, body: Any, response_type: Optional[type[T]]) -> Optional[T]:
568
576
  "Creates a new object via Confluence REST API."
569
577
 
570
578
  url, headers, data = self._build_request(version, path, body, response_type)
@@ -572,7 +580,13 @@ class ConfluenceSession:
572
580
  response.raise_for_status()
573
581
  return response_cast(response_type, response)
574
582
 
575
- def _put(self, version: ConfluenceVersion, path: str, body: Any, response_type: type[T]) -> T:
583
+ @overload
584
+ def _put(self, version: ConfluenceVersion, path: str, body: Any, response_type: None) -> None: ...
585
+
586
+ @overload
587
+ def _put(self, version: ConfluenceVersion, path: str, body: Any, response_type: type[T]) -> T: ...
588
+
589
+ def _put(self, version: ConfluenceVersion, path: str, body: Any, response_type: Optional[type[T]]) -> Optional[T]:
576
590
  "Updates an existing object via Confluence REST API."
577
591
 
578
592
  url, headers, data = self._build_request(version, path, body, response_type)
@@ -806,7 +820,7 @@ class ConfluenceSession:
806
820
  )
807
821
 
808
822
  LOGGER.info("Updating attachment: %s", attachment_id)
809
- self._put(ConfluenceVersion.VERSION_1, path, request, type(None))
823
+ self._put(ConfluenceVersion.VERSION_1, path, request, None)
810
824
 
811
825
  def get_page_properties_by_title(
812
826
  self,
@@ -899,7 +913,7 @@ class ConfluenceSession:
899
913
  version=ConfluenceContentVersion(number=version, minorEdit=True),
900
914
  )
901
915
  LOGGER.info("Updating page: %s", page_id)
902
- self._put(ConfluenceVersion.VERSION_2, path, request, type(None))
916
+ self._put(ConfluenceVersion.VERSION_2, path, request, None)
903
917
 
904
918
  def create_page(
905
919
  self,
@@ -934,7 +948,7 @@ class ConfluenceSession:
934
948
  url,
935
949
  data=json_dump_string(object_to_json(request)).encode("utf-8"),
936
950
  headers={
937
- "Content-Type": "application/json; charset=utf-8",
951
+ "Content-Type": "application/json",
938
952
  "Accept": "application/json",
939
953
  },
940
954
  verify=True,
@@ -995,7 +1009,7 @@ class ConfluenceSession:
995
1009
  url,
996
1010
  params=query,
997
1011
  headers={
998
- "Content-Type": "application/json; charset=utf-8",
1012
+ "Content-Type": "application/json",
999
1013
  "Accept": "application/json",
1000
1014
  },
1001
1015
  verify=True,
@@ -1048,7 +1062,7 @@ class ConfluenceSession:
1048
1062
  """
1049
1063
 
1050
1064
  path = f"/content/{page_id}/label"
1051
- self._post(ConfluenceVersion.VERSION_1, path, labels, type(None))
1065
+ self._post(ConfluenceVersion.VERSION_1, path, labels, None)
1052
1066
 
1053
1067
  def remove_labels(self, page_id: str, labels: list[ConfluenceLabel]) -> None:
1054
1068
  """