notionary 0.1.13__tar.gz → 0.1.14__tar.gz
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-0.1.13 → notionary-0.1.14}/PKG-INFO +1 -1
- {notionary-0.1.13 → notionary-0.1.14}/notionary/__init__.py +2 -2
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/audio_element.py +1 -1
- {notionary-0.1.13/notionary/converters/registry → notionary-0.1.14/notionary/elements}/block_element_registry.py +2 -5
- notionary-0.1.14/notionary/elements/block_element_registry_builder.py +401 -0
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/bookmark_element.py +1 -1
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/callout_element.py +2 -2
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/code_block_element.py +1 -1
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/column_element.py +1 -1
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/divider_element.py +1 -1
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/embed_element.py +1 -1
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/heading_element.py +2 -2
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/image_element.py +1 -1
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/list_element.py +2 -2
- notionary-0.1.14/notionary/elements/mention_element.py +135 -0
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/paragraph_element.py +2 -2
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/qoute_element.py +1 -1
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/table_element.py +2 -2
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/todo_lists.py +2 -2
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/toggle_element.py +1 -1
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/video_element.py +1 -1
- {notionary-0.1.13 → notionary-0.1.14}/notionary/notion_client.py +0 -1
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/content/page_content_manager.py +4 -3
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary/page}/markdown_to_notion_converter.py +2 -4
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/notion_page.py +23 -5
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/notion_page_factory.py +1 -15
- notionary-0.1.14/notionary/page/notion_to_markdown_converter.py +245 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary.egg-info/PKG-INFO +1 -1
- {notionary-0.1.13 → notionary-0.1.14}/notionary.egg-info/SOURCES.txt +23 -23
- {notionary-0.1.13 → notionary-0.1.14}/setup.py +1 -1
- notionary-0.1.13/notionary/converters/__init__.py +0 -50
- notionary-0.1.13/notionary/converters/notion_to_markdown_converter.py +0 -45
- notionary-0.1.13/notionary/converters/registry/block_element_registry_builder.py +0 -284
- {notionary-0.1.13 → notionary-0.1.14}/LICENSE +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/README.md +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/database/database_discovery.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/database/database_info_service.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/database/models/page_result.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/database/notion_database.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/database/notion_database_factory.py +0 -0
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/notion_block_element.py +0 -0
- {notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/text_inline_formatter.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/exceptions/database_exceptions.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/exceptions/page_creation_exception.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/content/notion_page_content_chunker.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/metadata/metadata_editor.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/metadata/notion_icon_manager.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/metadata/notion_page_cover_manager.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/properites/database_property_service.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/properites/page_property_manager.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/properites/property_formatter.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/properites/property_operation_result.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/properites/property_value_extractor.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/relations/notion_page_relation_manager.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/relations/notion_page_title_resolver.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/relations/page_database_relation.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/page/relations/relation_operation_result.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/util/logging_mixin.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/util/page_id_utils.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary/util/singleton_decorator.py +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary.egg-info/dependency_links.txt +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary.egg-info/requires.txt +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/notionary.egg-info/top_level.txt +0 -0
- {notionary-0.1.13 → notionary-0.1.14}/setup.cfg +0 -0
@@ -7,8 +7,8 @@ from .database.database_discovery import DatabaseDiscovery
|
|
7
7
|
from .page.notion_page import NotionPage
|
8
8
|
from .page.notion_page_factory import NotionPageFactory
|
9
9
|
|
10
|
-
from .
|
11
|
-
from .
|
10
|
+
from .elements.block_element_registry import BlockElementRegistry
|
11
|
+
from .elements.block_element_registry_builder import (
|
12
12
|
BlockElementRegistryBuilder,
|
13
13
|
)
|
14
14
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from typing import Dict, Any, Optional, List, Type
|
2
2
|
|
3
|
-
from notionary.
|
4
|
-
from notionary.
|
3
|
+
from notionary.elements.notion_block_element import NotionBlockElement
|
4
|
+
from notionary.elements.text_inline_formatter import TextInlineFormatter
|
5
5
|
|
6
6
|
|
7
7
|
class BlockElementRegistry:
|
@@ -96,9 +96,6 @@ class BlockElementRegistry:
|
|
96
96
|
# Create a copy of registered elements
|
97
97
|
element_classes = self._elements.copy()
|
98
98
|
|
99
|
-
# TODO: Das hier besser formattieren und über debug level lösen . )
|
100
|
-
print("Elements in registry:", element_classes)
|
101
|
-
|
102
99
|
formatter_names = [e.__name__ for e in element_classes]
|
103
100
|
if "TextInlineFormatter" not in formatter_names:
|
104
101
|
element_classes = [TextInlineFormatter] + element_classes
|
@@ -0,0 +1,401 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import List, Type
|
3
|
+
from collections import OrderedDict
|
4
|
+
|
5
|
+
from notionary.elements.audio_element import AudioElement
|
6
|
+
from notionary.elements.embed_element import EmbedElement
|
7
|
+
from notionary.elements.mention_element import MentionElement
|
8
|
+
from notionary.elements.notion_block_element import NotionBlockElement
|
9
|
+
from notionary.elements.block_element_registry import (
|
10
|
+
BlockElementRegistry,
|
11
|
+
)
|
12
|
+
|
13
|
+
from notionary.elements.paragraph_element import ParagraphElement
|
14
|
+
from notionary.elements.heading_element import HeadingElement
|
15
|
+
from notionary.elements.callout_element import CalloutElement
|
16
|
+
from notionary.elements.code_block_element import CodeBlockElement
|
17
|
+
from notionary.elements.divider_element import DividerElement
|
18
|
+
from notionary.elements.table_element import TableElement
|
19
|
+
from notionary.elements.todo_lists import TodoElement
|
20
|
+
from notionary.elements.list_element import (
|
21
|
+
BulletedListElement,
|
22
|
+
NumberedListElement,
|
23
|
+
)
|
24
|
+
from notionary.elements.qoute_element import QuoteElement
|
25
|
+
from notionary.elements.image_element import ImageElement
|
26
|
+
from notionary.elements.video_element import VideoElement
|
27
|
+
from notionary.elements.toggle_element import ToggleElement
|
28
|
+
from notionary.elements.bookmark_element import BookmarkElement
|
29
|
+
from notionary.elements.column_element import ColumnElement
|
30
|
+
|
31
|
+
|
32
|
+
class BlockElementRegistryBuilder:
|
33
|
+
"""
|
34
|
+
True builder for constructing BlockElementRegistry instances.
|
35
|
+
|
36
|
+
This builder allows for incremental construction of registry instances
|
37
|
+
with specific configurations of block elements.
|
38
|
+
"""
|
39
|
+
|
40
|
+
def __init__(self):
|
41
|
+
"""Initialize a new builder with an empty element list."""
|
42
|
+
self._elements = OrderedDict()
|
43
|
+
|
44
|
+
@classmethod
|
45
|
+
def start_empty(cls) -> BlockElementRegistryBuilder:
|
46
|
+
"""
|
47
|
+
Start with a completely empty registry builder.
|
48
|
+
|
49
|
+
Returns:
|
50
|
+
A new builder instance with no elements
|
51
|
+
"""
|
52
|
+
return cls()
|
53
|
+
|
54
|
+
@classmethod
|
55
|
+
def start_minimal(cls) -> BlockElementRegistryBuilder:
|
56
|
+
"""
|
57
|
+
Start with a minimal set of essential elements.
|
58
|
+
|
59
|
+
Returns:
|
60
|
+
A new builder instance with basic elements
|
61
|
+
"""
|
62
|
+
builder = cls()
|
63
|
+
return builder.with_headings().with_lists().with_paragraphs()
|
64
|
+
|
65
|
+
@classmethod
|
66
|
+
def start_standard(cls) -> BlockElementRegistryBuilder:
|
67
|
+
"""
|
68
|
+
Start with all standard elements in recommended order.
|
69
|
+
|
70
|
+
Returns:
|
71
|
+
A new builder instance with all standard elements
|
72
|
+
"""
|
73
|
+
builder = cls()
|
74
|
+
return (
|
75
|
+
builder.with_headings()
|
76
|
+
.with_callouts()
|
77
|
+
.with_code()
|
78
|
+
.with_dividers()
|
79
|
+
.with_tables()
|
80
|
+
.with_columns()
|
81
|
+
.with_lists()
|
82
|
+
.with_toggles()
|
83
|
+
.with_quotes()
|
84
|
+
.with_todos()
|
85
|
+
.with_bookmarks()
|
86
|
+
.with_images()
|
87
|
+
.with_videos()
|
88
|
+
.with_embeds()
|
89
|
+
.with_audio()
|
90
|
+
.with_mention()
|
91
|
+
.with_paragraphs()
|
92
|
+
)
|
93
|
+
|
94
|
+
# Element manipulation methods
|
95
|
+
|
96
|
+
def add_element(
|
97
|
+
self, element_class: Type[NotionBlockElement]
|
98
|
+
) -> BlockElementRegistryBuilder:
|
99
|
+
"""
|
100
|
+
Add an element class to the registry configuration.
|
101
|
+
If the element already exists, it's moved to the end.
|
102
|
+
|
103
|
+
Args:
|
104
|
+
element_class: The element class to add
|
105
|
+
|
106
|
+
Returns:
|
107
|
+
Self for method chaining
|
108
|
+
"""
|
109
|
+
self._elements.pop(element_class.__name__, None)
|
110
|
+
self._elements[element_class.__name__] = element_class
|
111
|
+
|
112
|
+
return self
|
113
|
+
|
114
|
+
def add_elements(
|
115
|
+
self, element_classes: List[Type[NotionBlockElement]]
|
116
|
+
) -> BlockElementRegistryBuilder:
|
117
|
+
"""
|
118
|
+
Add multiple element classes to the registry configuration.
|
119
|
+
|
120
|
+
Args:
|
121
|
+
element_classes: List of element classes to add
|
122
|
+
|
123
|
+
Returns:
|
124
|
+
Self for method chaining
|
125
|
+
"""
|
126
|
+
for element_class in element_classes:
|
127
|
+
self.add_element(element_class)
|
128
|
+
return self
|
129
|
+
|
130
|
+
def remove_element(
|
131
|
+
self, element_class: Type[NotionBlockElement]
|
132
|
+
) -> BlockElementRegistryBuilder:
|
133
|
+
"""
|
134
|
+
Remove an element class from the registry configuration.
|
135
|
+
|
136
|
+
Args:
|
137
|
+
element_class: The element class to remove
|
138
|
+
|
139
|
+
Returns:
|
140
|
+
Self for method chaining
|
141
|
+
"""
|
142
|
+
self._elements.pop(element_class.__name__, None)
|
143
|
+
return self
|
144
|
+
|
145
|
+
def move_element_to_end(
|
146
|
+
self, element_class: Type[NotionBlockElement]
|
147
|
+
) -> BlockElementRegistryBuilder:
|
148
|
+
"""
|
149
|
+
Move an existing element to the end of the registry.
|
150
|
+
If the element doesn't exist, it will be added.
|
151
|
+
|
152
|
+
Args:
|
153
|
+
element_class: The element class to move
|
154
|
+
|
155
|
+
Returns:
|
156
|
+
Self for method chaining
|
157
|
+
"""
|
158
|
+
return self.add_element(element_class) # add_element already handles this logic
|
159
|
+
|
160
|
+
def _ensure_paragraph_at_end(self) -> None:
|
161
|
+
"""
|
162
|
+
Internal method to ensure ParagraphElement is the last element in the registry.
|
163
|
+
"""
|
164
|
+
if ParagraphElement.__name__ in self._elements:
|
165
|
+
paragraph_class = self._elements.pop(ParagraphElement.__name__)
|
166
|
+
self._elements[ParagraphElement.__name__] = paragraph_class
|
167
|
+
|
168
|
+
def with_paragraphs(self) -> BlockElementRegistryBuilder:
|
169
|
+
"""
|
170
|
+
Add support for paragraph elements.
|
171
|
+
|
172
|
+
Returns:
|
173
|
+
Self for method chaining
|
174
|
+
"""
|
175
|
+
return self.add_element(ParagraphElement)
|
176
|
+
|
177
|
+
def with_headings(self) -> BlockElementRegistryBuilder:
|
178
|
+
"""
|
179
|
+
Add support for heading elements.
|
180
|
+
|
181
|
+
Returns:
|
182
|
+
Self for method chaining
|
183
|
+
"""
|
184
|
+
return self.add_element(HeadingElement)
|
185
|
+
|
186
|
+
def with_callouts(self) -> BlockElementRegistryBuilder:
|
187
|
+
"""
|
188
|
+
Add support for callout elements.
|
189
|
+
|
190
|
+
Returns:
|
191
|
+
Self for method chaining
|
192
|
+
"""
|
193
|
+
return self.add_element(CalloutElement)
|
194
|
+
|
195
|
+
def with_code(self) -> BlockElementRegistryBuilder:
|
196
|
+
"""
|
197
|
+
Add support for code blocks.
|
198
|
+
|
199
|
+
Returns:
|
200
|
+
Self for method chaining
|
201
|
+
"""
|
202
|
+
return self.add_element(CodeBlockElement)
|
203
|
+
|
204
|
+
def with_dividers(self) -> BlockElementRegistryBuilder:
|
205
|
+
"""
|
206
|
+
Add support for divider elements.
|
207
|
+
|
208
|
+
Returns:
|
209
|
+
Self for method chaining
|
210
|
+
"""
|
211
|
+
return self.add_element(DividerElement)
|
212
|
+
|
213
|
+
def with_tables(self) -> BlockElementRegistryBuilder:
|
214
|
+
"""
|
215
|
+
Add support for tables.
|
216
|
+
|
217
|
+
Returns:
|
218
|
+
Self for method chaining
|
219
|
+
"""
|
220
|
+
return self.add_element(TableElement)
|
221
|
+
|
222
|
+
def with_columns(self) -> BlockElementRegistryBuilder:
|
223
|
+
"""
|
224
|
+
Add support for column elements.
|
225
|
+
|
226
|
+
Returns:
|
227
|
+
Self for method chaining
|
228
|
+
"""
|
229
|
+
return self.add_element(ColumnElement)
|
230
|
+
|
231
|
+
def with_lists(self) -> BlockElementRegistryBuilder:
|
232
|
+
"""
|
233
|
+
Add support for list elements.
|
234
|
+
|
235
|
+
Returns:
|
236
|
+
Self for method chaining
|
237
|
+
"""
|
238
|
+
return self.add_element(BulletedListElement).add_element(NumberedListElement)
|
239
|
+
|
240
|
+
def with_toggles(self) -> BlockElementRegistryBuilder:
|
241
|
+
"""
|
242
|
+
Add support for toggle elements.
|
243
|
+
|
244
|
+
Returns:
|
245
|
+
Self for method chaining
|
246
|
+
"""
|
247
|
+
return self.add_element(ToggleElement)
|
248
|
+
|
249
|
+
def with_quotes(self) -> BlockElementRegistryBuilder:
|
250
|
+
"""
|
251
|
+
Add support for quote elements.
|
252
|
+
|
253
|
+
Returns:
|
254
|
+
Self for method chaining
|
255
|
+
"""
|
256
|
+
return self.add_element(QuoteElement)
|
257
|
+
|
258
|
+
def with_todos(self) -> BlockElementRegistryBuilder:
|
259
|
+
"""
|
260
|
+
Add support for todo elements.
|
261
|
+
|
262
|
+
Returns:
|
263
|
+
Self for method chaining
|
264
|
+
"""
|
265
|
+
return self.add_element(TodoElement)
|
266
|
+
|
267
|
+
def with_bookmarks(self) -> BlockElementRegistryBuilder:
|
268
|
+
"""
|
269
|
+
Add support for bookmark elements.
|
270
|
+
|
271
|
+
Returns:
|
272
|
+
Self for method chaining
|
273
|
+
"""
|
274
|
+
return self.add_element(BookmarkElement)
|
275
|
+
|
276
|
+
def with_images(self) -> BlockElementRegistryBuilder:
|
277
|
+
"""
|
278
|
+
Add support for image elements.
|
279
|
+
|
280
|
+
Returns:
|
281
|
+
Self for method chaining
|
282
|
+
"""
|
283
|
+
return self.add_element(ImageElement)
|
284
|
+
|
285
|
+
def with_videos(self) -> BlockElementRegistryBuilder:
|
286
|
+
"""
|
287
|
+
Add support for video elements.
|
288
|
+
|
289
|
+
Returns:
|
290
|
+
Self for method chaining
|
291
|
+
"""
|
292
|
+
return self.add_element(VideoElement)
|
293
|
+
|
294
|
+
def with_embeds(self) -> BlockElementRegistryBuilder:
|
295
|
+
"""
|
296
|
+
Add support for embed elements.
|
297
|
+
|
298
|
+
Returns:
|
299
|
+
Self for method chaining
|
300
|
+
"""
|
301
|
+
return self.add_element(EmbedElement)
|
302
|
+
|
303
|
+
def with_audio(self) -> BlockElementRegistryBuilder:
|
304
|
+
"""
|
305
|
+
Add support for audio elements.
|
306
|
+
|
307
|
+
Returns:
|
308
|
+
Self for method chaining
|
309
|
+
"""
|
310
|
+
return self.add_element(AudioElement)
|
311
|
+
|
312
|
+
def with_rich_content(self) -> BlockElementRegistryBuilder:
|
313
|
+
"""
|
314
|
+
Add support for rich content elements (callouts, toggles, etc.).
|
315
|
+
|
316
|
+
Returns:
|
317
|
+
Self for method chaining
|
318
|
+
"""
|
319
|
+
return self.with_callouts().with_toggles().with_quotes()
|
320
|
+
|
321
|
+
def with_media_support(self) -> BlockElementRegistryBuilder:
|
322
|
+
"""
|
323
|
+
Add support for media elements (images, videos, audio).
|
324
|
+
|
325
|
+
Returns:
|
326
|
+
Self for method chaining
|
327
|
+
"""
|
328
|
+
return self.with_images().with_videos().with_audio()
|
329
|
+
|
330
|
+
def with_task_support(self) -> BlockElementRegistryBuilder:
|
331
|
+
"""
|
332
|
+
Add support for task-related elements (todos).
|
333
|
+
|
334
|
+
Returns:
|
335
|
+
Self for method chaining
|
336
|
+
"""
|
337
|
+
return self.with_todos()
|
338
|
+
|
339
|
+
def with_mention(self) -> BlockElementRegistryBuilder:
|
340
|
+
return self.add_element(MentionElement)
|
341
|
+
|
342
|
+
def build(self) -> BlockElementRegistry:
|
343
|
+
"""
|
344
|
+
Build and return the configured BlockElementRegistry instance.
|
345
|
+
|
346
|
+
This automatically ensures that ParagraphElement is at the end
|
347
|
+
of the registry (if present) as a fallback element, unless
|
348
|
+
this behavior was explicitly disabled.
|
349
|
+
|
350
|
+
Returns:
|
351
|
+
A configured BlockElementRegistry instance
|
352
|
+
"""
|
353
|
+
if ParagraphElement.__name__ not in self._elements:
|
354
|
+
# Add paragraph as fallback if not present
|
355
|
+
self.add_element(ParagraphElement)
|
356
|
+
else:
|
357
|
+
# Ensure it's at the end
|
358
|
+
self._ensure_paragraph_at_end()
|
359
|
+
|
360
|
+
registry = BlockElementRegistry()
|
361
|
+
|
362
|
+
# Add elements in the recorded order
|
363
|
+
for element_class in self._elements.values():
|
364
|
+
registry.register(element_class)
|
365
|
+
|
366
|
+
return registry
|
367
|
+
|
368
|
+
@classmethod
|
369
|
+
def create_standard_registry(cls) -> BlockElementRegistry:
|
370
|
+
"""
|
371
|
+
Factory method to directly create a standard registry.
|
372
|
+
|
373
|
+
Returns:
|
374
|
+
A fully configured registry instance
|
375
|
+
"""
|
376
|
+
return cls.start_standard().build()
|
377
|
+
|
378
|
+
@classmethod
|
379
|
+
def create_minimal_registry(cls) -> BlockElementRegistry:
|
380
|
+
"""
|
381
|
+
Factory method to directly create a minimal registry.
|
382
|
+
|
383
|
+
Returns:
|
384
|
+
A minimal registry instance
|
385
|
+
"""
|
386
|
+
return cls.start_minimal().build()
|
387
|
+
|
388
|
+
@classmethod
|
389
|
+
def create_custom_registry(
|
390
|
+
cls, element_classes: List[Type[NotionBlockElement]]
|
391
|
+
) -> BlockElementRegistry:
|
392
|
+
"""
|
393
|
+
Factory method to directly create a custom registry.
|
394
|
+
|
395
|
+
Args:
|
396
|
+
element_classes: List of element classes to register
|
397
|
+
|
398
|
+
Returns:
|
399
|
+
A custom configured registry instance
|
400
|
+
"""
|
401
|
+
return cls().add_elements(element_classes).build()
|
{notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/bookmark_element.py
RENAMED
@@ -2,7 +2,7 @@ import re
|
|
2
2
|
from typing import Dict, Any, Optional, List, Tuple
|
3
3
|
from typing_extensions import override
|
4
4
|
|
5
|
-
from notionary.
|
5
|
+
from notionary.elements.notion_block_element import NotionBlockElement
|
6
6
|
|
7
7
|
|
8
8
|
class BookmarkElement(NotionBlockElement):
|
{notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/callout_element.py
RENAMED
@@ -2,8 +2,8 @@ from typing import Dict, Any, Optional
|
|
2
2
|
from typing_extensions import override
|
3
3
|
import re
|
4
4
|
|
5
|
-
from notionary.
|
6
|
-
from notionary.
|
5
|
+
from notionary.elements.text_inline_formatter import TextInlineFormatter
|
6
|
+
from notionary.elements.notion_block_element import NotionBlockElement
|
7
7
|
|
8
8
|
|
9
9
|
class CalloutElement(NotionBlockElement):
|
{notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/code_block_element.py
RENAMED
@@ -1,7 +1,7 @@
|
|
1
1
|
from typing import Dict, Any, Optional, List, Tuple
|
2
2
|
from typing_extensions import override
|
3
3
|
import re
|
4
|
-
from notionary.
|
4
|
+
from notionary.elements.notion_block_element import NotionBlockElement
|
5
5
|
|
6
6
|
|
7
7
|
class CodeBlockElement(NotionBlockElement):
|
{notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/column_element.py
RENAMED
@@ -2,7 +2,7 @@ import re
|
|
2
2
|
from typing import Dict, Any, Optional, List, Tuple, Callable
|
3
3
|
from typing_extensions import override
|
4
4
|
|
5
|
-
from notionary.
|
5
|
+
from notionary.elements.notion_block_element import NotionBlockElement
|
6
6
|
|
7
7
|
|
8
8
|
class ColumnElement(NotionBlockElement):
|
{notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/divider_element.py
RENAMED
@@ -4,7 +4,7 @@ from typing import Dict, Any, Optional
|
|
4
4
|
from typing_extensions import override
|
5
5
|
import re
|
6
6
|
|
7
|
-
from notionary.
|
7
|
+
from notionary.elements.notion_block_element import NotionBlockElement
|
8
8
|
|
9
9
|
|
10
10
|
class DividerElement(NotionBlockElement):
|
{notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/heading_element.py
RENAMED
@@ -2,8 +2,8 @@ from typing import Dict, Any, Optional
|
|
2
2
|
from typing_extensions import override
|
3
3
|
import re
|
4
4
|
|
5
|
-
from notionary.
|
6
|
-
from notionary.
|
5
|
+
from notionary.elements.notion_block_element import NotionBlockElement
|
6
|
+
from notionary.elements.text_inline_formatter import TextInlineFormatter
|
7
7
|
|
8
8
|
|
9
9
|
class HeadingElement(NotionBlockElement):
|
{notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/image_element.py
RENAMED
@@ -1,7 +1,7 @@
|
|
1
1
|
import re
|
2
2
|
from typing import Dict, Any, Optional, List
|
3
3
|
from typing_extensions import override
|
4
|
-
from notionary.
|
4
|
+
from notionary.elements.notion_block_element import NotionBlockElement
|
5
5
|
|
6
6
|
|
7
7
|
class ImageElement(NotionBlockElement):
|
{notionary-0.1.13/notionary/converters → notionary-0.1.14/notionary}/elements/list_element.py
RENAMED
@@ -1,8 +1,8 @@
|
|
1
1
|
import re
|
2
2
|
from typing import Dict, Any, Optional
|
3
3
|
from typing_extensions import override
|
4
|
-
from notionary.
|
5
|
-
from notionary.
|
4
|
+
from notionary.elements.notion_block_element import NotionBlockElement
|
5
|
+
from notionary.elements.text_inline_formatter import TextInlineFormatter
|
6
6
|
|
7
7
|
|
8
8
|
class BulletedListElement(NotionBlockElement):
|
@@ -0,0 +1,135 @@
|
|
1
|
+
from typing import Dict, Any, Optional, List
|
2
|
+
from typing_extensions import override
|
3
|
+
|
4
|
+
from notionary.elements.notion_block_element import NotionBlockElement
|
5
|
+
|
6
|
+
class MentionElement(NotionBlockElement):
|
7
|
+
"""
|
8
|
+
Handles conversion between Markdown mentions and Notion mention elements.
|
9
|
+
|
10
|
+
Markdown mention syntax:
|
11
|
+
- @[page-id] - Mention a page by its ID
|
12
|
+
|
13
|
+
Note: This element primarily supports Notion-to-Markdown conversion,
|
14
|
+
as page mentions in Markdown would typically require knowing internal page IDs.
|
15
|
+
"""
|
16
|
+
|
17
|
+
@override
|
18
|
+
@staticmethod
|
19
|
+
def match_markdown(text: str) -> bool:
|
20
|
+
"""Check if text is a markdown mention."""
|
21
|
+
return False
|
22
|
+
|
23
|
+
@override
|
24
|
+
@staticmethod
|
25
|
+
def match_notion(block: Dict[str, Any]) -> bool:
|
26
|
+
"""Check if block contains a mention."""
|
27
|
+
if block.get("type") not in ["paragraph", "heading_1", "heading_2", "heading_3", "bulleted_list_item", "numbered_list_item"]:
|
28
|
+
return False
|
29
|
+
|
30
|
+
block_content = block.get(block.get("type"), {})
|
31
|
+
rich_text = block_content.get("rich_text", [])
|
32
|
+
|
33
|
+
for text_item in rich_text:
|
34
|
+
if text_item.get("type") == "mention":
|
35
|
+
return True
|
36
|
+
|
37
|
+
return False
|
38
|
+
|
39
|
+
@override
|
40
|
+
@staticmethod
|
41
|
+
def markdown_to_notion(text: str) -> Optional[Dict[str, Any]]:
|
42
|
+
"""Convert markdown mention to Notion mention block."""
|
43
|
+
# This would be handled within rich text processing rather than as a standalone block
|
44
|
+
return None
|
45
|
+
|
46
|
+
@override
|
47
|
+
@staticmethod
|
48
|
+
def notion_to_markdown(block: Dict[str, Any]) -> Optional[str]:
|
49
|
+
"""Extract mentions from Notion block and convert to markdown format."""
|
50
|
+
block_type = block.get("type")
|
51
|
+
if not block_type or block_type not in block:
|
52
|
+
return None
|
53
|
+
|
54
|
+
block_content = block.get(block_type, {})
|
55
|
+
rich_text = block_content.get("rich_text", [])
|
56
|
+
|
57
|
+
processed_text = MentionElement._process_rich_text_with_mentions(rich_text)
|
58
|
+
|
59
|
+
if MentionElement._is_only_mentions(rich_text):
|
60
|
+
return processed_text
|
61
|
+
|
62
|
+
return None
|
63
|
+
|
64
|
+
@staticmethod
|
65
|
+
def _process_rich_text_with_mentions(rich_text: List[Dict[str, Any]]) -> str:
|
66
|
+
"""Process rich text array and convert any mentions to markdown format."""
|
67
|
+
result = []
|
68
|
+
|
69
|
+
for item in rich_text:
|
70
|
+
if item.get("type") == "mention":
|
71
|
+
mention = item.get("mention", {})
|
72
|
+
mention_type = mention.get("type")
|
73
|
+
|
74
|
+
if mention_type == "page":
|
75
|
+
page_id = mention.get("page", {}).get("id", "")
|
76
|
+
result.append(f"@[{page_id}]")
|
77
|
+
elif mention_type == "user":
|
78
|
+
user_id = mention.get("user", {}).get("id", "")
|
79
|
+
result.append(f"@user[{user_id}]")
|
80
|
+
elif mention_type == "date":
|
81
|
+
date_value = mention.get("date", {}).get("start", "")
|
82
|
+
result.append(f"@date[{date_value}]")
|
83
|
+
elif mention_type == "database":
|
84
|
+
db_id = mention.get("database", {}).get("id", "")
|
85
|
+
result.append(f"@db[{db_id}]")
|
86
|
+
else:
|
87
|
+
# Unknown mention type, fallback to plain text if available
|
88
|
+
result.append(item.get("plain_text", "@[unknown]"))
|
89
|
+
else:
|
90
|
+
# Regular text item
|
91
|
+
result.append(item.get("plain_text", ""))
|
92
|
+
|
93
|
+
return "".join(result)
|
94
|
+
|
95
|
+
@staticmethod
|
96
|
+
def _is_only_mentions(rich_text: List[Dict[str, Any]]) -> bool:
|
97
|
+
"""Check if rich_text array contains only mentions."""
|
98
|
+
if not rich_text:
|
99
|
+
return False
|
100
|
+
|
101
|
+
for item in rich_text:
|
102
|
+
if item.get("type") != "mention":
|
103
|
+
return False
|
104
|
+
|
105
|
+
return True
|
106
|
+
|
107
|
+
@override
|
108
|
+
@staticmethod
|
109
|
+
def is_multiline() -> bool:
|
110
|
+
return False
|
111
|
+
|
112
|
+
@classmethod
|
113
|
+
def get_llm_prompt_content(cls) -> dict:
|
114
|
+
"""
|
115
|
+
Returns a dictionary with all information needed for LLM prompts about this element.
|
116
|
+
"""
|
117
|
+
return {
|
118
|
+
"description": "References to Notion pages, users, databases, or dates within text content.",
|
119
|
+
"when_to_use": "Mentions are typically part of rich text content rather than standalone elements. They're used to link to other Notion content or users.",
|
120
|
+
"syntax": [
|
121
|
+
"@[page-id] - Reference to a Notion page",
|
122
|
+
"@user[user-id] - Reference to a Notion user",
|
123
|
+
"@date[YYYY-MM-DD] - Reference to a date",
|
124
|
+
"@db[database-id] - Reference to a Notion database"
|
125
|
+
],
|
126
|
+
"examples": [
|
127
|
+
"Check the meeting notes at @[1a6389d5-7bd3-80c5-9a87-e90b034989d0]",
|
128
|
+
"Please review this with @user[d3dbbbd7-ec00-4204-94d9-e4a46e4928db]",
|
129
|
+
"Deadline is @date[2023-12-31]"
|
130
|
+
],
|
131
|
+
"limitations": [
|
132
|
+
"Mentions are typically created through Notion's UI rather than direct markdown input",
|
133
|
+
"When converting Notion content to markdown, mentions are represented with their internal IDs"
|
134
|
+
]
|
135
|
+
}
|