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.
Files changed (105) hide show
  1. notionary/__init__.py +1 -1
  2. notionary/blocks/__init__.py +3 -1
  3. notionary/blocks/audio/__init__.py +0 -2
  4. notionary/blocks/audio/audio_element.py +92 -49
  5. notionary/blocks/audio/audio_markdown_node.py +4 -17
  6. notionary/blocks/bookmark/__init__.py +0 -2
  7. notionary/blocks/bookmark/bookmark_markdown_node.py +5 -21
  8. notionary/blocks/breadcrumbs/__init__.py +0 -2
  9. notionary/blocks/breadcrumbs/breadcrumb_markdown_node.py +2 -21
  10. notionary/blocks/bulleted_list/__init__.py +0 -2
  11. notionary/blocks/bulleted_list/bulleted_list_markdown_node.py +3 -17
  12. notionary/blocks/bulleted_list/bulleted_list_models.py +0 -1
  13. notionary/blocks/callout/__init__.py +0 -2
  14. notionary/blocks/callout/callout_markdown_node.py +4 -18
  15. notionary/blocks/callout/callout_models.py +3 -4
  16. notionary/blocks/child_database/child_database_element.py +2 -4
  17. notionary/blocks/code/code_markdown_node.py +5 -19
  18. notionary/blocks/column/__init__.py +0 -4
  19. notionary/blocks/column/column_list_markdown_node.py +3 -19
  20. notionary/blocks/column/column_markdown_node.py +4 -21
  21. notionary/blocks/divider/__init__.py +0 -2
  22. notionary/blocks/divider/divider_markdown_node.py +2 -16
  23. notionary/blocks/embed/__init__.py +0 -2
  24. notionary/blocks/embed/embed_markdown_node.py +4 -17
  25. notionary/blocks/equation/__init__.py +0 -1
  26. notionary/blocks/equation/equation_element_markdown_node.py +3 -15
  27. notionary/blocks/file/__init__.py +0 -2
  28. notionary/blocks/file/file_element.py +67 -46
  29. notionary/blocks/file/file_element_markdown_node.py +4 -17
  30. notionary/blocks/heading/__init__.py +0 -2
  31. notionary/blocks/heading/heading_markdown_node.py +5 -19
  32. notionary/blocks/heading/heading_models.py +3 -3
  33. notionary/blocks/image_block/__init__.py +0 -2
  34. notionary/blocks/image_block/image_element.py +66 -25
  35. notionary/blocks/image_block/image_markdown_node.py +5 -20
  36. notionary/{markdown → blocks/markdown}/markdown_builder.py +29 -233
  37. notionary/blocks/markdown/markdown_node.py +25 -0
  38. notionary/blocks/mixins/file_upload/__init__.py +3 -0
  39. notionary/blocks/mixins/file_upload/file_upload_mixin.py +320 -0
  40. notionary/blocks/numbered_list/__init__.py +0 -1
  41. notionary/blocks/numbered_list/numbered_list_markdown_node.py +3 -17
  42. notionary/blocks/numbered_list/numbered_list_models.py +3 -3
  43. notionary/blocks/paragraph/__init__.py +0 -2
  44. notionary/blocks/paragraph/paragraph_markdown_node.py +3 -13
  45. notionary/blocks/pdf/__init__.py +0 -2
  46. notionary/blocks/pdf/pdf_element.py +81 -32
  47. notionary/blocks/pdf/pdf_markdown_node.py +5 -18
  48. notionary/blocks/quote/__init__.py +0 -2
  49. notionary/blocks/quote/quote_markdown_node.py +3 -13
  50. notionary/blocks/registry/__init__.py +1 -2
  51. notionary/blocks/registry/block_registry.py +116 -61
  52. notionary/blocks/rich_text/text_inline_formatter.py +1 -1
  53. notionary/blocks/table/__init__.py +0 -2
  54. notionary/blocks/table/table_markdown_node.py +17 -16
  55. notionary/blocks/table_of_contents/__init__.py +0 -2
  56. notionary/blocks/table_of_contents/table_of_contents_element.py +27 -15
  57. notionary/blocks/table_of_contents/table_of_contents_markdown_node.py +3 -17
  58. notionary/blocks/table_of_contents/table_of_contents_models.py +2 -2
  59. notionary/blocks/todo/__init__.py +0 -2
  60. notionary/blocks/todo/todo_markdown_node.py +9 -20
  61. notionary/blocks/todo/todo_models.py +2 -3
  62. notionary/blocks/toggle/__init__.py +0 -2
  63. notionary/blocks/toggle/toggle_markdown_node.py +5 -19
  64. notionary/blocks/toggleable_heading/__init__.py +0 -2
  65. notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +6 -23
  66. notionary/blocks/video/__init__.py +0 -2
  67. notionary/blocks/video/video_element.py +110 -34
  68. notionary/blocks/video/video_markdown_node.py +4 -15
  69. notionary/comments/__init__.py +26 -0
  70. notionary/comments/client.py +211 -0
  71. notionary/comments/models.py +129 -0
  72. notionary/file_upload/client.py +3 -2
  73. notionary/file_upload/models.py +10 -1
  74. notionary/file_upload/notion_file_upload.py +5 -5
  75. notionary/page/client.py +1 -6
  76. notionary/page/markdown_whitespace_processor.py +129 -0
  77. notionary/page/notion_page.py +87 -48
  78. notionary/page/page_content_deleting_service.py +1 -1
  79. notionary/page/page_content_writer.py +32 -129
  80. notionary/page/page_context.py +0 -6
  81. notionary/page/reader/handler/column_list_renderer.py +2 -2
  82. notionary/page/reader/handler/column_renderer.py +2 -2
  83. notionary/page/reader/handler/line_renderer.py +2 -2
  84. notionary/page/reader/handler/toggle_renderer.py +2 -2
  85. notionary/page/reader/handler/toggleable_heading_renderer.py +2 -2
  86. notionary/page/writer/handler/toggle_handler.py +8 -4
  87. notionary/page/writer/handler/toggleable_heading_handler.py +3 -2
  88. notionary/page/writer/markdown_to_notion_converter.py +74 -30
  89. notionary/schemas/__init__.py +3 -0
  90. notionary/schemas/base.py +73 -0
  91. notionary/shared/__init__.py +3 -0
  92. notionary/{blocks/rich_text → shared}/name_to_id_resolver.py +0 -2
  93. {notionary-0.2.22.dist-info → notionary-0.2.24.dist-info}/METADATA +15 -2
  94. {notionary-0.2.22.dist-info → notionary-0.2.24.dist-info}/RECORD +97 -95
  95. notionary/blocks/guards.py +0 -22
  96. notionary/blocks/registry/block_registry_builder.py +0 -264
  97. notionary/markdown/makdown_document_model.py +0 -0
  98. notionary/markdown/markdown_document_model.py +0 -228
  99. notionary/markdown/markdown_node.py +0 -30
  100. notionary/models/notion_database_response.py +0 -0
  101. notionary/page/writer/markdown_to_notion_formatting_post_processor.py +0 -73
  102. notionary/page/writer/markdown_to_notion_post_processor.py +0 -0
  103. /notionary/{markdown/___init__.py → blocks/markdown/markdown_document_model.py} +0 -0
  104. {notionary-0.2.22.dist-info → notionary-0.2.24.dist-info}/LICENSE +0 -0
  105. {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