notionary 0.2.19__py3-none-any.whl → 0.2.21__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 +263 -0
- notionary/blocks/audio/__init__.py +8 -2
- notionary/blocks/audio/audio_element.py +42 -104
- notionary/blocks/audio/audio_markdown_node.py +3 -1
- notionary/blocks/audio/audio_models.py +6 -55
- notionary/blocks/base_block_element.py +30 -0
- notionary/blocks/bookmark/__init__.py +9 -2
- notionary/blocks/bookmark/bookmark_element.py +46 -139
- notionary/blocks/bookmark/bookmark_markdown_node.py +3 -1
- 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 +40 -55
- 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 +40 -89
- notionary/blocks/callout/callout_markdown_node.py +3 -1
- notionary/blocks/callout/callout_models.py +33 -0
- notionary/blocks/child_database/__init__.py +7 -0
- notionary/blocks/child_database/child_database_models.py +19 -0
- notionary/blocks/child_page/__init__.py +9 -0
- notionary/blocks/child_page/child_page_models.py +12 -0
- notionary/blocks/{shared/block_client.py → client.py} +55 -54
- notionary/blocks/code/__init__.py +6 -2
- notionary/blocks/code/code_element.py +53 -187
- notionary/blocks/code/code_markdown_node.py +13 -13
- notionary/blocks/code/code_models.py +94 -0
- notionary/blocks/column/__init__.py +25 -1
- notionary/blocks/column/column_element.py +40 -314
- notionary/blocks/column/column_list_element.py +37 -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 +26 -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 +47 -114
- 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 +80 -0
- notionary/blocks/equation/equation_element_markdown_node.py +36 -0
- notionary/blocks/equation/equation_models.py +11 -0
- notionary/blocks/file/__init__.py +25 -0
- notionary/blocks/file/file_element.py +93 -0
- notionary/blocks/file/file_element_markdown_node.py +35 -0
- notionary/blocks/file/file_element_models.py +39 -0
- notionary/blocks/heading/__init__.py +16 -2
- notionary/blocks/heading/heading_element.py +67 -72
- 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 +84 -0
- notionary/blocks/{image → image_block}/image_markdown_node.py +3 -1
- notionary/blocks/image_block/image_models.py +10 -0
- notionary/blocks/models.py +172 -0
- notionary/blocks/numbered_list/__init__.py +12 -2
- notionary/blocks/numbered_list/numbered_list_element.py +33 -58
- 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 +27 -69
- 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 +91 -0
- notionary/blocks/pdf/pdf_markdown_node.py +35 -0
- notionary/blocks/pdf/pdf_models.py +11 -0
- notionary/blocks/quote/__init__.py +11 -2
- notionary/blocks/quote/quote_element.py +31 -65
- notionary/blocks/quote/quote_markdown_node.py +4 -1
- notionary/blocks/quote/quote_models.py +18 -0
- notionary/blocks/registry/__init__.py +4 -0
- notionary/blocks/registry/block_registry.py +75 -91
- notionary/blocks/registry/block_registry_builder.py +107 -59
- notionary/blocks/rich_text/__init__.py +33 -0
- notionary/blocks/rich_text/rich_text_models.py +188 -0
- notionary/blocks/rich_text/text_inline_formatter.py +125 -0
- notionary/blocks/table/__init__.py +16 -2
- notionary/blocks/table/table_element.py +48 -241
- 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 +51 -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 +38 -95
- 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 +57 -264
- notionary/blocks/toggle/toggle_markdown_node.py +24 -14
- notionary/blocks/toggle/toggle_models.py +17 -0
- notionary/blocks/toggleable_heading/__init__.py +6 -2
- notionary/blocks/toggleable_heading/toggleable_heading_element.py +74 -244
- notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +26 -18
- notionary/blocks/types.py +61 -0
- notionary/blocks/video/__init__.py +8 -2
- notionary/blocks/video/video_element.py +67 -143
- notionary/blocks/video/video_element_models.py +10 -0
- notionary/blocks/video/video_markdown_node.py +3 -1
- notionary/database/client.py +3 -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 +2 -1
- notionary/file_upload/notion_file_upload.py +2 -3
- notionary/markdown/markdown_builder.py +722 -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 +9 -10
- notionary/page/models.py +327 -0
- notionary/page/notion_page.py +99 -52
- notionary/page/notion_text_length_utils.py +119 -0
- notionary/page/{content/page_content_writer.py → page_content_writer.py} +88 -38
- notionary/page/reader/handler/__init__.py +17 -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 +43 -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 +60 -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 +69 -0
- notionary/page/search_filter_builder.py +2 -1
- notionary/page/writer/handler/__init__.py +22 -0
- notionary/page/writer/handler/code_handler.py +100 -0
- notionary/page/writer/handler/column_handler.py +141 -0
- notionary/page/writer/handler/column_list_handler.py +139 -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 +92 -0
- notionary/page/writer/handler/table_handler.py +130 -0
- notionary/page/writer/handler/toggle_handler.py +153 -0
- notionary/page/writer/handler/toggleable_heading_handler.py +167 -0
- notionary/page/writer/markdown_to_notion_converter.py +76 -0
- notionary/telemetry/__init__.py +2 -2
- notionary/telemetry/service.py +4 -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 +3 -2
- notionary/user/notion_user_provider.py +1 -1
- 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 +3 -2
- {notionary-0.2.19.dist-info → notionary-0.2.21.dist-info}/METADATA +12 -8
- notionary-0.2.21.dist-info/RECORD +185 -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/__init__.py +0 -0
- 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/blocks/toggleable_heading/toggleable_heading_models.py +0 -0
- notionary/database/models/page_result.py +0 -10
- notionary/elements/__init__.py +0 -0
- 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/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-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/page/{content/markdown_whitespace_processor.py → markdown_whitespace_processor.py} +0 -0
- /notionary/{blocks/mention/mention_models.py → page/reader/handler/context.py} +0 -0
- {notionary-0.2.19.dist-info → notionary-0.2.21.dist-info}/LICENSE +0 -0
- {notionary-0.2.19.dist-info → notionary-0.2.21.dist-info}/WHEEL +0 -0
@@ -1,117 +1,74 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import re
|
4
|
+
from typing import Optional
|
2
5
|
|
3
|
-
from
|
4
|
-
from notionary.blocks import
|
5
|
-
from notionary.blocks import
|
6
|
-
|
7
|
-
ElementPromptBuilder,
|
8
|
-
NotionBlockResult,
|
9
|
-
)
|
10
|
-
from notionary.blocks.shared.models import RichTextObject
|
6
|
+
from notionary.blocks.base_block_element import BaseBlockElement
|
7
|
+
from notionary.blocks.code.code_models import CodeBlock, CodeLanguage, CreateCodeBlock
|
8
|
+
from notionary.blocks.models import Block, BlockCreateResult, BlockType
|
9
|
+
from notionary.blocks.rich_text.rich_text_models import RichTextObject
|
11
10
|
|
12
11
|
|
13
|
-
class CodeElement(
|
12
|
+
class CodeElement(BaseBlockElement):
|
14
13
|
"""
|
15
14
|
Handles conversion between Markdown code blocks and Notion code blocks.
|
15
|
+
Now integrated into the LineProcessor stack system.
|
16
16
|
|
17
17
|
Markdown code block syntax:
|
18
18
|
```language
|
19
|
-
code content
|
19
|
+
[code content as child lines]
|
20
20
|
```
|
21
|
-
Caption: optional caption text
|
22
|
-
|
23
|
-
Where:
|
24
|
-
- language is optional and specifies the programming language
|
25
|
-
- code content is the code to be displayed
|
26
|
-
- Caption line is optional and must appear immediately after the closing ```
|
27
21
|
"""
|
28
22
|
|
29
|
-
|
30
|
-
|
31
|
-
)
|
23
|
+
DEFAULT_LANGUAGE = "plain text"
|
24
|
+
CODE_START_PATTERN = re.compile(r"^```(\w*)\s*$")
|
32
25
|
|
33
26
|
@classmethod
|
34
|
-
def
|
35
|
-
"""Check if text contains a markdown code block."""
|
36
|
-
return bool(cls.PATTERN.search(text))
|
37
|
-
|
38
|
-
@classmethod
|
39
|
-
def match_notion(cls, block: dict[str, any]) -> bool:
|
27
|
+
def match_notion(cls, block: Block) -> bool:
|
40
28
|
"""Check if block is a Notion code block."""
|
41
|
-
return block.
|
29
|
+
return block.type == BlockType.CODE and block.code
|
42
30
|
|
43
31
|
@classmethod
|
44
|
-
def markdown_to_notion(cls, text: str) ->
|
45
|
-
"""Convert
|
46
|
-
match
|
47
|
-
if not match:
|
32
|
+
def markdown_to_notion(cls, text: str) -> BlockCreateResult:
|
33
|
+
"""Convert opening ```language to Notion code block."""
|
34
|
+
if not (match := cls.CODE_START_PATTERN.match(text.strip())):
|
48
35
|
return None
|
49
36
|
|
50
|
-
language = match.group(1) or
|
51
|
-
|
52
|
-
caption = match.group(3)
|
53
|
-
|
54
|
-
if content.endswith("\n"):
|
55
|
-
content = content[:-1]
|
37
|
+
language = (match.group(1) or cls.DEFAULT_LANGUAGE).lower()
|
38
|
+
language = cls._normalize_language(language)
|
56
39
|
|
57
|
-
# Create
|
58
|
-
|
59
|
-
|
60
|
-
block = {
|
61
|
-
"type": "code",
|
62
|
-
"code": {
|
63
|
-
"rich_text": [content_rich_text.model_dump()],
|
64
|
-
"language": language,
|
65
|
-
},
|
66
|
-
}
|
67
|
-
|
68
|
-
# Add caption if provided
|
69
|
-
if caption and caption.strip():
|
70
|
-
caption_rich_text = RichTextObject.from_plain_text(caption.strip())
|
71
|
-
block["code"]["caption"] = [caption_rich_text.model_dump()]
|
72
|
-
|
73
|
-
# Leerer Paragraph nach dem Code-Block
|
74
|
-
empty_paragraph = {"type": "paragraph", "paragraph": {"rich_text": []}}
|
75
|
-
|
76
|
-
return [block, empty_paragraph]
|
40
|
+
# Create empty CodeBlock - content will be added by stack processor
|
41
|
+
code_block = CodeBlock(rich_text=[], language=language, caption=[])
|
42
|
+
return CreateCodeBlock(code=code_block)
|
77
43
|
|
78
44
|
@classmethod
|
79
|
-
def notion_to_markdown(cls, block:
|
45
|
+
def notion_to_markdown(cls, block: Block) -> Optional[str]:
|
80
46
|
"""Convert Notion code block to Markdown."""
|
81
|
-
if block.
|
47
|
+
if block.type != BlockType.CODE:
|
48
|
+
return None
|
49
|
+
|
50
|
+
if not block.code:
|
82
51
|
return None
|
83
52
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
if text.get("type") == "text"
|
94
|
-
else text.get("plain_text", "")
|
95
|
-
for text in rich_text_list
|
96
|
-
)
|
97
|
-
|
98
|
-
def extract_caption(caption_list):
|
99
|
-
"""Extract caption text from caption array."""
|
100
|
-
return "".join(
|
101
|
-
c.get("text", {}).get("content", "")
|
102
|
-
for c in caption_list
|
103
|
-
if c.get("type") == "text"
|
104
|
-
)
|
105
|
-
|
106
|
-
code_content = extract_content(rich_text)
|
107
|
-
caption_text = extract_caption(caption)
|
53
|
+
language_enum = block.code.language
|
54
|
+
rich_text = block.code.rich_text or []
|
55
|
+
caption = block.code.caption or []
|
56
|
+
|
57
|
+
code_content = cls.extract_content(rich_text)
|
58
|
+
caption_text = cls.extract_caption(caption)
|
59
|
+
|
60
|
+
# Convert enum to string value
|
61
|
+
language = language_enum.value if language_enum else ""
|
108
62
|
|
109
63
|
# Handle language - convert "plain text" back to empty string for markdown
|
110
|
-
if language ==
|
64
|
+
if language == cls.DEFAULT_LANGUAGE:
|
111
65
|
language = ""
|
112
66
|
|
113
67
|
# Build markdown code block
|
114
|
-
|
68
|
+
if language:
|
69
|
+
result = f"```{language}\n{code_content}\n```"
|
70
|
+
else:
|
71
|
+
result = f"```\n{code_content}\n```"
|
115
72
|
|
116
73
|
# Add caption if present
|
117
74
|
if caption_text:
|
@@ -120,115 +77,24 @@ class CodeElement(NotionBlockElement):
|
|
120
77
|
return result
|
121
78
|
|
122
79
|
@classmethod
|
123
|
-
def
|
80
|
+
def _normalize_language(cls, language: str) -> CodeLanguage:
|
124
81
|
"""
|
125
|
-
|
126
|
-
|
127
|
-
Args:
|
128
|
-
text: The text to search in
|
129
|
-
|
130
|
-
Returns:
|
131
|
-
List of tuples with (start_pos, end_pos, block)
|
82
|
+
Normalize the language string to a valid CodeLanguage enum or default.
|
132
83
|
"""
|
133
|
-
|
134
|
-
for
|
135
|
-
|
136
|
-
|
137
|
-
caption = match.group(3)
|
138
|
-
|
139
|
-
# Remove trailing newline if present
|
140
|
-
if content.endswith("\n"):
|
141
|
-
content = content[:-1]
|
142
|
-
|
143
|
-
block = {
|
144
|
-
"type": "code",
|
145
|
-
"code": {
|
146
|
-
"rich_text": [
|
147
|
-
{
|
148
|
-
"type": "text",
|
149
|
-
"text": {"content": content},
|
150
|
-
"plain_text": content,
|
151
|
-
}
|
152
|
-
],
|
153
|
-
"language": language,
|
154
|
-
},
|
155
|
-
}
|
156
|
-
|
157
|
-
# Add caption if provided
|
158
|
-
if caption and caption.strip():
|
159
|
-
block["code"]["caption"] = [
|
160
|
-
{
|
161
|
-
"type": "text",
|
162
|
-
"text": {"content": caption.strip()},
|
163
|
-
"plain_text": caption.strip(),
|
164
|
-
}
|
165
|
-
]
|
166
|
-
|
167
|
-
matches.append((match.start(), match.end(), block))
|
168
|
-
|
169
|
-
return matches
|
84
|
+
# Try to find matching enum by value
|
85
|
+
for lang_enum in CodeLanguage:
|
86
|
+
if lang_enum.value.lower() == language.lower():
|
87
|
+
return lang_enum
|
170
88
|
|
171
|
-
|
172
|
-
|
173
|
-
return True
|
174
|
-
|
175
|
-
@classmethod
|
176
|
-
def get_llm_prompt_content(cls) -> ElementPromptContent:
|
177
|
-
"""
|
178
|
-
Returns structured LLM prompt metadata for the code block element.
|
179
|
-
"""
|
180
|
-
return (
|
181
|
-
ElementPromptBuilder()
|
182
|
-
.with_description(
|
183
|
-
"Use fenced code blocks to format content as code. Supports language annotations like "
|
184
|
-
"'python', 'json', or 'mermaid'. Useful for displaying code, configurations, command-line "
|
185
|
-
"examples, or diagram syntax. Also suitable for explaining or visualizing systems with diagram languages. "
|
186
|
-
"Code blocks can include optional captions for better documentation."
|
187
|
-
)
|
188
|
-
.with_usage_guidelines(
|
189
|
-
"Use code blocks when you want to present technical content like code snippets, terminal commands, "
|
190
|
-
"JSON structures, or system diagrams. Especially helpful when structure and formatting are essential. "
|
191
|
-
"Add captions to provide context, explanations, or titles for your code blocks."
|
192
|
-
)
|
193
|
-
.with_syntax(
|
194
|
-
"```language\ncode content\n```\nCaption: optional caption text\n\n"
|
195
|
-
"OR\n\n"
|
196
|
-
"```language\ncode content\n```"
|
197
|
-
)
|
198
|
-
.with_examples(
|
199
|
-
[
|
200
|
-
"```python\nprint('Hello, world!')\n```\nCaption: Basic Python greeting example",
|
201
|
-
'```json\n{"name": "Alice", "age": 30}\n```\nCaption: User data structure',
|
202
|
-
"```mermaid\nflowchart TD\n A --> B\n```\nCaption: Simple flow diagram",
|
203
|
-
'```bash\ngit commit -m "Initial commit"\n```',
|
204
|
-
]
|
205
|
-
)
|
206
|
-
.with_avoidance_guidelines(
|
207
|
-
"NEVER EVER wrap markdown content with ```markdown. Markdown should be written directly without code block formatting. "
|
208
|
-
"NEVER use ```markdown under any circumstances. "
|
209
|
-
"For Mermaid diagrams, use ONLY the default styling without colors, backgrounds, or custom styling attributes. "
|
210
|
-
"Keep Mermaid diagrams simple and minimal without any styling or color modifications. "
|
211
|
-
"Captions must appear immediately after the closing ``` on a new line starting with 'Caption:' - "
|
212
|
-
"no empty lines between the code block and the caption."
|
213
|
-
)
|
214
|
-
.build()
|
215
|
-
)
|
89
|
+
# Return default if not found
|
90
|
+
return CodeLanguage.PLAIN_TEXT
|
216
91
|
|
217
92
|
@staticmethod
|
218
|
-
def extract_content(rich_text_list: list[
|
93
|
+
def extract_content(rich_text_list: list[RichTextObject]) -> str:
|
219
94
|
"""Extract code content from rich_text array."""
|
220
|
-
return "".join(
|
221
|
-
text.get("text", {}).get("content", "")
|
222
|
-
if text.get("type") == "text"
|
223
|
-
else text.get("plain_text", "")
|
224
|
-
for text in rich_text_list
|
225
|
-
)
|
95
|
+
return "".join(rt.plain_text for rt in rich_text_list if rt.plain_text)
|
226
96
|
|
227
97
|
@staticmethod
|
228
|
-
def extract_caption(caption_list: list[
|
98
|
+
def extract_caption(caption_list: list[RichTextObject]) -> str:
|
229
99
|
"""Extract caption text from caption array."""
|
230
|
-
return "".join(
|
231
|
-
c.get("text", {}).get("content", "")
|
232
|
-
for c in caption_list
|
233
|
-
if c.get("type") == "text"
|
234
|
-
)
|
100
|
+
return "".join(rt.plain_text for rt in caption_list if rt.plain_text)
|
@@ -1,24 +1,18 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from typing import Optional
|
4
|
-
from pydantic import BaseModel
|
5
|
-
from notionary.blocks.markdown_node import MarkdownNode
|
6
4
|
|
7
|
-
|
8
|
-
|
9
|
-
code: str
|
10
|
-
language: Optional[str] = None
|
11
|
-
caption: Optional[str] = None
|
5
|
+
from notionary.blocks.code.code_models import CodeBlock
|
6
|
+
from notionary.markdown.markdown_node import MarkdownNode
|
12
7
|
|
13
8
|
|
14
9
|
class CodeMarkdownNode(MarkdownNode):
|
15
10
|
"""
|
16
11
|
Programmatic interface for creating Notion-style Markdown code blocks.
|
17
12
|
Example:
|
18
|
-
```python
|
13
|
+
```python "Basic usage"
|
19
14
|
print("Hello, world!")
|
20
15
|
```
|
21
|
-
Caption: Basic usage
|
22
16
|
"""
|
23
17
|
|
24
18
|
def __init__(
|
@@ -32,12 +26,18 @@ class CodeMarkdownNode(MarkdownNode):
|
|
32
26
|
self.caption = caption
|
33
27
|
|
34
28
|
@classmethod
|
35
|
-
def from_params(cls, params:
|
36
|
-
return cls(
|
29
|
+
def from_params(cls, params: CodeBlock) -> CodeMarkdownNode:
|
30
|
+
return cls(
|
31
|
+
code=params.rich_text, language=params.language, caption=params.caption
|
32
|
+
)
|
37
33
|
|
38
34
|
def to_markdown(self) -> str:
|
39
35
|
lang = self.language or ""
|
40
|
-
|
36
|
+
|
37
|
+
# Build the opening fence with optional caption
|
38
|
+
opening_fence = f"```{lang}"
|
41
39
|
if self.caption:
|
42
|
-
|
40
|
+
opening_fence += f' "{self.caption}"'
|
41
|
+
|
42
|
+
content = f"{opening_fence}\n{self.code}\n```"
|
43
43
|
return content
|
@@ -0,0 +1,94 @@
|
|
1
|
+
from enum import Enum
|
2
|
+
from typing import Literal
|
3
|
+
|
4
|
+
from pydantic import BaseModel, ConfigDict, Field
|
5
|
+
|
6
|
+
from notionary.blocks.rich_text.rich_text_models import RichTextObject
|
7
|
+
|
8
|
+
|
9
|
+
class CodeLanguage(str, Enum):
|
10
|
+
ABAP = "abap"
|
11
|
+
ARDUINO = "arduino"
|
12
|
+
BASH = "bash"
|
13
|
+
BASIC = "basic"
|
14
|
+
C = "c"
|
15
|
+
CLOJURE = "clojure"
|
16
|
+
COFFEESCRIPT = "coffeescript"
|
17
|
+
CPP = "c++"
|
18
|
+
CSHARP = "c#"
|
19
|
+
CSS = "css"
|
20
|
+
DART = "dart"
|
21
|
+
DIFF = "diff"
|
22
|
+
DOCKER = "docker"
|
23
|
+
ELIXIR = "elixir"
|
24
|
+
ELM = "elm"
|
25
|
+
ERLANG = "erlang"
|
26
|
+
FLOW = "flow"
|
27
|
+
FORTRAN = "fortran"
|
28
|
+
FSHARP = "f#"
|
29
|
+
GHERKIN = "gherkin"
|
30
|
+
GLSL = "glsl"
|
31
|
+
GO = "go"
|
32
|
+
GRAPHQL = "graphql"
|
33
|
+
GROOVY = "groovy"
|
34
|
+
HASKELL = "haskell"
|
35
|
+
HTML = "html"
|
36
|
+
JAVA = "java"
|
37
|
+
JAVASCRIPT = "javascript"
|
38
|
+
JSON = "json"
|
39
|
+
JULIA = "julia"
|
40
|
+
KOTLIN = "kotlin"
|
41
|
+
LATEX = "latex"
|
42
|
+
LESS = "less"
|
43
|
+
LISP = "lisp"
|
44
|
+
LIVESCRIPT = "livescript"
|
45
|
+
LUA = "lua"
|
46
|
+
MAKEFILE = "makefile"
|
47
|
+
MARKDOWN = "markdown"
|
48
|
+
MARKUP = "markup"
|
49
|
+
MATLAB = "matlab"
|
50
|
+
MERMAID = "mermaid"
|
51
|
+
NIX = "nix"
|
52
|
+
OBJECTIVE_C = "objective-c"
|
53
|
+
OCAML = "ocaml"
|
54
|
+
PASCAL = "pascal"
|
55
|
+
PERL = "perl"
|
56
|
+
PHP = "php"
|
57
|
+
PLAIN_TEXT = "plain text"
|
58
|
+
POWERSHELL = "powershell"
|
59
|
+
PROLOG = "prolog"
|
60
|
+
PROTOBUF = "protobuf"
|
61
|
+
PYTHON = "python"
|
62
|
+
R = "r"
|
63
|
+
REASON = "reason"
|
64
|
+
RUBY = "ruby"
|
65
|
+
RUST = "rust"
|
66
|
+
SASS = "sass"
|
67
|
+
SCALA = "scala"
|
68
|
+
SCHEME = "scheme"
|
69
|
+
SCSS = "scss"
|
70
|
+
SHELL = "shell"
|
71
|
+
SQL = "sql"
|
72
|
+
SWIFT = "swift"
|
73
|
+
TYPESCRIPT = "typescript"
|
74
|
+
VB_NET = "vb.net"
|
75
|
+
VERILOG = "verilog"
|
76
|
+
VHDL = "vhdl"
|
77
|
+
VISUAL_BASIC = "visual basic"
|
78
|
+
WEBASSEMBLY = "webassembly"
|
79
|
+
XML = "xml"
|
80
|
+
YAML = "yaml"
|
81
|
+
JAVA_C_CPP_CSHARP = "java/c/c++/c#"
|
82
|
+
|
83
|
+
|
84
|
+
class CodeBlock(BaseModel):
|
85
|
+
caption: list[RichTextObject] = Field(default_factory=list)
|
86
|
+
rich_text: list[RichTextObject]
|
87
|
+
language: CodeLanguage = CodeLanguage.PLAIN_TEXT
|
88
|
+
|
89
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
90
|
+
|
91
|
+
|
92
|
+
class CreateCodeBlock(BaseModel):
|
93
|
+
type: Literal["code"] = "code"
|
94
|
+
code: CodeBlock
|
@@ -1,5 +1,29 @@
|
|
1
|
-
from .column_element import ColumnElement
|
1
|
+
from notionary.blocks.column.column_element import ColumnElement
|
2
|
+
from notionary.blocks.column.column_list_element import ColumnListElement
|
3
|
+
from notionary.blocks.column.column_list_markdown_node import (
|
4
|
+
ColumnListMarkdownBlockParams,
|
5
|
+
ColumnListMarkdownNode,
|
6
|
+
)
|
7
|
+
from notionary.blocks.column.column_markdown_node import (
|
8
|
+
ColumnMarkdownBlockParams,
|
9
|
+
ColumnMarkdownNode,
|
10
|
+
)
|
11
|
+
from notionary.blocks.column.column_models import (
|
12
|
+
ColumnBlock,
|
13
|
+
ColumnListBlock,
|
14
|
+
CreateColumnBlock,
|
15
|
+
CreateColumnListBlock,
|
16
|
+
)
|
2
17
|
|
3
18
|
__all__ = [
|
4
19
|
"ColumnElement",
|
20
|
+
"ColumnListElement",
|
21
|
+
"ColumnBlock",
|
22
|
+
"CreateColumnBlock",
|
23
|
+
"ColumnListBlock",
|
24
|
+
"CreateColumnListBlock",
|
25
|
+
"ColumnMarkdownNode",
|
26
|
+
"ColumnMarkdownBlockParams",
|
27
|
+
"ColumnListMarkdownNode",
|
28
|
+
"ColumnListMarkdownBlockParams",
|
5
29
|
]
|