notionary 0.2.17__py3-none-any.whl → 0.2.19__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.
- notionary/__init__.py +3 -2
- notionary/blocks/__init__.py +54 -25
- notionary/blocks/audio/__init__.py +7 -0
- notionary/blocks/audio/audio_element.py +152 -0
- notionary/blocks/audio/audio_markdown_node.py +29 -0
- notionary/blocks/audio/audio_models.py +59 -0
- notionary/blocks/bookmark/__init__.py +7 -0
- notionary/blocks/{bookmark_element.py → bookmark/bookmark_element.py} +20 -65
- notionary/blocks/bookmark/bookmark_markdown_node.py +43 -0
- notionary/blocks/bookmark/bookmark_models.py +0 -0
- notionary/blocks/bulleted_list/__init__.py +7 -0
- notionary/blocks/{bulleted_list_element.py → bulleted_list/bulleted_list_element.py} +7 -3
- notionary/blocks/bulleted_list/bulleted_list_markdown_node.py +33 -0
- notionary/blocks/bulleted_list/bulleted_list_models.py +0 -0
- notionary/blocks/callout/__init__.py +7 -0
- notionary/blocks/callout/callout_element.py +132 -0
- notionary/blocks/callout/callout_markdown_node.py +31 -0
- notionary/blocks/callout/callout_models.py +0 -0
- notionary/blocks/code/__init__.py +7 -0
- notionary/blocks/{code_block_element.py → code/code_element.py} +72 -40
- notionary/blocks/code/code_markdown_node.py +43 -0
- notionary/blocks/code/code_models.py +0 -0
- notionary/blocks/column/__init__.py +5 -0
- notionary/blocks/{column_element.py → column/column_element.py} +24 -55
- notionary/blocks/column/column_models.py +0 -0
- notionary/blocks/divider/__init__.py +7 -0
- notionary/blocks/{divider_element.py → divider/divider_element.py} +11 -3
- notionary/blocks/divider/divider_markdown_node.py +24 -0
- notionary/blocks/divider/divider_models.py +0 -0
- notionary/blocks/document/__init__.py +7 -0
- notionary/blocks/document/document_element.py +102 -0
- notionary/blocks/document/document_markdown_node.py +31 -0
- notionary/blocks/document/document_models.py +0 -0
- notionary/blocks/embed/__init__.py +7 -0
- notionary/blocks/{embed_element.py → embed/embed_element.py} +50 -32
- notionary/blocks/embed/embed_markdown_node.py +30 -0
- notionary/blocks/embed/embed_models.py +0 -0
- notionary/blocks/heading/__init__.py +7 -0
- notionary/blocks/{heading_element.py → heading/heading_element.py} +25 -17
- notionary/blocks/heading/heading_markdown_node.py +29 -0
- notionary/blocks/heading/heading_models.py +0 -0
- notionary/blocks/image/__init__.py +7 -0
- notionary/blocks/{image_element.py → image/image_element.py} +62 -42
- notionary/blocks/image/image_markdown_node.py +33 -0
- notionary/blocks/image/image_models.py +0 -0
- notionary/blocks/markdown_builder.py +356 -0
- notionary/blocks/markdown_node.py +29 -0
- notionary/blocks/mention/__init__.py +7 -0
- notionary/blocks/{mention_element.py → mention/mention_element.py} +6 -2
- notionary/blocks/mention/mention_markdown_node.py +38 -0
- notionary/blocks/mention/mention_models.py +0 -0
- notionary/blocks/numbered_list/__init__.py +7 -0
- notionary/blocks/{numbered_list_element.py → numbered_list/numbered_list_element.py} +10 -6
- notionary/blocks/numbered_list/numbered_list_markdown_node.py +29 -0
- notionary/blocks/numbered_list/numbered_list_models.py +0 -0
- notionary/blocks/paragraph/__init__.py +7 -0
- notionary/blocks/{paragraph_element.py → paragraph/paragraph_element.py} +7 -3
- notionary/blocks/paragraph/paragraph_markdown_node.py +25 -0
- notionary/blocks/paragraph/paragraph_models.py +0 -0
- notionary/blocks/quote/__init__.py +7 -0
- notionary/blocks/quote/quote_element.py +92 -0
- notionary/blocks/quote/quote_markdown_node.py +23 -0
- notionary/blocks/quote/quote_models.py +0 -0
- notionary/blocks/registry/block_registry.py +17 -3
- notionary/blocks/registry/block_registry_builder.py +90 -178
- notionary/blocks/shared/__init__.py +0 -0
- notionary/blocks/shared/block_client.py +256 -0
- notionary/blocks/shared/models.py +713 -0
- notionary/blocks/{notion_block_element.py → shared/notion_block_element.py} +8 -5
- notionary/blocks/{text_inline_formatter.py → shared/text_inline_formatter.py} +14 -14
- notionary/blocks/shared/text_inline_formatter_new.py +139 -0
- notionary/blocks/table/__init__.py +7 -0
- notionary/blocks/{table_element.py → table/table_element.py} +23 -11
- notionary/blocks/table/table_markdown_node.py +40 -0
- notionary/blocks/table/table_models.py +0 -0
- notionary/blocks/todo/__init__.py +7 -0
- notionary/blocks/{todo_element.py → todo/todo_element.py} +8 -4
- notionary/blocks/todo/todo_markdown_node.py +31 -0
- notionary/blocks/todo/todo_models.py +0 -0
- notionary/blocks/toggle/__init__.py +4 -0
- notionary/blocks/{toggle_element.py → toggle/toggle_element.py} +7 -3
- notionary/blocks/toggle/toggle_markdown_node.py +35 -0
- notionary/blocks/toggle/toggle_models.py +0 -0
- notionary/blocks/toggleable_heading/__init__.py +9 -0
- notionary/blocks/{toggleable_heading_element.py → toggleable_heading/toggleable_heading_element.py} +8 -4
- notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +43 -0
- notionary/blocks/toggleable_heading/toggleable_heading_models.py +0 -0
- notionary/blocks/video/__init__.py +7 -0
- notionary/blocks/{video_element.py → video/video_element.py} +82 -57
- notionary/blocks/video/video_markdown_node.py +30 -0
- notionary/file_upload/notion_file_upload.py +1 -1
- notionary/page/content/markdown_whitespace_processor.py +80 -0
- notionary/page/content/notion_text_length_utils.py +87 -0
- notionary/page/content/page_content_retriever.py +18 -10
- notionary/page/content/page_content_writer.py +97 -148
- notionary/page/formatting/line_processor.py +153 -0
- notionary/page/formatting/markdown_to_notion_converter.py +104 -425
- notionary/page/notion_page.py +9 -11
- notionary/page/notion_to_markdown_converter.py +9 -13
- notionary/util/factory_decorator.py +0 -0
- notionary/workspace.py +0 -1
- {notionary-0.2.17.dist-info → notionary-0.2.19.dist-info}/METADATA +1 -1
- notionary-0.2.19.dist-info/RECORD +150 -0
- notionary/blocks/audio_element.py +0 -144
- notionary/blocks/callout_element.py +0 -122
- notionary/blocks/document_element.py +0 -194
- notionary/blocks/notion_block_client.py +0 -26
- notionary/blocks/qoute_element.py +0 -169
- notionary/page/content/notion_page_content_chunker.py +0 -84
- notionary/page/formatting/spacer_rules.py +0 -483
- notionary-0.2.17.dist-info/RECORD +0 -85
- {notionary-0.2.17.dist-info → notionary-0.2.19.dist-info}/LICENSE +0 -0
- {notionary-0.2.17.dist-info → notionary-0.2.19.dist-info}/WHEEL +0 -0
@@ -0,0 +1,92 @@
|
|
1
|
+
import re
|
2
|
+
from typing import Dict, Any, Optional, List, Tuple
|
3
|
+
|
4
|
+
from notionary.blocks import NotionBlockElement, NotionBlockResult
|
5
|
+
from notionary.blocks import ElementPromptContent, ElementPromptBuilder
|
6
|
+
|
7
|
+
class QuoteElement(NotionBlockElement):
|
8
|
+
"""
|
9
|
+
Handles conversion between Markdown quotes and Notion quote blocks.
|
10
|
+
Markdown quote syntax:
|
11
|
+
- [quote](Simple quote text)
|
12
|
+
"""
|
13
|
+
|
14
|
+
# Einzeilig, kein Author, kein Anführungszeichen-Kram mehr!
|
15
|
+
PATTERN = re.compile(r'^\[quote\]\(([^\n\r]+)\)$')
|
16
|
+
|
17
|
+
@classmethod
|
18
|
+
def match_markdown(cls, text: str) -> bool:
|
19
|
+
m = cls.PATTERN.match(text.strip())
|
20
|
+
# Nur gültig, wenn etwas nicht-leeres drinsteht
|
21
|
+
return bool(m and m.group(1).strip())
|
22
|
+
|
23
|
+
@classmethod
|
24
|
+
def match_notion(cls, block: Dict[str, Any]) -> bool:
|
25
|
+
return block.get("type") == "quote"
|
26
|
+
|
27
|
+
@classmethod
|
28
|
+
def markdown_to_notion(cls, text: str) -> NotionBlockResult:
|
29
|
+
if not text:
|
30
|
+
return None
|
31
|
+
|
32
|
+
match = cls.PATTERN.match(text.strip())
|
33
|
+
if not match:
|
34
|
+
return None
|
35
|
+
|
36
|
+
content = match.group(1).strip()
|
37
|
+
if not content:
|
38
|
+
return None
|
39
|
+
|
40
|
+
rich_text = [{"type": "text", "text": {"content": content}}]
|
41
|
+
return {"type": "quote", "quote": {"rich_text": rich_text, "color": "default"}}
|
42
|
+
|
43
|
+
@classmethod
|
44
|
+
def notion_to_markdown(cls, block: Dict[str, Any]) -> Optional[str]:
|
45
|
+
if block.get("type") != "quote":
|
46
|
+
return None
|
47
|
+
|
48
|
+
rich_text = block.get("quote", {}).get("rich_text", [])
|
49
|
+
content = cls._extract_text_content(rich_text)
|
50
|
+
if not content.strip():
|
51
|
+
return None
|
52
|
+
|
53
|
+
return f"[quote]({content.strip()})"
|
54
|
+
|
55
|
+
@classmethod
|
56
|
+
def find_matches(cls, text: str) -> List[Tuple[int, int, Dict[str, Any]]]:
|
57
|
+
matches = []
|
58
|
+
for match in re.finditer(r"^\[quote\]\([^\n\r]+\)$", text, re.MULTILINE):
|
59
|
+
candidate = match.group(0)
|
60
|
+
block = cls.markdown_to_notion(candidate)
|
61
|
+
if block:
|
62
|
+
matches.append((match.start(), match.end(), block))
|
63
|
+
return matches
|
64
|
+
|
65
|
+
@classmethod
|
66
|
+
def is_multiline(cls) -> bool:
|
67
|
+
return False
|
68
|
+
|
69
|
+
@classmethod
|
70
|
+
def _extract_text_content(cls, rich_text: List[Dict[str, Any]]) -> str:
|
71
|
+
return "".join(
|
72
|
+
t.get("text", {}).get("content", "")
|
73
|
+
for t in rich_text
|
74
|
+
if t.get("type") == "text"
|
75
|
+
)
|
76
|
+
|
77
|
+
@classmethod
|
78
|
+
def get_llm_prompt_content(cls) -> ElementPromptContent:
|
79
|
+
return (
|
80
|
+
ElementPromptBuilder()
|
81
|
+
.with_description("Creates blockquotes that visually distinguish quoted text.")
|
82
|
+
.with_usage_guidelines(
|
83
|
+
"Use quotes for quoting external sources, highlighting important statements, "
|
84
|
+
"or creating visual emphasis for key information."
|
85
|
+
)
|
86
|
+
.with_syntax('[quote](Quote text)')
|
87
|
+
.with_examples([
|
88
|
+
"[quote](This is a simple blockquote)",
|
89
|
+
"[quote](Knowledge is power)",
|
90
|
+
])
|
91
|
+
.build()
|
92
|
+
)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from pydantic import BaseModel
|
4
|
+
from notionary.blocks.markdown_node import MarkdownNode
|
5
|
+
|
6
|
+
class QuoteMarkdownBlockParams(BaseModel):
|
7
|
+
text: str
|
8
|
+
|
9
|
+
class QuoteMarkdownNode(MarkdownNode):
|
10
|
+
"""
|
11
|
+
Programmatic interface for creating Notion-style quote blocks.
|
12
|
+
Example: [quote](This is a quote)
|
13
|
+
"""
|
14
|
+
|
15
|
+
def __init__(self, text: str):
|
16
|
+
self.text = text
|
17
|
+
|
18
|
+
@classmethod
|
19
|
+
def from_params(cls, params: QuoteMarkdownBlockParams) -> QuoteMarkdownNode:
|
20
|
+
return cls(text=params.text)
|
21
|
+
|
22
|
+
def to_markdown(self) -> str:
|
23
|
+
return f"[quote]({self.text})"
|
File without changes
|
@@ -1,11 +1,11 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
from typing import Dict, Any, Optional, List, Set, Type
|
3
3
|
|
4
|
-
from notionary.blocks
|
4
|
+
from notionary.blocks import NotionBlockElement
|
5
5
|
from notionary.page.markdown_syntax_prompt_generator import (
|
6
6
|
MarkdownSyntaxPromptGenerator,
|
7
7
|
)
|
8
|
-
from notionary.blocks
|
8
|
+
from notionary.blocks import TextInlineFormatter
|
9
9
|
|
10
10
|
from notionary.blocks import NotionBlockElement
|
11
11
|
from notionary.telemetry import (
|
@@ -25,7 +25,6 @@ class BlockRegistry:
|
|
25
25
|
|
26
26
|
Args:
|
27
27
|
elements: Initial elements to register
|
28
|
-
builder: The builder that created this registry (optional)
|
29
28
|
"""
|
30
29
|
self._elements: List[NotionBlockElement] = []
|
31
30
|
self._element_types: Set[Type[NotionBlockElement]] = set()
|
@@ -36,6 +35,21 @@ class BlockRegistry:
|
|
36
35
|
|
37
36
|
self.telemetry = ProductTelemetry()
|
38
37
|
|
38
|
+
@classmethod
|
39
|
+
def create_registry(cls) -> BlockRegistry:
|
40
|
+
"""
|
41
|
+
Create a registry with all standard elements in recommended order.
|
42
|
+
|
43
|
+
This uses the BlockRegistryBuilder internally to construct a complete
|
44
|
+
registry with all available block types.
|
45
|
+
|
46
|
+
Returns:
|
47
|
+
BlockRegistry: A fully configured registry with all standard elements
|
48
|
+
"""
|
49
|
+
from notionary.blocks import BlockRegistryBuilder
|
50
|
+
|
51
|
+
return BlockRegistryBuilder.create_registry()
|
52
|
+
|
39
53
|
def register(self, element_class: Type[NotionBlockElement]) -> bool:
|
40
54
|
"""
|
41
55
|
Register an element class.
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
-
from typing import
|
2
|
+
from typing import Type, TYPE_CHECKING, Self
|
3
3
|
from collections import OrderedDict
|
4
4
|
|
5
5
|
from notionary.blocks import (
|
@@ -7,7 +7,7 @@ from notionary.blocks import (
|
|
7
7
|
AudioElement,
|
8
8
|
BulletedListElement,
|
9
9
|
CalloutElement,
|
10
|
-
|
10
|
+
CodeElement,
|
11
11
|
ColumnElement,
|
12
12
|
DividerElement,
|
13
13
|
EmbedElement,
|
@@ -42,7 +42,7 @@ class BlockRegistryBuilder:
|
|
42
42
|
self._elements = OrderedDict()
|
43
43
|
|
44
44
|
@classmethod
|
45
|
-
def
|
45
|
+
def create_registry(cls) -> BlockRegistry:
|
46
46
|
"""
|
47
47
|
Start with all standard elements in recommended order.
|
48
48
|
"""
|
@@ -69,57 +69,7 @@ class BlockRegistryBuilder:
|
|
69
69
|
.with_toggleable_heading_element()
|
70
70
|
).build()
|
71
71
|
|
72
|
-
|
73
|
-
def create_minimal_registry(cls) -> BlockRegistry:
|
74
|
-
"""
|
75
|
-
Create a minimal registry with just essential text elements.
|
76
|
-
Suitable for basic note-taking.
|
77
|
-
"""
|
78
|
-
builder = cls()
|
79
|
-
return (
|
80
|
-
builder.with_paragraphs()
|
81
|
-
.with_headings()
|
82
|
-
.with_bulleted_list()
|
83
|
-
.with_numbered_list()
|
84
|
-
).build()
|
85
|
-
|
86
|
-
def add_element(
|
87
|
-
self, element_class: Type[NotionBlockElement]
|
88
|
-
) -> BlockRegistryBuilder:
|
89
|
-
"""
|
90
|
-
Add an element class to the registry configuration.
|
91
|
-
If the element already exists, it's moved to the end.
|
92
|
-
|
93
|
-
Args:
|
94
|
-
element_class: The element class to add
|
95
|
-
|
96
|
-
Returns:
|
97
|
-
Self for method chaining
|
98
|
-
"""
|
99
|
-
self._elements.pop(element_class.__name__, None)
|
100
|
-
self._elements[element_class.__name__] = element_class
|
101
|
-
|
102
|
-
return self
|
103
|
-
|
104
|
-
def add_elements(
|
105
|
-
self, element_classes: List[Type[NotionBlockElement]]
|
106
|
-
) -> BlockRegistryBuilder:
|
107
|
-
"""
|
108
|
-
Add multiple element classes to the registry configuration.
|
109
|
-
|
110
|
-
Args:
|
111
|
-
element_classes: List of element classes to add
|
112
|
-
|
113
|
-
Returns:
|
114
|
-
Self for method chaining
|
115
|
-
"""
|
116
|
-
for element_class in element_classes:
|
117
|
-
self.add_element(element_class)
|
118
|
-
return self
|
119
|
-
|
120
|
-
def remove_element(
|
121
|
-
self, element_class: Type[NotionBlockElement]
|
122
|
-
) -> BlockRegistryBuilder:
|
72
|
+
def remove_element(self, element_class: Type[NotionBlockElement]) -> Self:
|
123
73
|
"""
|
124
74
|
Remove an element class from the registry configuration.
|
125
75
|
|
@@ -132,160 +82,97 @@ class BlockRegistryBuilder:
|
|
132
82
|
self._elements.pop(element_class.__name__, None)
|
133
83
|
return self
|
134
84
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
Move an existing element to the end of the registry.
|
140
|
-
If the element doesn't exist, it will be added.
|
85
|
+
# WITH methods (existing)
|
86
|
+
def with_paragraphs(self) -> Self:
|
87
|
+
"""Add support for paragraph elements."""
|
88
|
+
return self._add_element(ParagraphElement)
|
141
89
|
|
142
|
-
|
143
|
-
|
90
|
+
def with_headings(self) -> Self:
|
91
|
+
"""Add support for heading elements."""
|
92
|
+
return self._add_element(HeadingElement)
|
144
93
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
return self.add_element(element_class)
|
94
|
+
def with_callouts(self) -> Self:
|
95
|
+
"""Add support for callout elements."""
|
96
|
+
return self._add_element(CalloutElement)
|
149
97
|
|
150
|
-
def
|
151
|
-
"""
|
152
|
-
|
153
|
-
"""
|
154
|
-
if ParagraphElement.__name__ in self._elements:
|
155
|
-
paragraph_class = self._elements.pop(ParagraphElement.__name__)
|
156
|
-
self._elements[ParagraphElement.__name__] = paragraph_class
|
98
|
+
def with_code(self) -> Self:
|
99
|
+
"""Add support for code blocks."""
|
100
|
+
return self._add_element(CodeElement)
|
157
101
|
|
158
|
-
def
|
159
|
-
"""
|
160
|
-
|
161
|
-
"""
|
162
|
-
return self.add_element(ParagraphElement)
|
102
|
+
def with_dividers(self) -> Self:
|
103
|
+
"""Add support for divider elements."""
|
104
|
+
return self._add_element(DividerElement)
|
163
105
|
|
164
|
-
def
|
165
|
-
"""
|
166
|
-
|
167
|
-
"""
|
168
|
-
return self.add_element(HeadingElement)
|
106
|
+
def with_tables(self) -> Self:
|
107
|
+
"""Add support for tables."""
|
108
|
+
return self._add_element(TableElement)
|
169
109
|
|
170
|
-
def
|
171
|
-
"""
|
172
|
-
|
173
|
-
"""
|
174
|
-
return self.add_element(CalloutElement)
|
110
|
+
def with_bulleted_list(self) -> Self:
|
111
|
+
"""Add support for bulleted list elements (unordered lists)."""
|
112
|
+
return self._add_element(BulletedListElement)
|
175
113
|
|
176
|
-
def
|
177
|
-
"""
|
178
|
-
|
179
|
-
"""
|
180
|
-
return self.add_element(CodeBlockElement)
|
114
|
+
def with_numbered_list(self) -> Self:
|
115
|
+
"""Add support for numbered list elements (ordered lists)."""
|
116
|
+
return self._add_element(NumberedListElement)
|
181
117
|
|
182
|
-
def
|
183
|
-
"""
|
184
|
-
|
185
|
-
"""
|
186
|
-
return self.add_element(DividerElement)
|
118
|
+
def with_toggles(self) -> Self:
|
119
|
+
"""Add support for toggle elements."""
|
120
|
+
return self._add_element(ToggleElement)
|
187
121
|
|
188
|
-
def
|
189
|
-
"""
|
190
|
-
|
191
|
-
"""
|
192
|
-
return self.add_element(TableElement)
|
122
|
+
def with_quotes(self) -> Self:
|
123
|
+
"""Add support for quote elements."""
|
124
|
+
return self._add_element(QuoteElement)
|
193
125
|
|
194
|
-
def
|
195
|
-
"""
|
196
|
-
|
197
|
-
"""
|
198
|
-
return self.add_element(BulletedListElement)
|
126
|
+
def with_todos(self) -> Self:
|
127
|
+
"""Add support for todo elements."""
|
128
|
+
return self._add_element(TodoElement)
|
199
129
|
|
200
|
-
def
|
201
|
-
"""
|
202
|
-
|
203
|
-
"""
|
204
|
-
return self.add_element(NumberedListElement)
|
130
|
+
def with_bookmarks(self) -> Self:
|
131
|
+
"""Add support for bookmark elements."""
|
132
|
+
return self._add_element(BookmarkElement)
|
205
133
|
|
206
|
-
def
|
207
|
-
"""
|
208
|
-
|
209
|
-
"""
|
210
|
-
return self.add_element(ToggleElement)
|
211
|
-
|
212
|
-
def with_quotes(self) -> BlockRegistryBuilder:
|
213
|
-
"""
|
214
|
-
Add support for quote elements.
|
215
|
-
"""
|
216
|
-
return self.add_element(QuoteElement)
|
217
|
-
|
218
|
-
def with_todos(self) -> BlockRegistryBuilder:
|
219
|
-
"""
|
220
|
-
Add support for todo elements.
|
221
|
-
"""
|
222
|
-
return self.add_element(TodoElement)
|
134
|
+
def with_images(self) -> Self:
|
135
|
+
"""Add support for image elements."""
|
136
|
+
return self._add_element(ImageElement)
|
223
137
|
|
224
|
-
def
|
225
|
-
"""
|
226
|
-
|
227
|
-
"""
|
228
|
-
return self.add_element(BookmarkElement)
|
138
|
+
def with_videos(self) -> Self:
|
139
|
+
"""Add support for video elements."""
|
140
|
+
return self._add_element(VideoElement)
|
229
141
|
|
230
|
-
def
|
231
|
-
"""
|
232
|
-
|
233
|
-
"""
|
234
|
-
return self.add_element(ImageElement)
|
142
|
+
def with_embeds(self) -> Self:
|
143
|
+
"""Add support for embed elements."""
|
144
|
+
return self._add_element(EmbedElement)
|
235
145
|
|
236
|
-
def
|
237
|
-
"""
|
238
|
-
|
239
|
-
"""
|
240
|
-
return self.add_element(VideoElement)
|
146
|
+
def with_audio(self) -> Self:
|
147
|
+
"""Add support for audio elements."""
|
148
|
+
return self._add_element(AudioElement)
|
241
149
|
|
242
|
-
def
|
243
|
-
"""
|
244
|
-
|
245
|
-
"""
|
246
|
-
return self.add_element(EmbedElement)
|
150
|
+
def with_mention(self) -> Self:
|
151
|
+
"""Add support for mention elements."""
|
152
|
+
return self._add_element(MentionElement)
|
247
153
|
|
248
|
-
def
|
249
|
-
"""
|
250
|
-
|
251
|
-
"""
|
252
|
-
return self.add_element(AudioElement)
|
154
|
+
def with_toggleable_heading_element(self) -> Self:
|
155
|
+
"""Add support for toggleable heading elements."""
|
156
|
+
return self._add_element(ToggleableHeadingElement)
|
253
157
|
|
254
|
-
def
|
255
|
-
"""
|
256
|
-
|
257
|
-
"""
|
258
|
-
return self.with_images().with_videos().with_audio()
|
259
|
-
|
260
|
-
def with_mention(self) -> BlockRegistryBuilder:
|
261
|
-
return self.add_element(MentionElement)
|
262
|
-
|
263
|
-
def with_toggleable_heading_element(self) -> BlockRegistryBuilder:
|
264
|
-
return self.add_element(ToggleableHeadingElement)
|
265
|
-
|
266
|
-
def with_columns(self) -> BlockRegistryBuilder:
|
267
|
-
"""
|
268
|
-
Add support for column elements.
|
269
|
-
"""
|
270
|
-
return self.add_element(ColumnElement)
|
158
|
+
def with_columns(self) -> Self:
|
159
|
+
"""Add support for column elements."""
|
160
|
+
return self._add_element(ColumnElement)
|
271
161
|
|
272
162
|
def build(self) -> BlockRegistry:
|
273
163
|
"""
|
274
164
|
Build and return the configured BlockRegistry instance.
|
275
165
|
|
276
166
|
This automatically ensures that ParagraphElement is at the end
|
277
|
-
of the registry
|
278
|
-
this behavior was explicitly disabled.
|
167
|
+
of the registry as a fallback element.
|
279
168
|
|
280
169
|
Returns:
|
281
170
|
A configured BlockRegistry instance
|
282
171
|
"""
|
283
172
|
from notionary.blocks import BlockRegistry
|
284
173
|
|
285
|
-
|
286
|
-
|
287
|
-
else:
|
288
|
-
self._ensure_paragraph_at_end()
|
174
|
+
# Ensure ParagraphElement is always present and at the end
|
175
|
+
self._ensure_paragraph_at_end()
|
289
176
|
|
290
177
|
registry = BlockRegistry()
|
291
178
|
|
@@ -294,3 +181,28 @@ class BlockRegistryBuilder:
|
|
294
181
|
registry.register(element_class)
|
295
182
|
|
296
183
|
return registry
|
184
|
+
|
185
|
+
def _ensure_paragraph_at_end(self) -> None:
|
186
|
+
"""
|
187
|
+
Internal method to ensure ParagraphElement is the last element in the registry.
|
188
|
+
If ParagraphElement is not present, it will be added.
|
189
|
+
"""
|
190
|
+
# Remove if present, then always add at the end
|
191
|
+
self._elements.pop(ParagraphElement.__name__, None)
|
192
|
+
self._elements[ParagraphElement.__name__] = ParagraphElement
|
193
|
+
|
194
|
+
def _add_element(self, element_class: Type[NotionBlockElement]) -> Self:
|
195
|
+
"""
|
196
|
+
Add an element class to the registry configuration.
|
197
|
+
If the element already exists, it's moved to the end.
|
198
|
+
|
199
|
+
Args:
|
200
|
+
element_class: The element class to add
|
201
|
+
|
202
|
+
Returns:
|
203
|
+
Self for method chaining
|
204
|
+
"""
|
205
|
+
self._elements.pop(element_class.__name__, None)
|
206
|
+
self._elements[element_class.__name__] = element_class
|
207
|
+
|
208
|
+
return self
|
File without changes
|