notionary 0.2.22__py3-none-any.whl → 0.2.24__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 +1 -1
- notionary/blocks/__init__.py +3 -1
- notionary/blocks/audio/__init__.py +0 -2
- notionary/blocks/audio/audio_element.py +92 -49
- notionary/blocks/audio/audio_markdown_node.py +4 -17
- notionary/blocks/bookmark/__init__.py +0 -2
- notionary/blocks/bookmark/bookmark_markdown_node.py +5 -21
- notionary/blocks/breadcrumbs/__init__.py +0 -2
- notionary/blocks/breadcrumbs/breadcrumb_markdown_node.py +2 -21
- notionary/blocks/bulleted_list/__init__.py +0 -2
- notionary/blocks/bulleted_list/bulleted_list_markdown_node.py +3 -17
- notionary/blocks/bulleted_list/bulleted_list_models.py +0 -1
- notionary/blocks/callout/__init__.py +0 -2
- notionary/blocks/callout/callout_markdown_node.py +4 -18
- notionary/blocks/callout/callout_models.py +3 -4
- notionary/blocks/child_database/child_database_element.py +2 -4
- notionary/blocks/code/code_markdown_node.py +5 -19
- notionary/blocks/column/__init__.py +0 -4
- notionary/blocks/column/column_list_markdown_node.py +3 -19
- notionary/blocks/column/column_markdown_node.py +4 -21
- notionary/blocks/divider/__init__.py +0 -2
- notionary/blocks/divider/divider_markdown_node.py +2 -16
- notionary/blocks/embed/__init__.py +0 -2
- notionary/blocks/embed/embed_markdown_node.py +4 -17
- notionary/blocks/equation/__init__.py +0 -1
- notionary/blocks/equation/equation_element_markdown_node.py +3 -15
- notionary/blocks/file/__init__.py +0 -2
- notionary/blocks/file/file_element.py +67 -46
- notionary/blocks/file/file_element_markdown_node.py +4 -17
- notionary/blocks/heading/__init__.py +0 -2
- notionary/blocks/heading/heading_markdown_node.py +5 -19
- notionary/blocks/heading/heading_models.py +3 -3
- notionary/blocks/image_block/__init__.py +0 -2
- notionary/blocks/image_block/image_element.py +66 -25
- notionary/blocks/image_block/image_markdown_node.py +5 -20
- notionary/{markdown → blocks/markdown}/markdown_builder.py +29 -233
- notionary/blocks/markdown/markdown_node.py +25 -0
- notionary/blocks/mixins/file_upload/__init__.py +3 -0
- notionary/blocks/mixins/file_upload/file_upload_mixin.py +320 -0
- notionary/blocks/numbered_list/__init__.py +0 -1
- notionary/blocks/numbered_list/numbered_list_markdown_node.py +3 -17
- notionary/blocks/numbered_list/numbered_list_models.py +3 -3
- notionary/blocks/paragraph/__init__.py +0 -2
- notionary/blocks/paragraph/paragraph_markdown_node.py +3 -13
- notionary/blocks/pdf/__init__.py +0 -2
- notionary/blocks/pdf/pdf_element.py +81 -32
- notionary/blocks/pdf/pdf_markdown_node.py +5 -18
- notionary/blocks/quote/__init__.py +0 -2
- notionary/blocks/quote/quote_markdown_node.py +3 -13
- notionary/blocks/registry/__init__.py +1 -2
- notionary/blocks/registry/block_registry.py +116 -61
- notionary/blocks/rich_text/text_inline_formatter.py +1 -1
- notionary/blocks/table/__init__.py +0 -2
- notionary/blocks/table/table_markdown_node.py +17 -16
- notionary/blocks/table_of_contents/__init__.py +0 -2
- notionary/blocks/table_of_contents/table_of_contents_element.py +27 -15
- notionary/blocks/table_of_contents/table_of_contents_markdown_node.py +3 -17
- notionary/blocks/table_of_contents/table_of_contents_models.py +2 -2
- notionary/blocks/todo/__init__.py +0 -2
- notionary/blocks/todo/todo_markdown_node.py +9 -20
- notionary/blocks/todo/todo_models.py +2 -3
- notionary/blocks/toggle/__init__.py +0 -2
- notionary/blocks/toggle/toggle_markdown_node.py +5 -19
- notionary/blocks/toggleable_heading/__init__.py +0 -2
- notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +6 -23
- notionary/blocks/video/__init__.py +0 -2
- notionary/blocks/video/video_element.py +110 -34
- notionary/blocks/video/video_markdown_node.py +4 -15
- notionary/comments/__init__.py +26 -0
- notionary/comments/client.py +211 -0
- notionary/comments/models.py +129 -0
- notionary/file_upload/client.py +3 -2
- notionary/file_upload/models.py +10 -1
- notionary/file_upload/notion_file_upload.py +5 -5
- notionary/page/client.py +1 -6
- notionary/page/markdown_whitespace_processor.py +129 -0
- notionary/page/notion_page.py +87 -48
- notionary/page/page_content_deleting_service.py +1 -1
- notionary/page/page_content_writer.py +32 -129
- notionary/page/page_context.py +0 -6
- notionary/page/reader/handler/column_list_renderer.py +2 -2
- notionary/page/reader/handler/column_renderer.py +2 -2
- notionary/page/reader/handler/line_renderer.py +2 -2
- notionary/page/reader/handler/toggle_renderer.py +2 -2
- notionary/page/reader/handler/toggleable_heading_renderer.py +2 -2
- notionary/page/writer/handler/toggle_handler.py +8 -4
- notionary/page/writer/handler/toggleable_heading_handler.py +3 -2
- notionary/page/writer/markdown_to_notion_converter.py +74 -30
- notionary/schemas/__init__.py +3 -0
- notionary/schemas/base.py +73 -0
- notionary/shared/__init__.py +3 -0
- notionary/{blocks/rich_text → shared}/name_to_id_resolver.py +0 -2
- {notionary-0.2.22.dist-info → notionary-0.2.24.dist-info}/METADATA +15 -2
- {notionary-0.2.22.dist-info → notionary-0.2.24.dist-info}/RECORD +97 -95
- notionary/blocks/guards.py +0 -22
- notionary/blocks/registry/block_registry_builder.py +0 -264
- notionary/markdown/makdown_document_model.py +0 -0
- notionary/markdown/markdown_document_model.py +0 -228
- notionary/markdown/markdown_node.py +0 -30
- notionary/models/notion_database_response.py +0 -0
- notionary/page/writer/markdown_to_notion_formatting_post_processor.py +0 -73
- notionary/page/writer/markdown_to_notion_post_processor.py +0 -0
- /notionary/{markdown/___init__.py → blocks/markdown/markdown_document_model.py} +0 -0
- {notionary-0.2.22.dist-info → notionary-0.2.24.dist-info}/LICENSE +0 -0
- {notionary-0.2.22.dist-info → notionary-0.2.24.dist-info}/WHEEL +0 -0
@@ -1,264 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
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
|
29
|
-
|
30
|
-
if TYPE_CHECKING:
|
31
|
-
from notionary.blocks.registry.block_registry import BlockRegistry
|
32
|
-
|
33
|
-
|
34
|
-
class BlockRegistryBuilder:
|
35
|
-
"""
|
36
|
-
True builder for constructing BlockRegistry instances.
|
37
|
-
|
38
|
-
This builder allows for incremental construction of registry instances
|
39
|
-
with specific configurations of block elements.
|
40
|
-
"""
|
41
|
-
|
42
|
-
def __init__(self):
|
43
|
-
"""Initialize a new builder with an empty element list."""
|
44
|
-
self._elements = OrderedDict()
|
45
|
-
|
46
|
-
@classmethod
|
47
|
-
def create_registry(cls) -> BlockRegistry:
|
48
|
-
"""
|
49
|
-
Start with all standard elements in recommended order.
|
50
|
-
"""
|
51
|
-
builder = cls()
|
52
|
-
return (
|
53
|
-
builder.with_headings()
|
54
|
-
.with_callouts()
|
55
|
-
.with_code()
|
56
|
-
.with_dividers()
|
57
|
-
.with_tables()
|
58
|
-
.with_bulleted_list()
|
59
|
-
.with_numbered_list()
|
60
|
-
.with_toggles()
|
61
|
-
.with_quotes()
|
62
|
-
.with_todos()
|
63
|
-
.with_bookmarks()
|
64
|
-
.with_images()
|
65
|
-
.with_videos()
|
66
|
-
.with_embeds()
|
67
|
-
.with_audio()
|
68
|
-
.with_paragraphs()
|
69
|
-
.with_toggleable_heading_element()
|
70
|
-
.with_columns()
|
71
|
-
.with_equation()
|
72
|
-
.with_table_of_contents()
|
73
|
-
.with_breadcrumbs()
|
74
|
-
.with_child_database()
|
75
|
-
).build()
|
76
|
-
|
77
|
-
def remove_element(self, element_class: Type[BaseBlockElement]) -> Self:
|
78
|
-
"""
|
79
|
-
Remove an element class from the registry configuration.
|
80
|
-
|
81
|
-
Args:
|
82
|
-
element_class: The element class to remove
|
83
|
-
|
84
|
-
Returns:
|
85
|
-
Self for method chaining
|
86
|
-
"""
|
87
|
-
self._elements.pop(element_class.__name__, None)
|
88
|
-
return self
|
89
|
-
|
90
|
-
# WITH methods (existing)
|
91
|
-
def with_paragraphs(self) -> Self:
|
92
|
-
return self._add_element(ParagraphElement)
|
93
|
-
|
94
|
-
def with_headings(self) -> Self:
|
95
|
-
return self._add_element(HeadingElement)
|
96
|
-
|
97
|
-
def with_callouts(self) -> Self:
|
98
|
-
return self._add_element(CalloutElement)
|
99
|
-
|
100
|
-
def with_code(self) -> Self:
|
101
|
-
return self._add_element(CodeElement)
|
102
|
-
|
103
|
-
def with_dividers(self) -> Self:
|
104
|
-
return self._add_element(DividerElement)
|
105
|
-
|
106
|
-
def with_tables(self) -> Self:
|
107
|
-
return self._add_element(TableElement)
|
108
|
-
|
109
|
-
def with_bulleted_list(self) -> Self:
|
110
|
-
return self._add_element(BulletedListElement)
|
111
|
-
|
112
|
-
def with_numbered_list(self) -> Self:
|
113
|
-
return self._add_element(NumberedListElement)
|
114
|
-
|
115
|
-
def with_toggles(self) -> Self:
|
116
|
-
return self._add_element(ToggleElement)
|
117
|
-
|
118
|
-
def with_quotes(self) -> Self:
|
119
|
-
return self._add_element(QuoteElement)
|
120
|
-
|
121
|
-
def with_todos(self) -> Self:
|
122
|
-
return self._add_element(TodoElement)
|
123
|
-
|
124
|
-
def with_bookmarks(self) -> Self:
|
125
|
-
return self._add_element(BookmarkElement)
|
126
|
-
|
127
|
-
def with_images(self) -> Self:
|
128
|
-
return self._add_element(ImageElement)
|
129
|
-
|
130
|
-
def with_videos(self) -> Self:
|
131
|
-
return self._add_element(VideoElement)
|
132
|
-
|
133
|
-
def with_embeds(self) -> Self:
|
134
|
-
return self._add_element(EmbedElement)
|
135
|
-
|
136
|
-
def with_audio(self) -> Self:
|
137
|
-
return self._add_element(AudioElement)
|
138
|
-
|
139
|
-
def with_toggleable_heading_element(self) -> Self:
|
140
|
-
return self._add_element(ToggleableHeadingElement)
|
141
|
-
|
142
|
-
def with_columns(self) -> Self:
|
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)
|
223
|
-
|
224
|
-
def build(self) -> BlockRegistry:
|
225
|
-
"""
|
226
|
-
Build and return the configured BlockRegistry instance.
|
227
|
-
"""
|
228
|
-
from notionary.blocks.registry.block_registry import BlockRegistry
|
229
|
-
|
230
|
-
# Ensure ParagraphElement is always present and at the end
|
231
|
-
self._ensure_paragraph_at_end()
|
232
|
-
|
233
|
-
registry = BlockRegistry()
|
234
|
-
|
235
|
-
# Add elements in the recorded order
|
236
|
-
for element_class in self._elements.values():
|
237
|
-
registry.register(element_class)
|
238
|
-
|
239
|
-
return registry
|
240
|
-
|
241
|
-
def _ensure_paragraph_at_end(self) -> None:
|
242
|
-
"""
|
243
|
-
Internal method to ensure ParagraphElement is the last element in the registry.
|
244
|
-
If ParagraphElement is not present, it will be added.
|
245
|
-
"""
|
246
|
-
# Remove if present, then always add at the end
|
247
|
-
self._elements.pop(ParagraphElement.__name__, None)
|
248
|
-
self._elements[ParagraphElement.__name__] = ParagraphElement
|
249
|
-
|
250
|
-
def _add_element(self, element_class: Type[BaseBlockElement]) -> Self:
|
251
|
-
"""
|
252
|
-
Add an element class to the registry configuration.
|
253
|
-
If the element already exists, it's moved to the end.
|
254
|
-
|
255
|
-
Args:
|
256
|
-
element_class: The element class to add
|
257
|
-
|
258
|
-
Returns:
|
259
|
-
Self for method chaining
|
260
|
-
"""
|
261
|
-
self._elements.pop(element_class.__name__, None)
|
262
|
-
self._elements[element_class.__name__] = element_class
|
263
|
-
|
264
|
-
return self
|
File without changes
|
@@ -1,228 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from typing import Literal, Optional, Union
|
4
|
-
|
5
|
-
from pydantic import BaseModel, Field
|
6
|
-
|
7
|
-
from notionary.blocks.bookmark.bookmark_markdown_node import BookmarkMarkdownBlockParams
|
8
|
-
from notionary.blocks.bulleted_list.bulleted_list_markdown_node import (
|
9
|
-
BulletedListMarkdownBlockParams,
|
10
|
-
)
|
11
|
-
from notionary.blocks.callout.callout_markdown_node import CalloutMarkdownBlockParams
|
12
|
-
from notionary.blocks.divider.divider_markdown_node import DividerMarkdownBlockParams
|
13
|
-
from notionary.blocks.embed.embed_markdown_node import EmbedMarkdownBlockParams
|
14
|
-
from notionary.blocks.equation.equation_element_markdown_node import (
|
15
|
-
EquationMarkdownBlockParams,
|
16
|
-
)
|
17
|
-
from notionary.blocks.file.file_element_markdown_node import FileMarkdownNodeParams
|
18
|
-
|
19
|
-
# Import all the existing params models
|
20
|
-
from notionary.blocks.heading.heading_markdown_node import HeadingMarkdownBlockParams
|
21
|
-
from notionary.blocks.image_block.image_markdown_node import ImageMarkdownBlockParams
|
22
|
-
from notionary.blocks.numbered_list.numbered_list_markdown_node import (
|
23
|
-
NumberedListMarkdownBlockParams,
|
24
|
-
)
|
25
|
-
from notionary.blocks.paragraph.paragraph_markdown_node import (
|
26
|
-
ParagraphMarkdownBlockParams,
|
27
|
-
)
|
28
|
-
from notionary.blocks.quote.quote_markdown_node import QuoteMarkdownBlockParams
|
29
|
-
from notionary.blocks.table.table_markdown_node import TableMarkdownBlockParams
|
30
|
-
from notionary.blocks.table_of_contents.table_of_contents_markdown_node import (
|
31
|
-
TableOfContentsMarkdownBlockParams,
|
32
|
-
)
|
33
|
-
from notionary.blocks.todo.todo_markdown_node import TodoMarkdownBlockParams
|
34
|
-
from notionary.blocks.video.video_markdown_node import VideoMarkdownBlockParams
|
35
|
-
|
36
|
-
|
37
|
-
class HeadingBlock(BaseModel):
|
38
|
-
type: Literal["heading"] = "heading"
|
39
|
-
params: HeadingMarkdownBlockParams
|
40
|
-
|
41
|
-
|
42
|
-
class ParagraphBlock(BaseModel):
|
43
|
-
type: Literal["paragraph"] = "paragraph"
|
44
|
-
params: ParagraphMarkdownBlockParams
|
45
|
-
|
46
|
-
|
47
|
-
class QuoteBlock(BaseModel):
|
48
|
-
type: Literal["quote"] = "quote"
|
49
|
-
params: QuoteMarkdownBlockParams
|
50
|
-
|
51
|
-
|
52
|
-
class BulletedListBlock(BaseModel):
|
53
|
-
type: Literal["bulleted_list"] = "bulleted_list"
|
54
|
-
params: BulletedListMarkdownBlockParams
|
55
|
-
|
56
|
-
|
57
|
-
class NumberedListBlock(BaseModel):
|
58
|
-
type: Literal["numbered_list"] = "numbered_list"
|
59
|
-
params: NumberedListMarkdownBlockParams
|
60
|
-
|
61
|
-
|
62
|
-
class TodoBlock(BaseModel):
|
63
|
-
type: Literal["todo"] = "todo"
|
64
|
-
params: TodoMarkdownBlockParams
|
65
|
-
|
66
|
-
|
67
|
-
class CalloutBlock(BaseModel):
|
68
|
-
type: Literal["callout"] = "callout"
|
69
|
-
params: CalloutMarkdownBlockParams
|
70
|
-
|
71
|
-
|
72
|
-
class CodeBlock(BaseModel):
|
73
|
-
type: Literal["code"] = "code"
|
74
|
-
params: CodeBlock
|
75
|
-
|
76
|
-
|
77
|
-
class ImageBlock(BaseModel):
|
78
|
-
type: Literal["image"] = "image"
|
79
|
-
params: ImageMarkdownBlockParams
|
80
|
-
|
81
|
-
|
82
|
-
class VideoBlock(BaseModel):
|
83
|
-
type: Literal["video"] = "video"
|
84
|
-
params: VideoMarkdownBlockParams
|
85
|
-
|
86
|
-
|
87
|
-
class AudioBlock(BaseModel):
|
88
|
-
type: Literal["audio"] = "audio"
|
89
|
-
params: FileMarkdownNodeParams
|
90
|
-
|
91
|
-
|
92
|
-
class FileBlock(BaseModel):
|
93
|
-
type: Literal["file"] = "file"
|
94
|
-
params: FileMarkdownNodeParams
|
95
|
-
|
96
|
-
|
97
|
-
class PdfBlock(BaseModel):
|
98
|
-
type: Literal["pdf"] = "pdf"
|
99
|
-
params: FileMarkdownNodeParams
|
100
|
-
|
101
|
-
|
102
|
-
class BookmarkBlock(BaseModel):
|
103
|
-
type: Literal["bookmark"] = "bookmark"
|
104
|
-
params: BookmarkMarkdownBlockParams
|
105
|
-
|
106
|
-
|
107
|
-
class EmbedBlock(BaseModel):
|
108
|
-
type: Literal["embed"] = "embed"
|
109
|
-
params: EmbedMarkdownBlockParams
|
110
|
-
|
111
|
-
|
112
|
-
class TableBlock(BaseModel):
|
113
|
-
type: Literal["table"] = "table"
|
114
|
-
params: TableMarkdownBlockParams
|
115
|
-
|
116
|
-
|
117
|
-
class DividerBlock(BaseModel):
|
118
|
-
type: Literal["divider"] = "divider"
|
119
|
-
params: DividerMarkdownBlockParams
|
120
|
-
|
121
|
-
|
122
|
-
class EquationBlock(BaseModel):
|
123
|
-
type: Literal["equation"] = "equation"
|
124
|
-
params: EquationMarkdownBlockParams
|
125
|
-
|
126
|
-
|
127
|
-
class TableOfContentsBlock(BaseModel):
|
128
|
-
type: Literal["table_of_contents"] = "table_of_contents"
|
129
|
-
params: TableOfContentsMarkdownBlockParams
|
130
|
-
|
131
|
-
|
132
|
-
# Special blocks for nested content
|
133
|
-
class ToggleBlockParams(BaseModel):
|
134
|
-
title: str
|
135
|
-
children: list[MarkdownBlock] = Field(default_factory=list)
|
136
|
-
|
137
|
-
|
138
|
-
class ToggleBlock(BaseModel):
|
139
|
-
type: Literal["toggle"] = "toggle"
|
140
|
-
params: ToggleBlockParams
|
141
|
-
|
142
|
-
|
143
|
-
class ToggleableHeadingBlockParams(BaseModel):
|
144
|
-
text: str
|
145
|
-
level: int = Field(ge=1, le=3)
|
146
|
-
children: list[MarkdownBlock] = Field(default_factory=list)
|
147
|
-
|
148
|
-
|
149
|
-
class ToggleableHeadingBlock(BaseModel):
|
150
|
-
type: Literal["toggleable_heading"] = "toggleable_heading"
|
151
|
-
params: ToggleableHeadingBlockParams
|
152
|
-
|
153
|
-
|
154
|
-
class ColumnBlockParams(BaseModel):
|
155
|
-
columns: list[list[MarkdownBlock]] = Field(default_factory=list)
|
156
|
-
width_ratios: Optional[list[float]] = None
|
157
|
-
|
158
|
-
|
159
|
-
class ColumnBlock(BaseModel):
|
160
|
-
type: Literal["columns"] = "columns"
|
161
|
-
params: ColumnBlockParams
|
162
|
-
|
163
|
-
|
164
|
-
# Union of all possible blocks
|
165
|
-
MarkdownBlock = Union[
|
166
|
-
HeadingBlock,
|
167
|
-
ParagraphBlock,
|
168
|
-
QuoteBlock,
|
169
|
-
BulletedListBlock,
|
170
|
-
NumberedListBlock,
|
171
|
-
TodoBlock,
|
172
|
-
CalloutBlock,
|
173
|
-
CodeBlock,
|
174
|
-
ImageBlock,
|
175
|
-
VideoBlock,
|
176
|
-
AudioBlock,
|
177
|
-
FileBlock,
|
178
|
-
PdfBlock,
|
179
|
-
BookmarkBlock,
|
180
|
-
EmbedBlock,
|
181
|
-
TableBlock,
|
182
|
-
DividerBlock,
|
183
|
-
EquationBlock,
|
184
|
-
TableOfContentsBlock,
|
185
|
-
ToggleBlock,
|
186
|
-
ToggleableHeadingBlock,
|
187
|
-
ColumnBlock,
|
188
|
-
]
|
189
|
-
|
190
|
-
|
191
|
-
# Update forward references
|
192
|
-
ToggleBlockParams.model_rebuild()
|
193
|
-
ToggleableHeadingBlockParams.model_rebuild()
|
194
|
-
ColumnBlockParams.model_rebuild()
|
195
|
-
|
196
|
-
|
197
|
-
class MarkdownDocumentModel(BaseModel):
|
198
|
-
"""
|
199
|
-
Complete document model for generating Markdown via MarkdownBuilder.
|
200
|
-
Perfect for LLM structured output!
|
201
|
-
|
202
|
-
Example:
|
203
|
-
{
|
204
|
-
"blocks": [
|
205
|
-
{
|
206
|
-
"type": "heading",
|
207
|
-
"params": {"text": "My Document", "level": 1}
|
208
|
-
},
|
209
|
-
{
|
210
|
-
"type": "paragraph",
|
211
|
-
"params": {"text": "Introduction text"}
|
212
|
-
},
|
213
|
-
{
|
214
|
-
"type": "pdf",
|
215
|
-
"params": {"url": "https://example.com/doc.pdf", "caption": "Important PDF"}
|
216
|
-
}
|
217
|
-
]
|
218
|
-
}
|
219
|
-
"""
|
220
|
-
|
221
|
-
blocks: list[MarkdownBlock] = Field(default_factory=list)
|
222
|
-
|
223
|
-
def to_markdown(self) -> str:
|
224
|
-
"""Convert the model directly to markdown string."""
|
225
|
-
from notionary.markdown.markdown_builder import MarkdownBuilder
|
226
|
-
|
227
|
-
builder = MarkdownBuilder.from_model(self)
|
228
|
-
return builder.build()
|
@@ -1,30 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from abc import ABC, abstractmethod
|
4
|
-
|
5
|
-
|
6
|
-
class MarkdownNode(ABC):
|
7
|
-
"""
|
8
|
-
Abstract base class for all Markdown block elements.
|
9
|
-
Enforces implementation of to_markdown().
|
10
|
-
"""
|
11
|
-
|
12
|
-
@abstractmethod
|
13
|
-
def to_markdown(self) -> str:
|
14
|
-
"""
|
15
|
-
Returns the Markdown representation of the block.
|
16
|
-
Must be implemented by subclasses.
|
17
|
-
"""
|
18
|
-
pass
|
19
|
-
|
20
|
-
@classmethod
|
21
|
-
@abstractmethod
|
22
|
-
def from_params(cls, params) -> MarkdownNode:
|
23
|
-
"""
|
24
|
-
Creates an instance from a params object.
|
25
|
-
Must be implemented by subclasses.
|
26
|
-
"""
|
27
|
-
pass
|
28
|
-
|
29
|
-
def __str__(self):
|
30
|
-
return self.to_markdown()
|
File without changes
|
@@ -1,73 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Post-processor for handling block formatting in Markdown to Notion conversion.
|
3
|
-
|
4
|
-
Handles block formatting tasks like adding empty paragraphs before media blocks
|
5
|
-
and other formatting-related post-processing.
|
6
|
-
"""
|
7
|
-
|
8
|
-
from typing import cast
|
9
|
-
|
10
|
-
from notionary.blocks.models import BlockCreateRequest
|
11
|
-
from notionary.blocks.types import BlockType
|
12
|
-
from notionary.blocks.paragraph.paragraph_models import (
|
13
|
-
CreateParagraphBlock,
|
14
|
-
ParagraphBlock,
|
15
|
-
)
|
16
|
-
|
17
|
-
|
18
|
-
class MarkdownToNotionFormattingPostProcessor:
|
19
|
-
"""Handles block formatting post-processing for Notion blocks."""
|
20
|
-
|
21
|
-
BLOCKS_NEEDING_EMPTY_PARAGRAPH: set[BlockType] = {
|
22
|
-
BlockType.DIVIDER,
|
23
|
-
BlockType.FILE,
|
24
|
-
BlockType.IMAGE,
|
25
|
-
BlockType.PDF,
|
26
|
-
BlockType.VIDEO,
|
27
|
-
}
|
28
|
-
|
29
|
-
def process(self, blocks: list[BlockCreateRequest]) -> list[BlockCreateRequest]:
|
30
|
-
"""Process blocks with all formatting steps."""
|
31
|
-
if not blocks:
|
32
|
-
return blocks
|
33
|
-
|
34
|
-
return self._add_empty_paragraphs_for_media_blocks(blocks)
|
35
|
-
|
36
|
-
def _add_empty_paragraphs_for_media_blocks(
|
37
|
-
self, blocks: list[BlockCreateRequest]
|
38
|
-
) -> list[BlockCreateRequest]:
|
39
|
-
"""Add empty paragraphs before configured block types."""
|
40
|
-
if not blocks:
|
41
|
-
return blocks
|
42
|
-
|
43
|
-
result: list[BlockCreateRequest] = []
|
44
|
-
|
45
|
-
for i, block in enumerate(blocks):
|
46
|
-
block_type = block.type
|
47
|
-
|
48
|
-
if (
|
49
|
-
block_type in self.BLOCKS_NEEDING_EMPTY_PARAGRAPH
|
50
|
-
and i > 0
|
51
|
-
and not self._is_empty_paragraph(result[-1] if result else None)
|
52
|
-
):
|
53
|
-
|
54
|
-
# Create empty paragraph block inline
|
55
|
-
empty_paragraph = CreateParagraphBlock(
|
56
|
-
paragraph=ParagraphBlock(rich_text=[])
|
57
|
-
)
|
58
|
-
result.append(empty_paragraph)
|
59
|
-
|
60
|
-
result.append(block)
|
61
|
-
|
62
|
-
return result
|
63
|
-
|
64
|
-
def _is_empty_paragraph(self, block: BlockCreateRequest | None) -> bool:
|
65
|
-
if not block or block.type != BlockType.PARAGRAPH:
|
66
|
-
return False
|
67
|
-
if not isinstance(block, CreateParagraphBlock):
|
68
|
-
return False
|
69
|
-
|
70
|
-
para_block = cast(CreateParagraphBlock, block)
|
71
|
-
paragraph: ParagraphBlock | None = para_block.paragraph
|
72
|
-
if not paragraph:
|
73
|
-
return False
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|