notionary 0.2.19__py3-none-any.whl → 0.2.22__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 +8 -4
- notionary/base_notion_client.py +3 -1
- notionary/blocks/__init__.py +2 -91
- notionary/blocks/_bootstrap.py +271 -0
- notionary/blocks/audio/__init__.py +8 -2
- notionary/blocks/audio/audio_element.py +69 -106
- notionary/blocks/audio/audio_markdown_node.py +13 -5
- notionary/blocks/audio/audio_models.py +6 -55
- notionary/blocks/base_block_element.py +42 -0
- notionary/blocks/bookmark/__init__.py +9 -2
- notionary/blocks/bookmark/bookmark_element.py +49 -139
- notionary/blocks/bookmark/bookmark_markdown_node.py +19 -18
- notionary/blocks/bookmark/bookmark_models.py +15 -0
- notionary/blocks/breadcrumbs/__init__.py +17 -0
- notionary/blocks/breadcrumbs/breadcrumb_element.py +39 -0
- notionary/blocks/breadcrumbs/breadcrumb_markdown_node.py +32 -0
- notionary/blocks/breadcrumbs/breadcrumb_models.py +12 -0
- notionary/blocks/bulleted_list/__init__.py +12 -2
- notionary/blocks/bulleted_list/bulleted_list_element.py +55 -53
- notionary/blocks/bulleted_list/bulleted_list_markdown_node.py +2 -1
- notionary/blocks/bulleted_list/bulleted_list_models.py +18 -0
- notionary/blocks/callout/__init__.py +9 -2
- notionary/blocks/callout/callout_element.py +53 -86
- notionary/blocks/callout/callout_markdown_node.py +3 -1
- notionary/blocks/callout/callout_models.py +33 -0
- notionary/blocks/child_database/__init__.py +14 -0
- notionary/blocks/child_database/child_database_element.py +61 -0
- notionary/blocks/child_database/child_database_models.py +12 -0
- notionary/blocks/child_page/__init__.py +9 -0
- notionary/blocks/child_page/child_page_element.py +94 -0
- notionary/blocks/child_page/child_page_models.py +12 -0
- notionary/blocks/{shared/block_client.py → client.py} +54 -54
- notionary/blocks/code/__init__.py +6 -2
- notionary/blocks/code/code_element.py +96 -181
- notionary/blocks/code/code_markdown_node.py +64 -13
- notionary/blocks/code/code_models.py +94 -0
- notionary/blocks/column/__init__.py +25 -1
- notionary/blocks/column/column_element.py +44 -312
- notionary/blocks/column/column_list_element.py +52 -0
- notionary/blocks/column/column_list_markdown_node.py +50 -0
- notionary/blocks/column/column_markdown_node.py +59 -0
- notionary/blocks/column/column_models.py +26 -0
- notionary/blocks/divider/__init__.py +9 -2
- notionary/blocks/divider/divider_element.py +18 -49
- notionary/blocks/divider/divider_markdown_node.py +2 -1
- notionary/blocks/divider/divider_models.py +12 -0
- notionary/blocks/embed/__init__.py +9 -2
- notionary/blocks/embed/embed_element.py +65 -111
- notionary/blocks/embed/embed_markdown_node.py +3 -1
- notionary/blocks/embed/embed_models.py +14 -0
- notionary/blocks/equation/__init__.py +14 -0
- notionary/blocks/equation/equation_element.py +133 -0
- notionary/blocks/equation/equation_element_markdown_node.py +35 -0
- notionary/blocks/equation/equation_models.py +11 -0
- notionary/blocks/file/__init__.py +25 -0
- notionary/blocks/file/file_element.py +112 -0
- notionary/blocks/file/file_element_markdown_node.py +37 -0
- notionary/blocks/file/file_element_models.py +39 -0
- notionary/blocks/guards.py +22 -0
- notionary/blocks/heading/__init__.py +16 -2
- notionary/blocks/heading/heading_element.py +83 -69
- notionary/blocks/heading/heading_markdown_node.py +2 -1
- notionary/blocks/heading/heading_models.py +29 -0
- notionary/blocks/image_block/__init__.py +13 -0
- notionary/blocks/image_block/image_element.py +89 -0
- notionary/blocks/{image → image_block}/image_markdown_node.py +13 -6
- notionary/blocks/image_block/image_models.py +10 -0
- notionary/blocks/mixins/captions/__init__.py +4 -0
- notionary/blocks/mixins/captions/caption_markdown_node_mixin.py +31 -0
- notionary/blocks/mixins/captions/caption_mixin.py +92 -0
- notionary/blocks/models.py +174 -0
- notionary/blocks/numbered_list/__init__.py +12 -2
- notionary/blocks/numbered_list/numbered_list_element.py +48 -56
- notionary/blocks/numbered_list/numbered_list_markdown_node.py +3 -1
- notionary/blocks/numbered_list/numbered_list_models.py +17 -0
- notionary/blocks/paragraph/__init__.py +12 -2
- notionary/blocks/paragraph/paragraph_element.py +40 -66
- notionary/blocks/paragraph/paragraph_markdown_node.py +2 -1
- notionary/blocks/paragraph/paragraph_models.py +16 -0
- notionary/blocks/pdf/__init__.py +13 -0
- notionary/blocks/pdf/pdf_element.py +97 -0
- notionary/blocks/pdf/pdf_markdown_node.py +37 -0
- notionary/blocks/pdf/pdf_models.py +11 -0
- notionary/blocks/quote/__init__.py +11 -2
- notionary/blocks/quote/quote_element.py +45 -62
- notionary/blocks/quote/quote_markdown_node.py +6 -3
- notionary/blocks/quote/quote_models.py +18 -0
- notionary/blocks/registry/__init__.py +4 -0
- notionary/blocks/registry/block_registry.py +60 -121
- notionary/blocks/registry/block_registry_builder.py +115 -59
- notionary/blocks/rich_text/__init__.py +33 -0
- notionary/blocks/rich_text/name_to_id_resolver.py +205 -0
- notionary/blocks/rich_text/rich_text_models.py +221 -0
- notionary/blocks/rich_text/text_inline_formatter.py +456 -0
- notionary/blocks/syntax_prompt_builder.py +137 -0
- notionary/blocks/table/__init__.py +16 -2
- notionary/blocks/table/table_element.py +136 -228
- notionary/blocks/table/table_markdown_node.py +2 -1
- notionary/blocks/table/table_models.py +28 -0
- notionary/blocks/table_of_contents/__init__.py +19 -0
- notionary/blocks/table_of_contents/table_of_contents_element.py +68 -0
- notionary/blocks/table_of_contents/table_of_contents_markdown_node.py +35 -0
- notionary/blocks/table_of_contents/table_of_contents_models.py +18 -0
- notionary/blocks/todo/__init__.py +9 -2
- notionary/blocks/todo/todo_element.py +52 -92
- notionary/blocks/todo/todo_markdown_node.py +2 -1
- notionary/blocks/todo/todo_models.py +19 -0
- notionary/blocks/toggle/__init__.py +13 -3
- notionary/blocks/toggle/toggle_element.py +69 -260
- notionary/blocks/toggle/toggle_markdown_node.py +25 -15
- notionary/blocks/toggle/toggle_models.py +17 -0
- notionary/blocks/toggleable_heading/__init__.py +6 -2
- notionary/blocks/toggleable_heading/toggleable_heading_element.py +86 -241
- notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +26 -18
- notionary/blocks/types.py +130 -0
- notionary/blocks/video/__init__.py +8 -2
- notionary/blocks/video/video_element.py +70 -141
- notionary/blocks/video/video_element_models.py +10 -0
- notionary/blocks/video/video_markdown_node.py +13 -6
- notionary/database/client.py +26 -8
- notionary/database/database.py +13 -14
- notionary/database/database_filter_builder.py +2 -2
- notionary/database/database_provider.py +5 -4
- notionary/database/models.py +337 -0
- notionary/database/notion_database.py +6 -7
- notionary/file_upload/client.py +5 -7
- notionary/file_upload/models.py +3 -2
- notionary/file_upload/notion_file_upload.py +2 -3
- notionary/markdown/markdown_builder.py +729 -0
- notionary/markdown/markdown_document_model.py +228 -0
- notionary/{blocks → markdown}/markdown_node.py +1 -0
- notionary/models/notion_database_response.py +0 -338
- notionary/page/client.py +34 -15
- notionary/page/models.py +327 -0
- notionary/page/notion_page.py +136 -58
- notionary/page/{content/page_content_writer.py → page_content_deleting_service.py} +25 -59
- notionary/page/page_content_writer.py +177 -0
- notionary/page/page_context.py +65 -0
- notionary/page/reader/handler/__init__.py +19 -0
- notionary/page/reader/handler/base_block_renderer.py +44 -0
- notionary/page/reader/handler/block_processing_context.py +35 -0
- notionary/page/reader/handler/block_rendering_context.py +48 -0
- notionary/page/reader/handler/column_list_renderer.py +51 -0
- notionary/page/reader/handler/column_renderer.py +60 -0
- notionary/page/reader/handler/line_renderer.py +73 -0
- notionary/page/reader/handler/numbered_list_renderer.py +85 -0
- notionary/page/reader/handler/toggle_renderer.py +69 -0
- notionary/page/reader/handler/toggleable_heading_renderer.py +89 -0
- notionary/page/reader/page_content_retriever.py +81 -0
- notionary/page/search_filter_builder.py +2 -1
- notionary/page/writer/handler/__init__.py +24 -0
- notionary/page/writer/handler/code_handler.py +72 -0
- notionary/page/writer/handler/column_handler.py +141 -0
- notionary/page/writer/handler/column_list_handler.py +139 -0
- notionary/page/writer/handler/equation_handler.py +74 -0
- notionary/page/writer/handler/line_handler.py +35 -0
- notionary/page/writer/handler/line_processing_context.py +54 -0
- notionary/page/writer/handler/regular_line_handler.py +86 -0
- notionary/page/writer/handler/table_handler.py +66 -0
- notionary/page/writer/handler/toggle_handler.py +155 -0
- notionary/page/writer/handler/toggleable_heading_handler.py +173 -0
- notionary/page/writer/markdown_to_notion_converter.py +95 -0
- notionary/page/writer/markdown_to_notion_converter_context.py +30 -0
- notionary/page/writer/markdown_to_notion_formatting_post_processor.py +73 -0
- notionary/page/writer/notion_text_length_processor.py +150 -0
- notionary/telemetry/__init__.py +2 -2
- notionary/telemetry/service.py +3 -3
- notionary/user/__init__.py +2 -2
- notionary/user/base_notion_user.py +2 -1
- notionary/user/client.py +2 -3
- notionary/user/models.py +1 -0
- notionary/user/notion_bot_user.py +4 -5
- notionary/user/notion_user.py +3 -4
- notionary/user/notion_user_manager.py +23 -95
- notionary/util/__init__.py +3 -2
- notionary/util/fuzzy.py +2 -1
- notionary/util/logging_mixin.py +2 -2
- notionary/util/singleton_metaclass.py +1 -1
- notionary/workspace.py +6 -5
- notionary-0.2.22.dist-info/METADATA +237 -0
- notionary-0.2.22.dist-info/RECORD +200 -0
- notionary/blocks/document/__init__.py +0 -7
- notionary/blocks/document/document_element.py +0 -102
- notionary/blocks/document/document_markdown_node.py +0 -31
- notionary/blocks/image/__init__.py +0 -7
- notionary/blocks/image/image_element.py +0 -151
- notionary/blocks/markdown_builder.py +0 -356
- notionary/blocks/mention/__init__.py +0 -7
- notionary/blocks/mention/mention_element.py +0 -229
- notionary/blocks/mention/mention_markdown_node.py +0 -38
- notionary/blocks/prompts/element_prompt_builder.py +0 -83
- notionary/blocks/prompts/element_prompt_content.py +0 -41
- notionary/blocks/shared/models.py +0 -713
- notionary/blocks/shared/notion_block_element.py +0 -37
- notionary/blocks/shared/text_inline_formatter.py +0 -262
- notionary/blocks/shared/text_inline_formatter_new.py +0 -139
- notionary/database/models/page_result.py +0 -10
- notionary/models/notion_block_response.py +0 -264
- notionary/models/notion_page_response.py +0 -78
- notionary/models/search_response.py +0 -0
- notionary/page/__init__.py +0 -0
- notionary/page/content/markdown_whitespace_processor.py +0 -80
- notionary/page/content/notion_text_length_utils.py +0 -87
- notionary/page/content/page_content_retriever.py +0 -60
- notionary/page/formatting/line_processor.py +0 -153
- notionary/page/formatting/markdown_to_notion_converter.py +0 -153
- notionary/page/markdown_syntax_prompt_generator.py +0 -114
- notionary/page/notion_to_markdown_converter.py +0 -179
- notionary/page/properites/property_value_extractor.py +0 -0
- notionary/user/notion_user_provider.py +0 -1
- notionary-0.2.19.dist-info/METADATA +0 -225
- notionary-0.2.19.dist-info/RECORD +0 -150
- /notionary/{blocks/document/document_models.py → markdown/___init__.py} +0 -0
- /notionary/{blocks/image/image_models.py → markdown/makdown_document_model.py} +0 -0
- /notionary/{blocks/mention/mention_models.py → page/reader/handler/equation_renderer.py} +0 -0
- /notionary/{blocks/shared/__init__.py → page/writer/markdown_to_notion_post_processor.py} +0 -0
- /notionary/{blocks/toggleable_heading/toggleable_heading_models.py → page/writer/markdown_to_notion_text_length_post_processor.py} +0 -0
- /notionary/{elements/__init__.py → util/concurrency_limiter.py} +0 -0
- {notionary-0.2.19.dist-info → notionary-0.2.22.dist-info}/LICENSE +0 -0
- {notionary-0.2.19.dist-info → notionary-0.2.22.dist-info}/WHEEL +0 -0
@@ -1,32 +1,34 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
-
from typing import Type, TYPE_CHECKING, Self
|
3
|
-
from collections import OrderedDict
|
4
2
|
|
5
|
-
from
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
3
|
+
from collections import OrderedDict
|
4
|
+
from typing import TYPE_CHECKING, Self, Type
|
5
|
+
|
6
|
+
from notionary.blocks.audio import AudioElement
|
7
|
+
from notionary.blocks.base_block_element import BaseBlockElement
|
8
|
+
from notionary.blocks.bookmark import BookmarkElement
|
9
|
+
from notionary.blocks.breadcrumbs import BreadcrumbElement
|
10
|
+
from notionary.blocks.bulleted_list import BulletedListElement
|
11
|
+
from notionary.blocks.callout import CalloutElement
|
12
|
+
from notionary.blocks.child_database import ChildDatabaseElement
|
13
|
+
from notionary.blocks.code import CodeElement
|
14
|
+
from notionary.blocks.column import ColumnElement, ColumnListElement
|
15
|
+
from notionary.blocks.divider import DividerElement
|
16
|
+
from notionary.blocks.embed import EmbedElement
|
17
|
+
from notionary.blocks.equation import EquationElement
|
18
|
+
from notionary.blocks.heading import HeadingElement
|
19
|
+
from notionary.blocks.image_block import ImageElement
|
20
|
+
from notionary.blocks.numbered_list import NumberedListElement
|
21
|
+
from notionary.blocks.paragraph import ParagraphElement
|
22
|
+
from notionary.blocks.quote import QuoteElement
|
23
|
+
from notionary.blocks.table import TableElement
|
24
|
+
from notionary.blocks.table_of_contents import TableOfContentsElement
|
25
|
+
from notionary.blocks.todo import TodoElement
|
26
|
+
from notionary.blocks.toggle import ToggleElement
|
27
|
+
from notionary.blocks.toggleable_heading import ToggleableHeadingElement
|
28
|
+
from notionary.blocks.video import VideoElement
|
27
29
|
|
28
30
|
if TYPE_CHECKING:
|
29
|
-
from notionary.blocks import BlockRegistry
|
31
|
+
from notionary.blocks.registry.block_registry import BlockRegistry
|
30
32
|
|
31
33
|
|
32
34
|
class BlockRegistryBuilder:
|
@@ -63,13 +65,16 @@ class BlockRegistryBuilder:
|
|
63
65
|
.with_videos()
|
64
66
|
.with_embeds()
|
65
67
|
.with_audio()
|
66
|
-
.with_columns()
|
67
|
-
.with_mention()
|
68
68
|
.with_paragraphs()
|
69
69
|
.with_toggleable_heading_element()
|
70
|
+
.with_columns()
|
71
|
+
.with_equation()
|
72
|
+
.with_table_of_contents()
|
73
|
+
.with_breadcrumbs()
|
74
|
+
.with_child_database()
|
70
75
|
).build()
|
71
76
|
|
72
|
-
def remove_element(self, element_class: Type[
|
77
|
+
def remove_element(self, element_class: Type[BaseBlockElement]) -> Self:
|
73
78
|
"""
|
74
79
|
Remove an element class from the registry configuration.
|
75
80
|
|
@@ -84,92 +89,143 @@ class BlockRegistryBuilder:
|
|
84
89
|
|
85
90
|
# WITH methods (existing)
|
86
91
|
def with_paragraphs(self) -> Self:
|
87
|
-
"""Add support for paragraph elements."""
|
88
92
|
return self._add_element(ParagraphElement)
|
89
93
|
|
90
94
|
def with_headings(self) -> Self:
|
91
|
-
"""Add support for heading elements."""
|
92
95
|
return self._add_element(HeadingElement)
|
93
96
|
|
94
97
|
def with_callouts(self) -> Self:
|
95
|
-
"""Add support for callout elements."""
|
96
98
|
return self._add_element(CalloutElement)
|
97
99
|
|
98
100
|
def with_code(self) -> Self:
|
99
|
-
"""Add support for code blocks."""
|
100
101
|
return self._add_element(CodeElement)
|
101
102
|
|
102
103
|
def with_dividers(self) -> Self:
|
103
|
-
"""Add support for divider elements."""
|
104
104
|
return self._add_element(DividerElement)
|
105
105
|
|
106
106
|
def with_tables(self) -> Self:
|
107
|
-
"""Add support for tables."""
|
108
107
|
return self._add_element(TableElement)
|
109
108
|
|
110
109
|
def with_bulleted_list(self) -> Self:
|
111
|
-
"""Add support for bulleted list elements (unordered lists)."""
|
112
110
|
return self._add_element(BulletedListElement)
|
113
111
|
|
114
112
|
def with_numbered_list(self) -> Self:
|
115
|
-
"""Add support for numbered list elements (ordered lists)."""
|
116
113
|
return self._add_element(NumberedListElement)
|
117
114
|
|
118
115
|
def with_toggles(self) -> Self:
|
119
|
-
"""Add support for toggle elements."""
|
120
116
|
return self._add_element(ToggleElement)
|
121
117
|
|
122
118
|
def with_quotes(self) -> Self:
|
123
|
-
"""Add support for quote elements."""
|
124
119
|
return self._add_element(QuoteElement)
|
125
120
|
|
126
121
|
def with_todos(self) -> Self:
|
127
|
-
"""Add support for todo elements."""
|
128
122
|
return self._add_element(TodoElement)
|
129
123
|
|
130
124
|
def with_bookmarks(self) -> Self:
|
131
|
-
"""Add support for bookmark elements."""
|
132
125
|
return self._add_element(BookmarkElement)
|
133
126
|
|
134
127
|
def with_images(self) -> Self:
|
135
|
-
"""Add support for image elements."""
|
136
128
|
return self._add_element(ImageElement)
|
137
129
|
|
138
130
|
def with_videos(self) -> Self:
|
139
|
-
"""Add support for video elements."""
|
140
131
|
return self._add_element(VideoElement)
|
141
132
|
|
142
133
|
def with_embeds(self) -> Self:
|
143
|
-
"""Add support for embed elements."""
|
144
134
|
return self._add_element(EmbedElement)
|
145
135
|
|
146
136
|
def with_audio(self) -> Self:
|
147
|
-
"""Add support for audio elements."""
|
148
137
|
return self._add_element(AudioElement)
|
149
138
|
|
150
|
-
def with_mention(self) -> Self:
|
151
|
-
"""Add support for mention elements."""
|
152
|
-
return self._add_element(MentionElement)
|
153
|
-
|
154
139
|
def with_toggleable_heading_element(self) -> Self:
|
155
|
-
"""Add support for toggleable heading elements."""
|
156
140
|
return self._add_element(ToggleableHeadingElement)
|
157
141
|
|
158
142
|
def with_columns(self) -> Self:
|
159
|
-
|
160
|
-
|
143
|
+
self._add_element(ColumnListElement)
|
144
|
+
self._add_element(ColumnElement)
|
145
|
+
return self
|
146
|
+
|
147
|
+
def with_equation(self) -> Self:
|
148
|
+
return self._add_element(EquationElement)
|
149
|
+
|
150
|
+
def with_table_of_contents(self) -> Self:
|
151
|
+
return self._add_element(TableOfContentsElement)
|
152
|
+
|
153
|
+
def with_breadcrumbs(self) -> Self:
|
154
|
+
return self._add_element(BreadcrumbElement)
|
155
|
+
|
156
|
+
def with_child_database(self) -> Self:
|
157
|
+
return self._add_element(ChildDatabaseElement)
|
158
|
+
|
159
|
+
def without_headings(self) -> Self:
|
160
|
+
return self.remove_element(HeadingElement)
|
161
|
+
|
162
|
+
def without_callouts(self) -> Self:
|
163
|
+
return self.remove_element(CalloutElement)
|
164
|
+
|
165
|
+
def without_code(self) -> Self:
|
166
|
+
return self.remove_element(CodeElement)
|
167
|
+
|
168
|
+
def without_dividers(self) -> Self:
|
169
|
+
return self.remove_element(DividerElement)
|
170
|
+
|
171
|
+
def without_tables(self) -> Self:
|
172
|
+
return self.remove_element(TableElement)
|
173
|
+
|
174
|
+
def without_bulleted_list(self) -> Self:
|
175
|
+
return self.remove_element(BulletedListElement)
|
176
|
+
|
177
|
+
def without_numbered_list(self) -> Self:
|
178
|
+
return self.remove_element(NumberedListElement)
|
179
|
+
|
180
|
+
def without_toggles(self) -> Self:
|
181
|
+
return self.remove_element(ToggleElement)
|
182
|
+
|
183
|
+
def without_quotes(self) -> Self:
|
184
|
+
return self.remove_element(QuoteElement)
|
185
|
+
|
186
|
+
def without_todos(self) -> Self:
|
187
|
+
return self.remove_element(TodoElement)
|
188
|
+
|
189
|
+
def without_bookmarks(self) -> Self:
|
190
|
+
return self.remove_element(BookmarkElement)
|
191
|
+
|
192
|
+
def without_images(self) -> Self:
|
193
|
+
return self.remove_element(ImageElement)
|
194
|
+
|
195
|
+
def without_videos(self) -> Self:
|
196
|
+
return self.remove_element(VideoElement)
|
197
|
+
|
198
|
+
def without_embeds(self) -> Self:
|
199
|
+
return self.remove_element(EmbedElement)
|
200
|
+
|
201
|
+
def without_audio(self) -> Self:
|
202
|
+
return self.remove_element(AudioElement)
|
203
|
+
|
204
|
+
def without_toggleable_heading_element(self) -> Self:
|
205
|
+
return self.remove_element(ToggleableHeadingElement)
|
206
|
+
|
207
|
+
def without_columns(self) -> Self:
|
208
|
+
self.remove_element(ColumnListElement)
|
209
|
+
self.remove_element(ColumnElement)
|
210
|
+
return self
|
211
|
+
|
212
|
+
def without_equation(self) -> Self:
|
213
|
+
return self.remove_element(EquationElement)
|
214
|
+
|
215
|
+
def without_table_of_contents(self) -> Self:
|
216
|
+
return self.remove_element(TableOfContentsElement)
|
217
|
+
|
218
|
+
def without_breadcrumbs(self) -> Self:
|
219
|
+
return self.remove_element(BreadcrumbElement)
|
220
|
+
|
221
|
+
def without_child_database(self) -> Self:
|
222
|
+
return self.remove_element(ChildDatabaseElement)
|
161
223
|
|
162
224
|
def build(self) -> BlockRegistry:
|
163
225
|
"""
|
164
226
|
Build and return the configured BlockRegistry instance.
|
165
|
-
|
166
|
-
This automatically ensures that ParagraphElement is at the end
|
167
|
-
of the registry as a fallback element.
|
168
|
-
|
169
|
-
Returns:
|
170
|
-
A configured BlockRegistry instance
|
171
227
|
"""
|
172
|
-
from notionary.blocks import BlockRegistry
|
228
|
+
from notionary.blocks.registry.block_registry import BlockRegistry
|
173
229
|
|
174
230
|
# Ensure ParagraphElement is always present and at the end
|
175
231
|
self._ensure_paragraph_at_end()
|
@@ -191,7 +247,7 @@ class BlockRegistryBuilder:
|
|
191
247
|
self._elements.pop(ParagraphElement.__name__, None)
|
192
248
|
self._elements[ParagraphElement.__name__] = ParagraphElement
|
193
249
|
|
194
|
-
def _add_element(self, element_class: Type[
|
250
|
+
def _add_element(self, element_class: Type[BaseBlockElement]) -> Self:
|
195
251
|
"""
|
196
252
|
Add an element class to the registry configuration.
|
197
253
|
If the element already exists, it's moved to the end.
|
@@ -0,0 +1,33 @@
|
|
1
|
+
"""Rich text handling for Notionary."""
|
2
|
+
|
3
|
+
from notionary.blocks.rich_text.rich_text_models import (
|
4
|
+
EquationObject,
|
5
|
+
LinkObject,
|
6
|
+
MentionDatabaseRef,
|
7
|
+
MentionDate,
|
8
|
+
MentionLinkPreview,
|
9
|
+
MentionObject,
|
10
|
+
MentionPageRef,
|
11
|
+
MentionTemplateMention,
|
12
|
+
MentionUserRef,
|
13
|
+
RichTextObject,
|
14
|
+
TextAnnotations,
|
15
|
+
TextContent,
|
16
|
+
)
|
17
|
+
from notionary.blocks.rich_text.text_inline_formatter import TextInlineFormatter
|
18
|
+
|
19
|
+
__all__ = [
|
20
|
+
"RichTextObject",
|
21
|
+
"TextAnnotations",
|
22
|
+
"LinkObject",
|
23
|
+
"TextContent",
|
24
|
+
"EquationObject",
|
25
|
+
"MentionUserRef",
|
26
|
+
"MentionPageRef",
|
27
|
+
"MentionDatabaseRef",
|
28
|
+
"MentionLinkPreview",
|
29
|
+
"MentionDate",
|
30
|
+
"MentionTemplateMention",
|
31
|
+
"MentionObject",
|
32
|
+
"TextInlineFormatter",
|
33
|
+
]
|
@@ -0,0 +1,205 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import logging
|
4
|
+
from contextlib import contextmanager
|
5
|
+
from typing import Optional
|
6
|
+
|
7
|
+
from notionary.user.notion_user_manager import NotionUserManager
|
8
|
+
from notionary.util import format_uuid
|
9
|
+
from notionary.util.fuzzy import find_best_match
|
10
|
+
|
11
|
+
|
12
|
+
class NameIdResolver:
|
13
|
+
"""
|
14
|
+
Bidirectional resolver for Notion page and database names and IDs.
|
15
|
+
"""
|
16
|
+
|
17
|
+
def __init__(
|
18
|
+
self,
|
19
|
+
*,
|
20
|
+
token: Optional[str] = None,
|
21
|
+
search_limit: int = 10,
|
22
|
+
):
|
23
|
+
"""
|
24
|
+
Initialize the resolver with a Notion workspace.
|
25
|
+
"""
|
26
|
+
from notionary import NotionWorkspace
|
27
|
+
|
28
|
+
self.workspace = NotionWorkspace(token=token)
|
29
|
+
self.notion_user_manager = NotionUserManager(token=token)
|
30
|
+
self.search_limit = search_limit
|
31
|
+
|
32
|
+
async def resolve_page_id(self, name: str) -> Optional[str]:
|
33
|
+
"""
|
34
|
+
Convert a page name to its Notion page ID.
|
35
|
+
Specifically searches only pages, not databases.
|
36
|
+
"""
|
37
|
+
if not name:
|
38
|
+
return None
|
39
|
+
|
40
|
+
cleaned_name = name.strip()
|
41
|
+
|
42
|
+
# Return if already a valid Notion ID
|
43
|
+
formatted_uuid = format_uuid(cleaned_name)
|
44
|
+
if formatted_uuid:
|
45
|
+
return formatted_uuid
|
46
|
+
|
47
|
+
# Search for page by name
|
48
|
+
return await self._resolve_page_id(cleaned_name)
|
49
|
+
|
50
|
+
async def resolve_database_id(self, name: str) -> Optional[str]:
|
51
|
+
"""
|
52
|
+
Convert a database name to its Notion database ID.
|
53
|
+
Specifically searches only databases, not pages.
|
54
|
+
"""
|
55
|
+
if not name:
|
56
|
+
return None
|
57
|
+
|
58
|
+
cleaned_name = name.strip()
|
59
|
+
|
60
|
+
formatted_uuid = format_uuid(cleaned_name)
|
61
|
+
if formatted_uuid:
|
62
|
+
return formatted_uuid
|
63
|
+
|
64
|
+
return await self._resolve_database_id(cleaned_name)
|
65
|
+
|
66
|
+
async def resolve_page_name(self, page_id: str) -> Optional[str]:
|
67
|
+
"""
|
68
|
+
Convert a Notion page ID to its human-readable title.
|
69
|
+
"""
|
70
|
+
if not page_id:
|
71
|
+
return None
|
72
|
+
|
73
|
+
formatted_id = format_uuid(page_id)
|
74
|
+
if not formatted_id:
|
75
|
+
return None
|
76
|
+
|
77
|
+
try:
|
78
|
+
from notionary import NotionPage
|
79
|
+
|
80
|
+
page = await NotionPage.from_page_id(formatted_id)
|
81
|
+
return page.title if page else None
|
82
|
+
except Exception:
|
83
|
+
return None
|
84
|
+
|
85
|
+
async def resolve_database_name(self, database_id: str) -> Optional[str]:
|
86
|
+
"""
|
87
|
+
Convert a Notion database ID to its human-readable title.
|
88
|
+
"""
|
89
|
+
if not database_id:
|
90
|
+
return None
|
91
|
+
|
92
|
+
# Validate and format UUID
|
93
|
+
formatted_id = format_uuid(database_id)
|
94
|
+
if not formatted_id:
|
95
|
+
return None
|
96
|
+
|
97
|
+
try:
|
98
|
+
from notionary.database import NotionDatabase
|
99
|
+
|
100
|
+
database = await NotionDatabase.from_database_id(formatted_id)
|
101
|
+
return database.title if database else None
|
102
|
+
except Exception:
|
103
|
+
return None
|
104
|
+
|
105
|
+
async def resolve_user_id(self, name: str) -> Optional[str]:
|
106
|
+
"""
|
107
|
+
Convert a user name to its Notion user ID.
|
108
|
+
Specifically searches only users.
|
109
|
+
"""
|
110
|
+
if not name:
|
111
|
+
return None
|
112
|
+
|
113
|
+
cleaned_name = name.strip()
|
114
|
+
|
115
|
+
# Return if already a valid Notion ID
|
116
|
+
formatted_uuid = format_uuid(cleaned_name)
|
117
|
+
if formatted_uuid:
|
118
|
+
return formatted_uuid
|
119
|
+
|
120
|
+
# Search for user by name
|
121
|
+
return await self._resolve_user_id(cleaned_name)
|
122
|
+
|
123
|
+
async def resolve_user_name(self, user_id: str) -> Optional[str]:
|
124
|
+
"""
|
125
|
+
Convert a Notion user ID to its human-readable name.
|
126
|
+
|
127
|
+
Args:
|
128
|
+
user_id: Notion user ID to resolve
|
129
|
+
|
130
|
+
Returns:
|
131
|
+
User name if found, None if not found or inaccessible
|
132
|
+
"""
|
133
|
+
if not user_id:
|
134
|
+
return None
|
135
|
+
|
136
|
+
# Validate and format UUID
|
137
|
+
formatted_id = format_uuid(user_id)
|
138
|
+
if not formatted_id:
|
139
|
+
return None
|
140
|
+
|
141
|
+
try:
|
142
|
+
user = await self.notion_user_manager.get_user_by_id(formatted_id)
|
143
|
+
return user.name if user else None
|
144
|
+
except Exception:
|
145
|
+
return None
|
146
|
+
|
147
|
+
async def _resolve_user_id(self, name: str) -> Optional[str]:
|
148
|
+
"""Search for users matching the name."""
|
149
|
+
try:
|
150
|
+
users = await self.notion_user_manager.find_users_by_name(name)
|
151
|
+
|
152
|
+
if not users:
|
153
|
+
return None
|
154
|
+
|
155
|
+
# Use fuzzy matching to find best match
|
156
|
+
best_match = find_best_match(
|
157
|
+
query=name,
|
158
|
+
items=users,
|
159
|
+
text_extractor=lambda user: user.name or "",
|
160
|
+
)
|
161
|
+
|
162
|
+
return best_match.item.id if best_match else None
|
163
|
+
except Exception:
|
164
|
+
return None
|
165
|
+
|
166
|
+
async def _resolve_page_id(self, name: str) -> Optional[str]:
|
167
|
+
"""Search for pages matching the name."""
|
168
|
+
search_results = await self.workspace.search_pages(
|
169
|
+
query=name, limit=self.search_limit
|
170
|
+
)
|
171
|
+
|
172
|
+
return self._find_best_fuzzy_match(query=name, candidate_objects=search_results)
|
173
|
+
|
174
|
+
async def _resolve_database_id(self, name: str) -> Optional[str]:
|
175
|
+
"""Search for databases matching the name."""
|
176
|
+
search_results = await self.workspace.search_databases(
|
177
|
+
query=name, limit=self.search_limit
|
178
|
+
)
|
179
|
+
|
180
|
+
return self._find_best_fuzzy_match(query=name, candidate_objects=search_results)
|
181
|
+
|
182
|
+
def _find_best_fuzzy_match(
|
183
|
+
self, query: str, candidate_objects: list
|
184
|
+
) -> Optional[str]:
|
185
|
+
"""
|
186
|
+
Find the best fuzzy match among candidate objects using existing fuzzy matching logic.
|
187
|
+
|
188
|
+
Args:
|
189
|
+
query: The search query to match against
|
190
|
+
candidate_objects: Objects (pages or databases) with .id and .title attributes
|
191
|
+
|
192
|
+
Returns:
|
193
|
+
ID of best match, or None if no match meets threshold
|
194
|
+
"""
|
195
|
+
if not candidate_objects:
|
196
|
+
return None
|
197
|
+
|
198
|
+
# Use existing fuzzy matching logic
|
199
|
+
best_match = find_best_match(
|
200
|
+
query=query,
|
201
|
+
items=candidate_objects,
|
202
|
+
text_extractor=lambda obj: obj.title,
|
203
|
+
)
|
204
|
+
|
205
|
+
return best_match.item.id if best_match else None
|