notionary 0.2.18__py3-none-any.whl → 0.2.21__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.
Files changed (204) hide show
  1. notionary/__init__.py +8 -4
  2. notionary/base_notion_client.py +3 -1
  3. notionary/blocks/__init__.py +2 -91
  4. notionary/blocks/_bootstrap.py +263 -0
  5. notionary/blocks/audio/__init__.py +8 -2
  6. notionary/blocks/audio/audio_element.py +42 -104
  7. notionary/blocks/audio/audio_markdown_node.py +3 -1
  8. notionary/blocks/audio/audio_models.py +6 -55
  9. notionary/blocks/base_block_element.py +30 -0
  10. notionary/blocks/bookmark/__init__.py +9 -2
  11. notionary/blocks/bookmark/bookmark_element.py +46 -139
  12. notionary/blocks/bookmark/bookmark_markdown_node.py +3 -1
  13. notionary/blocks/bookmark/bookmark_models.py +15 -0
  14. notionary/blocks/breadcrumbs/__init__.py +17 -0
  15. notionary/blocks/breadcrumbs/breadcrumb_element.py +39 -0
  16. notionary/blocks/breadcrumbs/breadcrumb_markdown_node.py +32 -0
  17. notionary/blocks/breadcrumbs/breadcrumb_models.py +12 -0
  18. notionary/blocks/bulleted_list/__init__.py +12 -2
  19. notionary/blocks/bulleted_list/bulleted_list_element.py +40 -55
  20. notionary/blocks/bulleted_list/bulleted_list_markdown_node.py +2 -1
  21. notionary/blocks/bulleted_list/bulleted_list_models.py +18 -0
  22. notionary/blocks/callout/__init__.py +9 -2
  23. notionary/blocks/callout/callout_element.py +40 -89
  24. notionary/blocks/callout/callout_markdown_node.py +3 -1
  25. notionary/blocks/callout/callout_models.py +33 -0
  26. notionary/blocks/child_database/__init__.py +7 -0
  27. notionary/blocks/child_database/child_database_models.py +19 -0
  28. notionary/blocks/child_page/__init__.py +9 -0
  29. notionary/blocks/child_page/child_page_models.py +12 -0
  30. notionary/blocks/{shared/block_client.py → client.py} +55 -54
  31. notionary/blocks/code/__init__.py +6 -2
  32. notionary/blocks/code/code_element.py +53 -187
  33. notionary/blocks/code/code_markdown_node.py +13 -13
  34. notionary/blocks/code/code_models.py +94 -0
  35. notionary/blocks/column/__init__.py +25 -1
  36. notionary/blocks/column/column_element.py +40 -314
  37. notionary/blocks/column/column_list_element.py +37 -0
  38. notionary/blocks/column/column_list_markdown_node.py +50 -0
  39. notionary/blocks/column/column_markdown_node.py +59 -0
  40. notionary/blocks/column/column_models.py +26 -0
  41. notionary/blocks/divider/__init__.py +9 -2
  42. notionary/blocks/divider/divider_element.py +26 -49
  43. notionary/blocks/divider/divider_markdown_node.py +2 -1
  44. notionary/blocks/divider/divider_models.py +12 -0
  45. notionary/blocks/embed/__init__.py +9 -2
  46. notionary/blocks/embed/embed_element.py +47 -114
  47. notionary/blocks/embed/embed_markdown_node.py +3 -1
  48. notionary/blocks/embed/embed_models.py +14 -0
  49. notionary/blocks/equation/__init__.py +14 -0
  50. notionary/blocks/equation/equation_element.py +80 -0
  51. notionary/blocks/equation/equation_element_markdown_node.py +36 -0
  52. notionary/blocks/equation/equation_models.py +11 -0
  53. notionary/blocks/file/__init__.py +25 -0
  54. notionary/blocks/file/file_element.py +93 -0
  55. notionary/blocks/file/file_element_markdown_node.py +35 -0
  56. notionary/blocks/file/file_element_models.py +39 -0
  57. notionary/blocks/heading/__init__.py +16 -2
  58. notionary/blocks/heading/heading_element.py +67 -72
  59. notionary/blocks/heading/heading_markdown_node.py +2 -1
  60. notionary/blocks/heading/heading_models.py +29 -0
  61. notionary/blocks/image_block/__init__.py +13 -0
  62. notionary/blocks/image_block/image_element.py +84 -0
  63. notionary/blocks/{image → image_block}/image_markdown_node.py +3 -1
  64. notionary/blocks/image_block/image_models.py +10 -0
  65. notionary/blocks/models.py +172 -0
  66. notionary/blocks/numbered_list/__init__.py +12 -2
  67. notionary/blocks/numbered_list/numbered_list_element.py +33 -58
  68. notionary/blocks/numbered_list/numbered_list_markdown_node.py +3 -1
  69. notionary/blocks/numbered_list/numbered_list_models.py +17 -0
  70. notionary/blocks/paragraph/__init__.py +12 -2
  71. notionary/blocks/paragraph/paragraph_element.py +27 -69
  72. notionary/blocks/paragraph/paragraph_markdown_node.py +2 -1
  73. notionary/blocks/paragraph/paragraph_models.py +16 -0
  74. notionary/blocks/pdf/__init__.py +13 -0
  75. notionary/blocks/pdf/pdf_element.py +91 -0
  76. notionary/blocks/pdf/pdf_markdown_node.py +35 -0
  77. notionary/blocks/pdf/pdf_models.py +11 -0
  78. notionary/blocks/quote/__init__.py +11 -2
  79. notionary/blocks/quote/quote_element.py +31 -65
  80. notionary/blocks/quote/quote_markdown_node.py +4 -1
  81. notionary/blocks/quote/quote_models.py +18 -0
  82. notionary/blocks/registry/__init__.py +4 -0
  83. notionary/blocks/registry/block_registry.py +75 -91
  84. notionary/blocks/registry/block_registry_builder.py +107 -59
  85. notionary/blocks/rich_text/__init__.py +33 -0
  86. notionary/blocks/rich_text/rich_text_models.py +188 -0
  87. notionary/blocks/rich_text/text_inline_formatter.py +125 -0
  88. notionary/blocks/table/__init__.py +16 -2
  89. notionary/blocks/table/table_element.py +48 -241
  90. notionary/blocks/table/table_markdown_node.py +2 -1
  91. notionary/blocks/table/table_models.py +28 -0
  92. notionary/blocks/table_of_contents/__init__.py +19 -0
  93. notionary/blocks/table_of_contents/table_of_contents_element.py +51 -0
  94. notionary/blocks/table_of_contents/table_of_contents_markdown_node.py +35 -0
  95. notionary/blocks/table_of_contents/table_of_contents_models.py +18 -0
  96. notionary/blocks/todo/__init__.py +9 -2
  97. notionary/blocks/todo/todo_element.py +38 -95
  98. notionary/blocks/todo/todo_markdown_node.py +2 -1
  99. notionary/blocks/todo/todo_models.py +19 -0
  100. notionary/blocks/toggle/__init__.py +13 -3
  101. notionary/blocks/toggle/toggle_element.py +57 -264
  102. notionary/blocks/toggle/toggle_markdown_node.py +24 -14
  103. notionary/blocks/toggle/toggle_models.py +17 -0
  104. notionary/blocks/toggleable_heading/__init__.py +6 -2
  105. notionary/blocks/toggleable_heading/toggleable_heading_element.py +74 -244
  106. notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +26 -18
  107. notionary/blocks/types.py +61 -0
  108. notionary/blocks/video/__init__.py +8 -2
  109. notionary/blocks/video/video_element.py +67 -143
  110. notionary/blocks/video/video_element_models.py +10 -0
  111. notionary/blocks/video/video_markdown_node.py +3 -1
  112. notionary/database/client.py +3 -8
  113. notionary/database/database.py +13 -14
  114. notionary/database/database_filter_builder.py +2 -2
  115. notionary/database/database_provider.py +5 -4
  116. notionary/database/models.py +337 -0
  117. notionary/database/notion_database.py +6 -7
  118. notionary/file_upload/client.py +5 -7
  119. notionary/file_upload/models.py +2 -1
  120. notionary/file_upload/notion_file_upload.py +2 -3
  121. notionary/markdown/markdown_builder.py +722 -0
  122. notionary/markdown/markdown_document_model.py +228 -0
  123. notionary/{blocks → markdown}/markdown_node.py +1 -0
  124. notionary/models/notion_database_response.py +0 -338
  125. notionary/page/client.py +9 -10
  126. notionary/page/models.py +327 -0
  127. notionary/page/notion_page.py +99 -52
  128. notionary/page/notion_text_length_utils.py +119 -0
  129. notionary/page/{content/page_content_writer.py → page_content_writer.py} +88 -38
  130. notionary/page/reader/handler/__init__.py +17 -0
  131. notionary/page/reader/handler/base_block_renderer.py +44 -0
  132. notionary/page/reader/handler/block_processing_context.py +35 -0
  133. notionary/page/reader/handler/block_rendering_context.py +43 -0
  134. notionary/page/reader/handler/column_list_renderer.py +51 -0
  135. notionary/page/reader/handler/column_renderer.py +60 -0
  136. notionary/page/reader/handler/line_renderer.py +60 -0
  137. notionary/page/reader/handler/toggle_renderer.py +69 -0
  138. notionary/page/reader/handler/toggleable_heading_renderer.py +89 -0
  139. notionary/page/reader/page_content_retriever.py +69 -0
  140. notionary/page/search_filter_builder.py +2 -1
  141. notionary/page/writer/handler/__init__.py +22 -0
  142. notionary/page/writer/handler/code_handler.py +100 -0
  143. notionary/page/writer/handler/column_handler.py +141 -0
  144. notionary/page/writer/handler/column_list_handler.py +139 -0
  145. notionary/page/writer/handler/line_handler.py +35 -0
  146. notionary/page/writer/handler/line_processing_context.py +54 -0
  147. notionary/page/writer/handler/regular_line_handler.py +92 -0
  148. notionary/page/writer/handler/table_handler.py +130 -0
  149. notionary/page/writer/handler/toggle_handler.py +153 -0
  150. notionary/page/writer/handler/toggleable_heading_handler.py +167 -0
  151. notionary/page/writer/markdown_to_notion_converter.py +76 -0
  152. notionary/telemetry/__init__.py +2 -2
  153. notionary/telemetry/service.py +4 -3
  154. notionary/user/__init__.py +2 -2
  155. notionary/user/base_notion_user.py +2 -1
  156. notionary/user/client.py +2 -3
  157. notionary/user/models.py +1 -0
  158. notionary/user/notion_bot_user.py +4 -5
  159. notionary/user/notion_user.py +3 -4
  160. notionary/user/notion_user_manager.py +3 -2
  161. notionary/user/notion_user_provider.py +1 -1
  162. notionary/util/__init__.py +3 -2
  163. notionary/util/fuzzy.py +2 -1
  164. notionary/util/logging_mixin.py +2 -2
  165. notionary/util/singleton_metaclass.py +1 -1
  166. notionary/workspace.py +3 -2
  167. {notionary-0.2.18.dist-info → notionary-0.2.21.dist-info}/METADATA +12 -8
  168. notionary-0.2.21.dist-info/RECORD +185 -0
  169. notionary/blocks/document/__init__.py +0 -7
  170. notionary/blocks/document/document_element.py +0 -102
  171. notionary/blocks/document/document_markdown_node.py +0 -31
  172. notionary/blocks/image/__init__.py +0 -7
  173. notionary/blocks/image/image_element.py +0 -151
  174. notionary/blocks/markdown_builder.py +0 -356
  175. notionary/blocks/mention/__init__.py +0 -7
  176. notionary/blocks/mention/mention_element.py +0 -229
  177. notionary/blocks/mention/mention_markdown_node.py +0 -38
  178. notionary/blocks/prompts/element_prompt_builder.py +0 -83
  179. notionary/blocks/prompts/element_prompt_content.py +0 -41
  180. notionary/blocks/shared/__init__.py +0 -0
  181. notionary/blocks/shared/models.py +0 -710
  182. notionary/blocks/shared/notion_block_element.py +0 -37
  183. notionary/blocks/shared/text_inline_formatter.py +0 -262
  184. notionary/blocks/shared/text_inline_formatter_new.py +0 -139
  185. notionary/blocks/toggleable_heading/toggleable_heading_models.py +0 -0
  186. notionary/database/models/page_result.py +0 -10
  187. notionary/models/notion_block_response.py +0 -264
  188. notionary/models/notion_page_response.py +0 -78
  189. notionary/models/search_response.py +0 -0
  190. notionary/page/__init__.py +0 -0
  191. notionary/page/content/notion_text_length_utils.py +0 -87
  192. notionary/page/content/page_content_retriever.py +0 -52
  193. notionary/page/formatting/line_processor.py +0 -153
  194. notionary/page/formatting/markdown_to_notion_converter.py +0 -153
  195. notionary/page/markdown_syntax_prompt_generator.py +0 -114
  196. notionary/page/notion_to_markdown_converter.py +0 -179
  197. notionary/page/properites/property_value_extractor.py +0 -0
  198. notionary-0.2.18.dist-info/RECORD +0 -149
  199. /notionary/{blocks/document/document_models.py → markdown/___init__.py} +0 -0
  200. /notionary/{blocks/image/image_models.py → markdown/makdown_document_model.py} +0 -0
  201. /notionary/page/{content/markdown_whitespace_processor.py → markdown_whitespace_processor.py} +0 -0
  202. /notionary/{blocks/mention/mention_models.py → page/reader/handler/context.py} +0 -0
  203. {notionary-0.2.18.dist-info → notionary-0.2.21.dist-info}/LICENSE +0 -0
  204. {notionary-0.2.18.dist-info → notionary-0.2.21.dist-info}/WHEEL +0 -0
@@ -1,151 +0,0 @@
1
- import re
2
- from typing import Dict, Any, Optional, List
3
-
4
- from notionary.blocks import NotionBlockElement
5
- from notionary.blocks import (
6
- ElementPromptContent,
7
- ElementPromptBuilder,
8
- NotionBlockResult,
9
- )
10
-
11
-
12
- class ImageElement(NotionBlockElement):
13
- """
14
- Handles conversion between Markdown images and Notion image blocks.
15
-
16
- Markdown image syntax:
17
- - [image](https://example.com/image.jpg) - Simple image with URL only
18
- - [image](https://example.com/image.jpg "Caption") - Image with URL and caption
19
-
20
- Where:
21
- - URL is the required image URL
22
- - Caption is an optional descriptive text (enclosed in quotes)
23
- """
24
-
25
- # Regex pattern for image syntax with optional caption
26
- PATTERN = re.compile(
27
- r"^\[image\]\(" # [image]( prefix
28
- + r'(https?://[^\s"]+)' # URL (required)
29
- + r'(?:\s+"([^"]+)")?' # Optional caption in quotes
30
- + r"\)$" # closing parenthesis
31
- )
32
-
33
- @classmethod
34
- def match_markdown(cls, text: str) -> bool:
35
- """Check if text is a markdown image."""
36
- return text.strip().startswith("[image]") and bool(
37
- ImageElement.PATTERN.match(text.strip())
38
- )
39
-
40
- @classmethod
41
- def match_notion(cls, block: Dict[str, Any]) -> bool:
42
- """Check if block is a Notion image."""
43
- return block.get("type") == "image"
44
-
45
- @classmethod
46
- def markdown_to_notion(cls, text: str) -> NotionBlockResult:
47
- """Convert markdown image to Notion image block."""
48
- image_match = ImageElement.PATTERN.match(text.strip())
49
- if not image_match:
50
- return None
51
-
52
- url = image_match.group(1)
53
- caption = image_match.group(2)
54
-
55
- if not url:
56
- return None
57
-
58
- image_data = {"type": "external", "external": {"url": url}}
59
-
60
- # Add caption if provided
61
- if caption:
62
- image_data["caption"] = [{"type": "text", "text": {"content": caption}}]
63
- else:
64
- image_data["caption"] = []
65
-
66
- # Prepare the image block
67
- image_block = {"type": "image", "image": image_data}
68
-
69
- # Add empty paragraph after image
70
- empty_paragraph = {"type": "paragraph", "paragraph": {"rich_text": []}}
71
-
72
- return [image_block, empty_paragraph]
73
-
74
- @classmethod
75
- def notion_to_markdown(cls, block: Dict[str, Any]) -> Optional[str]:
76
- """Convert Notion image block to markdown image."""
77
- if block.get("type") != "image":
78
- return None
79
-
80
- image_data = block.get("image", {})
81
-
82
- # Handle both external and file (uploaded) images
83
- url = ImageElement._extract_image_url(image_data)
84
- if not url:
85
- return None
86
-
87
- caption_rich_text = image_data.get("caption", [])
88
-
89
- if not caption_rich_text:
90
- # Simple image with URL only
91
- return f"[image]({url})"
92
-
93
- # Extract caption text
94
- caption = ImageElement._extract_text_content(caption_rich_text)
95
-
96
- if caption:
97
- return f'[image]({url} "{caption}")'
98
-
99
- return f"[image]({url})"
100
-
101
- @classmethod
102
- def is_multiline(cls) -> bool:
103
- """Images are single-line elements."""
104
- return False
105
-
106
- @classmethod
107
- def _extract_image_url(cls, image_data: Dict[str, Any]) -> str:
108
- """Extract URL from image data, handling both external and uploaded images."""
109
- if image_data.get("type") == "external":
110
- return image_data.get("external", {}).get("url", "")
111
- elif image_data.get("type") == "file":
112
- return image_data.get("file", {}).get("url", "")
113
- return ""
114
-
115
- @classmethod
116
- def _extract_text_content(cls, rich_text: List[Dict[str, Any]]) -> str:
117
- """Extract plain text content from Notion rich_text elements."""
118
- result = ""
119
- for text_obj in rich_text:
120
- if text_obj.get("type") == "text":
121
- result += text_obj.get("text", {}).get("content", "")
122
- elif "plain_text" in text_obj:
123
- result += text_obj.get("plain_text", "")
124
- return result
125
-
126
- @classmethod
127
- def get_llm_prompt_content(cls) -> ElementPromptContent:
128
- """
129
- Returns structured LLM prompt metadata for the image element.
130
- """
131
- return (
132
- ElementPromptBuilder()
133
- .with_description(
134
- "Embeds an image from an external URL into your document."
135
- )
136
- .with_usage_guidelines(
137
- "Use images to include visual content such as diagrams, screenshots, charts, photos, or illustrations "
138
- "that enhance your document. Images can make complex information easier to understand, create visual interest, "
139
- "or provide evidence for your points."
140
- )
141
- .with_syntax('[image](https://example.com/image.jpg "Optional caption")')
142
- .with_examples(
143
- [
144
- "[image](https://example.com/chart.png)",
145
- '[image](https://example.com/screenshot.jpg "Data visualization showing monthly trends")',
146
- '[image](https://company.com/logo.png "Company Inc. logo")',
147
- '[image](https://example.com/diagram.jpg "System architecture overview")',
148
- ]
149
- )
150
- .build()
151
- )
@@ -1,356 +0,0 @@
1
- """
2
- Clean Fluent Markdown Builder
3
- ============================
4
-
5
- A direct, chainable builder for all MarkdownNode types without overengineering.
6
- Maps 1:1 to the available blocks with clear, expressive method names.
7
- """
8
-
9
- from __future__ import annotations
10
- from typing import Optional, Self, Union
11
-
12
- from notionary.blocks import (
13
- HeadingMarkdownNode,
14
- ImageMarkdownNode,
15
- ParagraphMarkdownNode,
16
- AudioMarkdownNode,
17
- BookmarkMarkdownNode,
18
- CalloutMarkdownNode,
19
- CodeMarkdownNode,
20
- DividerMarkdownNode,
21
- DocumentMarkdownNode,
22
- EmbedMarkdownNode,
23
- MentionMarkdownNode,
24
- NumberedListMarkdownNode,
25
- BulletedListMarkdownNode,
26
- QuoteMarkdownNode,
27
- TableMarkdownNode,
28
- TodoMarkdownNode,
29
- ToggleMarkdownNode,
30
- ToggleableHeadingMarkdownNode,
31
- VideoMarkdownNode,
32
- MarkdownNode,
33
- )
34
-
35
-
36
- class MarkdownBuilder:
37
- """
38
- Fluent interface builder for creating Notion content with clean, direct methods.
39
- """
40
-
41
- def __init__(self) -> None:
42
- self.children: list[MarkdownNode] = []
43
-
44
- def h1(self, text: str) -> Self:
45
- """
46
- Add an H1 heading.
47
-
48
- Args:
49
- text: The heading text content
50
- """
51
- self.children.append(HeadingMarkdownNode(text=text, level=1))
52
- return self
53
-
54
- def h2(self, text: str) -> Self:
55
- """
56
- Add an H2 heading.
57
-
58
- Args:
59
- text: The heading text content
60
- """
61
- self.children.append(HeadingMarkdownNode(text=text, level=2))
62
- return self
63
-
64
- def h3(self, text: str) -> Self:
65
- """
66
- Add an H3 heading.
67
-
68
- Args:
69
- text: The heading text content
70
- """
71
- self.children.append(HeadingMarkdownNode(text=text, level=3))
72
- return self
73
-
74
- def heading(self, text: str, level: int = 2) -> Self:
75
- """
76
- Add a heading with specified level.
77
-
78
- Args:
79
- text: The heading text content
80
- level: Heading level (1-3), defaults to 2
81
- """
82
- self.children.append(HeadingMarkdownNode(text=text, level=level))
83
- return self
84
-
85
- def paragraph(self, text: str) -> Self:
86
- """
87
- Add a paragraph block.
88
-
89
- Args:
90
- text: The paragraph text content
91
- """
92
- self.children.append(ParagraphMarkdownNode(text=text))
93
- return self
94
-
95
- def text(self, content: str) -> Self:
96
- """
97
- Add a text paragraph (alias for paragraph).
98
-
99
- Args:
100
- content: The text content
101
- """
102
- return self.paragraph(content)
103
-
104
- def quote(self, text: str, author: Optional[str] = None) -> Self:
105
- """
106
- Add a blockquote.
107
-
108
- Args:
109
- text: Quote text content
110
- author: Optional quote author/attribution
111
- """
112
- self.children.append(QuoteMarkdownNode(text=text, author=author))
113
- return self
114
-
115
- def divider(self) -> Self:
116
- """Add a horizontal divider."""
117
- self.children.append(DividerMarkdownNode())
118
- return self
119
-
120
- def numbered_list(self, items: list[str]) -> Self:
121
- """
122
- Add a numbered list.
123
-
124
- Args:
125
- items: List of text items for the numbered list
126
- """
127
- self.children.append(NumberedListMarkdownNode(texts=items))
128
- return self
129
-
130
- def bulleted_list(self, items: list[str]) -> Self:
131
- """
132
- Add a bulleted list.
133
-
134
- Args:
135
- items: List of text items for the bulleted list
136
- """
137
- self.children.append(BulletedListMarkdownNode(texts=items))
138
- return self
139
-
140
- def todo(self, text: str, checked: bool = False) -> Self:
141
- """
142
- Add a single todo item.
143
-
144
- Args:
145
- text: The todo item text
146
- checked: Whether the todo item is completed, defaults to False
147
- """
148
- self.children.append(TodoMarkdownNode(text=text, checked=checked))
149
- return self
150
-
151
- def todo_list(
152
- self, items: list[str], completed: Optional[list[bool]] = None
153
- ) -> Self:
154
- """
155
- Add multiple todo items.
156
-
157
- Args:
158
- items: List of todo item texts
159
- completed: List of completion states for each item, defaults to all False
160
- """
161
- if completed is None:
162
- completed = [False] * len(items)
163
-
164
- for i, item in enumerate(items):
165
- is_done = completed[i] if i < len(completed) else False
166
- self.children.append(TodoMarkdownNode(text=item, checked=is_done))
167
- return self
168
-
169
- def callout(self, text: str, emoji: Optional[str] = None) -> Self:
170
- """
171
- Add a callout block.
172
-
173
- Args:
174
- text: The callout text content
175
- emoji: Optional emoji for the callout icon
176
- """
177
- self.children.append(CalloutMarkdownNode(text=text, emoji=emoji))
178
- return self
179
-
180
- def toggle(self, title: str, content: Optional[list[str]] = None) -> Self:
181
- """
182
- Add a toggle block.
183
-
184
- Args:
185
- title: The toggle title/header text
186
- content: Optional list of content items inside the toggle
187
- """
188
- self.children.append(ToggleMarkdownNode(title=title, content=content))
189
- return self
190
-
191
- def toggleable_heading(
192
- self, text: str, level: int = 2, content: Optional[list[str]] = None
193
- ) -> Self:
194
- """
195
- Add a toggleable heading.
196
-
197
- Args:
198
- text: The heading text content
199
- level: Heading level (1-3), defaults to 2
200
- content: Optional list of content items inside the toggleable heading
201
- """
202
- self.children.append(
203
- ToggleableHeadingMarkdownNode(text=text, level=level, content=content)
204
- )
205
- return self
206
-
207
- def image(
208
- self, url: str, caption: Optional[str] = None, alt: Optional[str] = None
209
- ) -> Self:
210
- """
211
- Add an image.
212
-
213
- Args:
214
- url: Image URL or file path
215
- caption: Optional image caption text
216
- alt: Optional alternative text for accessibility
217
- """
218
- self.children.append(ImageMarkdownNode(url=url, caption=caption, alt=alt))
219
- return self
220
-
221
- def video(self, url: str, caption: Optional[str] = None) -> Self:
222
- """
223
- Add a video.
224
-
225
- Args:
226
- url: Video URL or file path
227
- caption: Optional video caption text
228
- """
229
- self.children.append(VideoMarkdownNode(url=url, caption=caption))
230
- return self
231
-
232
- def audio(self, url: str, caption: Optional[str] = None) -> Self:
233
- """
234
- Add audio content.
235
-
236
- Args:
237
- url: Audio file URL or path
238
- caption: Optional audio caption text
239
- """
240
- self.children.append(AudioMarkdownNode(url=url, caption=caption))
241
- return self
242
-
243
- def document(self, url: str, caption: Optional[str] = None) -> Self:
244
- """
245
- Add a document file.
246
-
247
- Args:
248
- url: Document file URL or path
249
- caption: Optional document caption text
250
- """
251
- self.children.append(DocumentMarkdownNode(url=url, caption=caption))
252
- return self
253
-
254
- def bookmark(
255
- self, url: str, title: Optional[str] = None, description: Optional[str] = None
256
- ) -> Self:
257
- """
258
- Add a bookmark.
259
-
260
- Args:
261
- url: Bookmark URL
262
- title: Optional bookmark title
263
- description: Optional bookmark description text
264
- """
265
- self.children.append(
266
- BookmarkMarkdownNode(url=url, title=title, description=description)
267
- )
268
- return self
269
-
270
- def embed(self, url: str, caption: Optional[str] = None) -> Self:
271
- """
272
- Add an embed.
273
-
274
- Args:
275
- url: URL to embed (e.g., YouTube, Twitter, etc.)
276
- caption: Optional embed caption text
277
- """
278
- self.children.append(EmbedMarkdownNode(url=url, caption=caption))
279
- return self
280
-
281
- def code(
282
- self, code: str, language: Optional[str] = None, caption: Optional[str] = None
283
- ) -> Self:
284
- """
285
- Add a code block.
286
-
287
- Args:
288
- code: The source code content
289
- language: Optional programming language for syntax highlighting
290
- caption: Optional code block caption text
291
- """
292
- self.children.append(
293
- CodeMarkdownNode(code=code, language=language, caption=caption)
294
- )
295
- return self
296
-
297
- def table(self, headers: list[str], rows: list[list[str]]) -> Self:
298
- """
299
- Add a table.
300
-
301
- Args:
302
- headers: List of column header texts
303
- rows: List of rows, where each row is a list of cell texts
304
- """
305
- self.children.append(TableMarkdownNode(headers=headers, rows=rows))
306
- return self
307
-
308
- def mention_page(self, page_id: str) -> Self:
309
- """
310
- Add a page mention.
311
-
312
- Args:
313
- page_id: The ID of the page to mention
314
- """
315
- self.children.append(MentionMarkdownNode("page", page_id))
316
- return self
317
-
318
- def mention_database(self, database_id: str) -> Self:
319
- """
320
- Add a database mention.
321
-
322
- Args:
323
- database_id: The ID of the database to mention
324
- """
325
- self.children.append(MentionMarkdownNode("database", database_id))
326
- return self
327
-
328
- def mention_date(self, date: str) -> Self:
329
- """
330
- Add a date mention.
331
-
332
- Args:
333
- date: Date in YYYY-MM-DD format
334
- """
335
- self.children.append(MentionMarkdownNode("date", date))
336
- return self
337
-
338
- def add_custom(self, node: MarkdownNode) -> Self:
339
- """
340
- Add a custom MarkdownNode.
341
-
342
- Args:
343
- node: A custom MarkdownNode instance
344
- """
345
- self.children.append(node)
346
- return self
347
-
348
- def space(self) -> Self:
349
- """Add vertical spacing."""
350
- return self.paragraph("")
351
-
352
- def build(self) -> str:
353
- """Build and return the final markdown string."""
354
- return "\n\n".join(
355
- child.to_markdown() for child in self.children if child is not None
356
- )
@@ -1,7 +0,0 @@
1
- from .mention_element import MentionElement
2
- from .mention_markdown_node import MentionMarkdownNode
3
-
4
- __all__ = [
5
- "MentionElement",
6
- "MentionMarkdownNode",
7
- ]