markdown-to-confluence 0.4.7__py3-none-any.whl → 0.5.0__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.
md2conf/scanner.py CHANGED
@@ -10,25 +10,17 @@ import re
10
10
  import typing
11
11
  from dataclasses import dataclass
12
12
  from pathlib import Path
13
- from typing import Any, Literal, Optional, TypeVar
13
+ from typing import Any, Literal, TypeVar
14
14
 
15
15
  import yaml
16
- from strong_typing.core import JsonType
17
- from strong_typing.serialization import DeserializerOptions, json_to_object
18
16
 
19
17
  from .mermaid import MermaidConfigProperties
18
+ from .serializer import JsonType, json_to_object
20
19
 
21
20
  T = TypeVar("T")
22
21
 
23
22
 
24
- def _json_to_object(
25
- typ: type[T],
26
- data: JsonType,
27
- ) -> T:
28
- return json_to_object(typ, data, options=DeserializerOptions(skip_unassigned=True))
29
-
30
-
31
- def extract_value(pattern: str, text: str) -> tuple[Optional[str], str]:
23
+ def extract_value(pattern: str, text: str) -> tuple[str | None, str]:
32
24
  values: list[str] = []
33
25
 
34
26
  def _repl_func(matchobj: re.Match[str]) -> str:
@@ -40,18 +32,18 @@ def extract_value(pattern: str, text: str) -> tuple[Optional[str], str]:
40
32
  return value, text
41
33
 
42
34
 
43
- def extract_frontmatter_block(text: str) -> tuple[Optional[str], str]:
35
+ def extract_frontmatter_block(text: str) -> tuple[str | None, str]:
44
36
  "Extracts the front-matter from a Markdown document as a blob of unparsed text."
45
37
 
46
38
  return extract_value(r"(?ms)\A---$(.+?)^---$", text)
47
39
 
48
40
 
49
- def extract_frontmatter_properties(text: str) -> tuple[Optional[dict[str, JsonType]], str]:
41
+ def extract_frontmatter_properties(text: str) -> tuple[dict[str, JsonType] | None, str]:
50
42
  "Extracts the front-matter from a Markdown document as a dictionary."
51
43
 
52
44
  block, text = extract_frontmatter_block(text)
53
45
 
54
- properties: Optional[dict[str, Any]] = None
46
+ properties: dict[str, Any] | None = None
55
47
  if block is not None:
56
48
  data = yaml.safe_load(block)
57
49
  if isinstance(data, dict):
@@ -77,16 +69,16 @@ class DocumentProperties:
77
69
  :param alignment: Alignment for block-level images and formulas.
78
70
  """
79
71
 
80
- page_id: Optional[str]
81
- space_key: Optional[str]
82
- confluence_page_id: Optional[str]
83
- confluence_space_key: Optional[str]
84
- generated_by: Optional[str]
85
- title: Optional[str]
86
- tags: Optional[list[str]]
87
- synchronized: Optional[bool]
88
- properties: Optional[dict[str, JsonType]]
89
- alignment: Optional[Literal["center", "left", "right"]]
72
+ page_id: str | None = None
73
+ space_key: str | None = None
74
+ confluence_page_id: str | None = None
75
+ confluence_space_key: str | None = None
76
+ generated_by: str | None = None
77
+ title: str | None = None
78
+ tags: list[str] | None = None
79
+ synchronized: bool | None = None
80
+ properties: dict[str, JsonType] | None = None
81
+ alignment: Literal["center", "left", "right"] | None = None
90
82
 
91
83
 
92
84
  @dataclass
@@ -105,14 +97,14 @@ class ScannedDocument:
105
97
  :param text: Text that remains after front-matter and inline properties have been extracted.
106
98
  """
107
99
 
108
- page_id: Optional[str]
109
- space_key: Optional[str]
110
- generated_by: Optional[str]
111
- title: Optional[str]
112
- tags: Optional[list[str]]
113
- synchronized: Optional[bool]
114
- properties: Optional[dict[str, JsonType]]
115
- alignment: Optional[Literal["center", "left", "right"]]
100
+ page_id: str | None
101
+ space_key: str | None
102
+ generated_by: str | None
103
+ title: str | None
104
+ tags: list[str] | None
105
+ synchronized: bool | None
106
+ properties: dict[str, JsonType] | None
107
+ alignment: Literal["center", "left", "right"] | None
116
108
  text: str
117
109
 
118
110
 
@@ -135,16 +127,16 @@ class Scanner:
135
127
  # extract 'generated-by' tag text
136
128
  generated_by, text = extract_value(r"<!--\s+generated[-_]by:\s*(.*)\s+-->", text)
137
129
 
138
- title: Optional[str] = None
139
- tags: Optional[list[str]] = None
140
- synchronized: Optional[bool] = None
141
- properties: Optional[dict[str, JsonType]] = None
142
- alignment: Optional[Literal["center", "left", "right"]] = None
130
+ title: str | None = None
131
+ tags: list[str] | None = None
132
+ synchronized: bool | None = None
133
+ properties: dict[str, JsonType] | None = None
134
+ alignment: Literal["center", "left", "right"] | None = None
143
135
 
144
136
  # extract front-matter
145
137
  data, text = extract_frontmatter_properties(text)
146
138
  if data is not None:
147
- p = _json_to_object(DocumentProperties, data)
139
+ p = json_to_object(DocumentProperties, data)
148
140
  page_id = page_id or p.confluence_page_id or p.page_id
149
141
  space_key = space_key or p.confluence_space_key or p.space_key
150
142
  generated_by = generated_by or p.generated_by
@@ -176,8 +168,8 @@ class MermaidProperties:
176
168
  :param config: Configuration options for rendering.
177
169
  """
178
170
 
179
- title: Optional[str] = None
180
- config: Optional[MermaidConfigProperties] = None
171
+ title: str | None = None
172
+ config: MermaidConfigProperties | None = None
181
173
 
182
174
 
183
175
  class MermaidScanner:
@@ -203,7 +195,7 @@ class MermaidScanner:
203
195
 
204
196
  properties, _ = extract_frontmatter_properties(content)
205
197
  if properties is not None:
206
- front_matter = _json_to_object(MermaidProperties, properties)
198
+ front_matter = json_to_object(MermaidProperties, properties)
207
199
  config = front_matter.config or MermaidConfigProperties()
208
200
 
209
201
  return MermaidProperties(title=front_matter.title, config=config)
md2conf/serializer.py ADDED
@@ -0,0 +1,52 @@
1
+ """
2
+ Publish Markdown files to Confluence wiki.
3
+
4
+ Copyright 2022-2025, Levente Hunyadi
5
+
6
+ :see: https://github.com/hunyadi/md2conf
7
+ """
8
+
9
+ from typing import TypeVar
10
+
11
+ from cattrs.preconf.json import make_converter
12
+
13
+ JsonType = None | bool | int | float | str | dict[str, "JsonType"] | list["JsonType"]
14
+ JsonComposite = dict[str, "JsonType"] | list["JsonType"]
15
+
16
+ T = TypeVar("T")
17
+
18
+
19
+ _converter = make_converter(forbid_extra_keys=False)
20
+
21
+
22
+ @_converter.register_structure_hook
23
+ def json_type_structure_hook(value: JsonType, cls: type[JsonType]) -> JsonType:
24
+ return value
25
+
26
+
27
+ @_converter.register_structure_hook
28
+ def json_composite_structure_hook(value: JsonComposite, cls: type[JsonComposite]) -> JsonComposite:
29
+ return value
30
+
31
+
32
+ def json_to_object(typ: type[T], data: JsonType) -> T:
33
+ """
34
+ Converts a raw JSON object to a structured object, validating input data.
35
+
36
+ :param typ: Target structured type.
37
+ :param data: Source data as a JSON object.
38
+ :returns: A valid object instance of the expected type.
39
+ """
40
+
41
+ return _converter.structure(data, typ)
42
+
43
+
44
+ def object_to_json_payload(data: object) -> bytes:
45
+ """
46
+ Converts a structured object to a JSON string encoded in UTF-8.
47
+
48
+ :param data: Object to convert to a JSON string.
49
+ :returns: JSON string encoded in UTF-8.
50
+ """
51
+
52
+ return _converter.dumps(data).encode("utf-8")
md2conf/toc.py CHANGED
@@ -7,7 +7,6 @@ Copyright 2022-2025, Levente Hunyadi
7
7
  """
8
8
 
9
9
  from dataclasses import dataclass
10
- from typing import Optional
11
10
 
12
11
 
13
12
  @dataclass(eq=True)
@@ -24,7 +23,7 @@ class TableOfContentsEntry:
24
23
  text: str
25
24
  children: list["TableOfContentsEntry"]
26
25
 
27
- def __init__(self, level: int, text: str, children: Optional[list["TableOfContentsEntry"]] = None) -> None:
26
+ def __init__(self, level: int, text: str, children: list["TableOfContentsEntry"] | None = None) -> None:
28
27
  self.level = level
29
28
  self.text = text
30
29
  self.children = children or []
@@ -74,7 +73,7 @@ class TableOfContentsBuilder:
74
73
  # push new level onto the stack
75
74
  self._stack.append(item)
76
75
 
77
- def get_title(self) -> Optional[str]:
76
+ def get_title(self) -> str | None:
78
77
  """
79
78
  Returns a proposed document title.
80
79
 
md2conf/xml.py CHANGED
@@ -6,7 +6,7 @@ Copyright 2022-2025, Levente Hunyadi
6
6
  :see: https://github.com/hunyadi/md2conf
7
7
  """
8
8
 
9
- from typing import Iterable, Optional
9
+ from typing import Iterable
10
10
 
11
11
  import lxml.etree as ET
12
12
 
@@ -39,7 +39,7 @@ class ElementComparator:
39
39
  skip_attributes: set[str]
40
40
  skip_elements: set[str]
41
41
 
42
- def __init__(self, *, skip_attributes: Optional[Iterable[str]] = None, skip_elements: Optional[Iterable[str]] = None):
42
+ def __init__(self, *, skip_attributes: Iterable[str] | None = None, skip_elements: Iterable[str] | None = None):
43
43
  """
44
44
  Initializes a new element tree comparator.
45
45
 
@@ -81,12 +81,10 @@ class ElementComparator:
81
81
  # compare children recursively
82
82
  if len(e1) != len(e2):
83
83
  return False
84
- return all(self.is_equal(c1, c2) for c1, c2 in zip(e1, e2))
84
+ return all(self.is_equal(c1, c2) for c1, c2 in zip(e1, e2, strict=True))
85
85
 
86
86
 
87
- def is_xml_equal(
88
- tree1: ElementType, tree2: ElementType, *, skip_attributes: Optional[Iterable[str]] = None, skip_elements: Optional[Iterable[str]] = None
89
- ) -> bool:
87
+ def is_xml_equal(tree1: ElementType, tree2: ElementType, *, skip_attributes: Iterable[str] | None = None, skip_elements: Iterable[str] | None = None) -> bool:
90
88
  """
91
89
  Compare two XML documents for equivalence, ignoring leading/trailing whitespace differences and attribute definition order.
92
90
 
@@ -1,34 +0,0 @@
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,,