notionary 0.1.19__py3-none-any.whl → 0.1.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 +2 -2
- notionary/database/notion_database.py +3 -1
- notionary/elements/audio_element.py +7 -11
- notionary/elements/bookmark_element.py +17 -29
- notionary/elements/bulleted_list_element.py +69 -0
- notionary/elements/callout_element.py +18 -80
- notionary/elements/code_block_element.py +15 -10
- notionary/elements/column_element.py +39 -26
- notionary/elements/divider_element.py +8 -25
- notionary/elements/embed_element.py +10 -18
- notionary/elements/heading_element.py +10 -12
- notionary/elements/image_element.py +9 -15
- notionary/elements/mention_element.py +6 -15
- notionary/elements/notion_block_element.py +12 -11
- notionary/elements/numbered_list_element.py +68 -0
- notionary/elements/paragraph_element.py +11 -7
- notionary/elements/prompts/element_prompt_content.py +20 -0
- notionary/elements/prompts/synthax_prompt_builder.py +92 -0
- notionary/elements/qoute_element.py +20 -89
- notionary/elements/registry/block_element_registry.py +90 -0
- notionary/elements/{block_element_registry_builder.py → registry/block_element_registry_builder.py} +15 -124
- notionary/elements/table_element.py +4 -16
- notionary/elements/text_inline_formatter.py +15 -78
- notionary/elements/todo_lists.py +14 -18
- notionary/elements/toggle_element.py +19 -1
- notionary/elements/video_element.py +10 -19
- notionary/notion_client.py +2 -2
- notionary/page/content/page_content_manager.py +2 -3
- notionary/page/markdown_to_notion_converter.py +3 -3
- notionary/page/notion_page.py +3 -3
- notionary/page/notion_to_markdown_converter.py +3 -3
- notionary/page/relations/notion_page_relation_manager.py +24 -24
- notionary/page/relations/notion_page_title_resolver.py +1 -2
- {notionary-0.1.19.dist-info → notionary-0.1.21.dist-info}/METADATA +3 -3
- notionary-0.1.21.dist-info/RECORD +58 -0
- {notionary-0.1.19.dist-info → notionary-0.1.21.dist-info}/WHEEL +1 -1
- notionary/elements/block_element_registry.py +0 -233
- notionary/elements/list_element.py +0 -130
- notionary/util/singleton_decorator.py +0 -20
- notionary-0.1.19.dist-info/RECORD +0 -56
- {notionary-0.1.19.dist-info → notionary-0.1.21.dist-info}/licenses/LICENSE +0 -0
- {notionary-0.1.19.dist-info → notionary-0.1.21.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,8 @@
|
|
1
1
|
from typing import Dict, Any, List, Tuple
|
2
2
|
import re
|
3
3
|
|
4
|
+
from notionary.elements.prompts.element_prompt_content import ElementPromptContent
|
5
|
+
|
4
6
|
|
5
7
|
class TextInlineFormatter:
|
6
8
|
"""
|
@@ -25,31 +27,6 @@ class TextInlineFormatter:
|
|
25
27
|
(r"~~(.+?)~~", {"strikethrough": True}),
|
26
28
|
(r"`(.+?)`", {"code": True}),
|
27
29
|
(r"\[(.+?)\]\((.+?)\)", {"link": True}),
|
28
|
-
(r"==([a-z_]+):(.+?)==", {"highlight": True}),
|
29
|
-
(r"==(.+?)==", {"highlight_default": True}),
|
30
|
-
]
|
31
|
-
|
32
|
-
# Valid colors for highlighting
|
33
|
-
VALID_COLORS = [
|
34
|
-
"default",
|
35
|
-
"gray",
|
36
|
-
"brown",
|
37
|
-
"orange",
|
38
|
-
"yellow",
|
39
|
-
"green",
|
40
|
-
"blue",
|
41
|
-
"purple",
|
42
|
-
"pink",
|
43
|
-
"red",
|
44
|
-
"gray_background",
|
45
|
-
"brown_background",
|
46
|
-
"orange_background",
|
47
|
-
"yellow_background",
|
48
|
-
"green_background",
|
49
|
-
"blue_background",
|
50
|
-
"purple_background",
|
51
|
-
"pink_background",
|
52
|
-
"red_background",
|
53
30
|
]
|
54
31
|
|
55
32
|
@classmethod
|
@@ -108,25 +85,6 @@ class TextInlineFormatter:
|
|
108
85
|
cls._create_text_element(remaining_text[:earliest_pos], {})
|
109
86
|
)
|
110
87
|
|
111
|
-
if "highlight" in earliest_format:
|
112
|
-
color = earliest_match.group(1)
|
113
|
-
content = earliest_match.group(2)
|
114
|
-
|
115
|
-
if color not in cls.VALID_COLORS:
|
116
|
-
if not color.endswith("_background"):
|
117
|
-
color = f"{color}_background"
|
118
|
-
|
119
|
-
if color not in cls.VALID_COLORS:
|
120
|
-
color = "yellow_background"
|
121
|
-
|
122
|
-
segments.append(cls._create_text_element(content, {"color": color}))
|
123
|
-
|
124
|
-
elif "highlight_default" in earliest_format:
|
125
|
-
content = earliest_match.group(1)
|
126
|
-
segments.append(
|
127
|
-
cls._create_text_element(content, {"color": "yellow_background"})
|
128
|
-
)
|
129
|
-
|
130
88
|
elif "link" in earliest_format:
|
131
89
|
content = earliest_match.group(1)
|
132
90
|
url = earliest_match.group(2)
|
@@ -224,10 +182,6 @@ class TextInlineFormatter:
|
|
224
182
|
if annotations.get("bold", False):
|
225
183
|
content = f"**{content}**"
|
226
184
|
|
227
|
-
color = annotations.get("color", "default")
|
228
|
-
if color != "default":
|
229
|
-
content = f"=={color.replace('_background', '')}:{content}=="
|
230
|
-
|
231
185
|
text_data = text_obj.get("text", {})
|
232
186
|
link_data = text_data.get("link")
|
233
187
|
if link_data:
|
@@ -256,39 +210,22 @@ class TextInlineFormatter:
|
|
256
210
|
}
|
257
211
|
|
258
212
|
@classmethod
|
259
|
-
def get_llm_prompt_content(cls) ->
|
213
|
+
def get_llm_prompt_content(cls) -> ElementPromptContent:
|
260
214
|
"""
|
261
|
-
Returns
|
262
|
-
|
263
|
-
This method provides documentation about supported inline formatting options
|
264
|
-
that can be used across all block elements.
|
265
|
-
|
266
|
-
Returns:
|
267
|
-
A dictionary with descriptions, syntax examples, and usage guidelines
|
215
|
+
Returns structured LLM prompt metadata for inline formatting.
|
268
216
|
"""
|
269
217
|
return {
|
270
|
-
"description": "
|
271
|
-
"
|
272
|
-
"
|
273
|
-
"
|
274
|
-
|
275
|
-
|
276
|
-
"`text` - Inline code",
|
277
|
-
"[text](url) - Link",
|
278
|
-
"==text== - Default highlight (yellow background)",
|
279
|
-
"==color:text== - Colored highlight (e.g., ==red:warning==)",
|
280
|
-
"<!-- spacer --> - Creates vertical spacing between elements",
|
281
|
-
],
|
218
|
+
"description": "Enables inline formatting like bold, italics, strikethrough, code, links, and underlining for enhanced readability and emphasis.",
|
219
|
+
"when_to_use": (
|
220
|
+
"Use inline formatting to highlight important words, provide emphasis, show code or paths, or add hyperlinks. "
|
221
|
+
"Helps create a visual hierarchy and improves scanability of long texts."
|
222
|
+
),
|
223
|
+
"syntax": "**bold**, *italic*, `code`, [text](url)",
|
282
224
|
"examples": [
|
283
|
-
"This is a **bold**
|
284
|
-
"
|
285
|
-
"
|
286
|
-
"
|
287
|
-
"
|
288
|
-
"==red:Warning:== This action cannot be undone.",
|
289
|
-
"==blue:Note:== Common colors include red, blue, green, yellow, purple.",
|
290
|
-
"First paragraph content.\n\n<!-- spacer -->\n\nSecond paragraph with additional spacing above.",
|
225
|
+
"This is a **bold** word.",
|
226
|
+
"Use *italics* for emphasis.",
|
227
|
+
"Mark outdated content like ~~this~~.",
|
228
|
+
"Write `config.json` to reference a file.",
|
229
|
+
"Visit [Notion](https://notion.so) for more info.",
|
291
230
|
],
|
292
|
-
"highlight_usage": "The highlight syntax (==text== and ==color:text==) should be used to emphasize important information, warnings, notes, or other content that needs to stand out. This is particularly useful for making content more scannable at a glance.",
|
293
|
-
"spacer_usage": "Use the <!-- spacer --> tag on its own line to create additional vertical spacing between elements. This is useful for improving readability by visually separating sections of content. Multiple spacer tags can be used for greater spacing.",
|
294
231
|
}
|
notionary/elements/todo_lists.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import re
|
2
2
|
from typing import Dict, Any, Optional
|
3
|
-
from typing_extensions import override
|
4
3
|
from notionary.elements.notion_block_element import NotionBlockElement
|
4
|
+
from notionary.elements.prompts.element_prompt_content import ElementPromptContent
|
5
5
|
from notionary.elements.text_inline_formatter import TextInlineFormatter
|
6
6
|
|
7
7
|
|
@@ -20,7 +20,6 @@ class TodoElement(NotionBlockElement):
|
|
20
20
|
TODO_PATTERN = re.compile(r"^\s*[-*+]\s+\[\s?\]\s+(.+)$")
|
21
21
|
DONE_PATTERN = re.compile(r"^\s*[-*+]\s+\[x\]\s+(.+)$")
|
22
22
|
|
23
|
-
@override
|
24
23
|
@staticmethod
|
25
24
|
def match_markdown(text: str) -> bool:
|
26
25
|
"""Check if text is a markdown todo item."""
|
@@ -28,13 +27,11 @@ class TodoElement(NotionBlockElement):
|
|
28
27
|
TodoElement.TODO_PATTERN.match(text) or TodoElement.DONE_PATTERN.match(text)
|
29
28
|
)
|
30
29
|
|
31
|
-
@override
|
32
30
|
@staticmethod
|
33
31
|
def match_notion(block: Dict[str, Any]) -> bool:
|
34
32
|
"""Check if block is a Notion to_do block."""
|
35
33
|
return block.get("type") == "to_do"
|
36
34
|
|
37
|
-
@override
|
38
35
|
@staticmethod
|
39
36
|
def markdown_to_notion(text: str) -> Optional[Dict[str, Any]]:
|
40
37
|
"""Convert markdown todo item to Notion to_do block."""
|
@@ -50,7 +47,6 @@ class TodoElement(NotionBlockElement):
|
|
50
47
|
|
51
48
|
return None
|
52
49
|
|
53
|
-
@override
|
54
50
|
@staticmethod
|
55
51
|
def notion_to_markdown(block: Dict[str, Any]) -> Optional[str]:
|
56
52
|
"""Convert Notion to_do block to markdown todo item."""
|
@@ -89,26 +85,26 @@ class TodoElement(NotionBlockElement):
|
|
89
85
|
},
|
90
86
|
}
|
91
87
|
|
92
|
-
@override
|
93
88
|
@staticmethod
|
94
89
|
def is_multiline() -> bool:
|
95
90
|
return False
|
96
91
|
|
97
92
|
@classmethod
|
98
|
-
def get_llm_prompt_content(cls) ->
|
99
|
-
"""
|
93
|
+
def get_llm_prompt_content(cls) -> ElementPromptContent:
|
94
|
+
"""
|
95
|
+
Returns structured LLM prompt metadata for the todo element.
|
96
|
+
"""
|
100
97
|
return {
|
101
98
|
"description": "Creates interactive to-do items with checkboxes that can be marked as complete.",
|
102
|
-
"when_to_use":
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
"x in brackets [x] indicates checked status",
|
108
|
-
"To-do items support inline formatting like **bold** and *italic*",
|
109
|
-
],
|
99
|
+
"when_to_use": (
|
100
|
+
"Use to-do items for task lists, checklists, or tracking progress on items that need to be completed. "
|
101
|
+
"Todo items are interactive in Notion and can be checked/unchecked directly."
|
102
|
+
),
|
103
|
+
"syntax": "- [ ] Task to complete",
|
110
104
|
"examples": [
|
111
|
-
"- [ ] Draft project proposal
|
112
|
-
"
|
105
|
+
"- [ ] Draft project proposal",
|
106
|
+
"- [x] Create initial timeline",
|
107
|
+
"* [ ] Review code changes",
|
108
|
+
"+ [x] Finalize handoff checklist",
|
113
109
|
],
|
114
110
|
}
|
@@ -2,6 +2,7 @@ import re
|
|
2
2
|
from typing import Dict, Any, Optional, List, Tuple, Callable
|
3
3
|
|
4
4
|
from notionary.elements.notion_block_element import NotionBlockElement
|
5
|
+
from notionary.elements.prompts.element_prompt_content import ElementPromptContent
|
5
6
|
|
6
7
|
|
7
8
|
class ToggleElement(NotionBlockElement):
|
@@ -12,7 +13,6 @@ class ToggleElement(NotionBlockElement):
|
|
12
13
|
TOGGLE_PATTERN = re.compile(r"^[+]{3}\s+(.+)$")
|
13
14
|
INDENT_PATTERN = re.compile(r"^(\s{2,}|\t+)(.+)$")
|
14
15
|
|
15
|
-
# Ein neues Pattern, um spezifisch nach der "Transcript" Überschrift zu suchen
|
16
16
|
TRANSCRIPT_TOGGLE_PATTERN = re.compile(r"^[+]{3}\s+Transcript$")
|
17
17
|
|
18
18
|
@staticmethod
|
@@ -206,3 +206,21 @@ class ToggleElement(NotionBlockElement):
|
|
206
206
|
i = next_index
|
207
207
|
|
208
208
|
return toggle_blocks
|
209
|
+
|
210
|
+
@classmethod
|
211
|
+
def get_llm_prompt_content(cls) -> ElementPromptContent:
|
212
|
+
"""
|
213
|
+
Returns structured LLM prompt metadata for the toggle element.
|
214
|
+
"""
|
215
|
+
return {
|
216
|
+
"description": "Toggle elements are collapsible sections that help organize and hide detailed information.",
|
217
|
+
"when_to_use": (
|
218
|
+
"Use toggles for supplementary information that's not essential for the first reading, "
|
219
|
+
"such as details, examples, or technical information."
|
220
|
+
),
|
221
|
+
"syntax": "+++ Toggle Title",
|
222
|
+
"examples": [
|
223
|
+
"+++ Key Findings\n The research demonstrates **three main conclusions**:\n 1. First important point\n 2. Second important point",
|
224
|
+
"+++ FAQ\n **Q: When should I use toggles?**\n *A: Use toggles for supplementary information.*",
|
225
|
+
],
|
226
|
+
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import re
|
2
2
|
from typing import Dict, Any, Optional, List
|
3
3
|
from notionary.elements.notion_block_element import NotionBlockElement
|
4
|
+
from notionary.elements.prompts.element_prompt_content import ElementPromptContent
|
4
5
|
|
5
6
|
|
6
7
|
class VideoElement(NotionBlockElement):
|
@@ -16,14 +17,12 @@ class VideoElement(NotionBlockElement):
|
|
16
17
|
Supports various video URLs including YouTube, Vimeo, and direct video file links.
|
17
18
|
"""
|
18
19
|
|
19
|
-
# Regex pattern for video syntax
|
20
20
|
PATTERN = re.compile(
|
21
21
|
r"^\@\[(.*?)\]" # @[Caption] part
|
22
22
|
+ r'\((https?://[^\s"]+)' # (URL part
|
23
23
|
+ r"\)$" # closing parenthesis
|
24
24
|
)
|
25
25
|
|
26
|
-
# YouTube specific patterns
|
27
26
|
YOUTUBE_PATTERNS = [
|
28
27
|
re.compile(
|
29
28
|
r"(?:https?://)?(?:www\.)?youtube\.com/watch\?v=([a-zA-Z0-9_-]{11})"
|
@@ -73,18 +72,15 @@ class VideoElement(NotionBlockElement):
|
|
73
72
|
if not url:
|
74
73
|
return None
|
75
74
|
|
76
|
-
# For YouTube videos, ensure we use the full embed URL
|
77
75
|
youtube_id = VideoElement.get_youtube_id(url)
|
78
76
|
if youtube_id:
|
79
77
|
url = f"https://www.youtube.com/watch?v={youtube_id}"
|
80
78
|
|
81
|
-
# Prepare the video block
|
82
79
|
video_block = {
|
83
80
|
"type": "video",
|
84
81
|
"video": {"type": "external", "external": {"url": url}},
|
85
82
|
}
|
86
83
|
|
87
|
-
# Add caption if provided
|
88
84
|
if caption:
|
89
85
|
video_block["video"]["caption"] = [
|
90
86
|
{"type": "text", "text": {"content": caption}}
|
@@ -111,7 +107,6 @@ class VideoElement(NotionBlockElement):
|
|
111
107
|
if not url:
|
112
108
|
return None
|
113
109
|
|
114
|
-
# Extract caption if available
|
115
110
|
caption = ""
|
116
111
|
caption_rich_text = video_data.get("caption", [])
|
117
112
|
if caption_rich_text:
|
@@ -136,21 +131,17 @@ class VideoElement(NotionBlockElement):
|
|
136
131
|
return result
|
137
132
|
|
138
133
|
@classmethod
|
139
|
-
def get_llm_prompt_content(cls) ->
|
140
|
-
"""
|
134
|
+
def get_llm_prompt_content(cls) -> ElementPromptContent:
|
135
|
+
"""
|
136
|
+
Returns structured LLM prompt metadata for the video element.
|
137
|
+
"""
|
141
138
|
return {
|
142
139
|
"description": "Embeds video content from external sources like YouTube or direct video URLs.",
|
143
|
-
"when_to_use":
|
144
|
-
|
145
|
-
"
|
146
|
-
|
147
|
-
],
|
148
|
-
"supported_sources": [
|
149
|
-
"YouTube videos (https://youtube.com/watch?v=ID or https://youtu.be/ID)",
|
150
|
-
"Vimeo videos",
|
151
|
-
"Direct links to video files (.mp4, .mov, etc.)",
|
152
|
-
"Other video hosting platforms supported by Notion",
|
153
|
-
],
|
140
|
+
"when_to_use": (
|
141
|
+
"Use video embeds when you want to include multimedia content directly in your document. "
|
142
|
+
"Videos are useful for tutorials, demonstrations, presentations, or any content that benefits from visual explanation."
|
143
|
+
),
|
144
|
+
"syntax": "@[Caption](https://example.com/video.mp4)",
|
154
145
|
"examples": [
|
155
146
|
"@[How to use this feature](https://www.youtube.com/watch?v=dQw4w9WgXcQ)",
|
156
147
|
"@[Product demo](https://example.com/videos/demo.mp4)",
|
notionary/notion_client.py
CHANGED
@@ -46,7 +46,7 @@ class NotionClient(LoggingMixin):
|
|
46
46
|
for instance in list(cls._instances):
|
47
47
|
await instance.close()
|
48
48
|
|
49
|
-
async def close(self)
|
49
|
+
async def close(self): #
|
50
50
|
"""
|
51
51
|
Closes the HTTP client for this instance and releases resources.
|
52
52
|
"""
|
@@ -77,7 +77,7 @@ class NotionClient(LoggingMixin):
|
|
77
77
|
A dictionary with the page data, or None if the request failed.
|
78
78
|
"""
|
79
79
|
return await self.get(f"pages/{page_id}")
|
80
|
-
|
80
|
+
|
81
81
|
async def post(
|
82
82
|
self, endpoint: str, data: Optional[Dict[str, Any]] = None
|
83
83
|
) -> Optional[Dict[str, Any]]:
|
@@ -1,7 +1,6 @@
|
|
1
|
-
import json
|
2
1
|
from typing import Any, Dict, List, Optional
|
3
2
|
|
4
|
-
from notionary.elements.block_element_registry import BlockElementRegistry
|
3
|
+
from notionary.elements.registry.block_element_registry import BlockElementRegistry
|
5
4
|
from notionary.notion_client import NotionClient
|
6
5
|
|
7
6
|
from notionary.page.markdown_to_notion_converter import (
|
@@ -39,7 +38,7 @@ class PageContentManager(LoggingMixin):
|
|
39
38
|
"""
|
40
39
|
try:
|
41
40
|
blocks = self._markdown_to_notion_converter.convert(markdown_text)
|
42
|
-
|
41
|
+
|
43
42
|
fixed_blocks = self._chunker.fix_blocks_content_length(blocks)
|
44
43
|
|
45
44
|
result = await self._client.patch(
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from typing import Dict, Any, List, Optional, Tuple
|
2
2
|
|
3
|
-
from notionary.elements.block_element_registry import BlockElementRegistry
|
4
|
-
from notionary.elements.block_element_registry_builder import (
|
3
|
+
from notionary.elements.registry.block_element_registry import BlockElementRegistry
|
4
|
+
from notionary.elements.registry.block_element_registry_builder import (
|
5
5
|
BlockElementRegistryBuilder,
|
6
6
|
)
|
7
7
|
|
@@ -21,7 +21,7 @@ class MarkdownToNotionConverter:
|
|
21
21
|
block_registry: Optional registry of Notion block elements
|
22
22
|
"""
|
23
23
|
self._block_registry = (
|
24
|
-
block_registry or BlockElementRegistryBuilder().
|
24
|
+
block_registry or BlockElementRegistryBuilder().create_full_registry()
|
25
25
|
)
|
26
26
|
|
27
27
|
self._setup_element_callbacks()
|
notionary/page/notion_page.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
import re
|
2
2
|
from typing import Any, Dict, List, Optional, Union
|
3
3
|
|
4
|
-
from notionary.elements.block_element_registry import BlockElementRegistry
|
5
|
-
from notionary.elements.block_element_registry_builder import (
|
4
|
+
from notionary.elements.registry.block_element_registry import BlockElementRegistry
|
5
|
+
from notionary.elements.registry.block_element_registry_builder import (
|
6
6
|
BlockElementRegistryBuilder,
|
7
7
|
)
|
8
8
|
from notionary.notion_client import NotionClient
|
@@ -45,7 +45,7 @@ class NotionPage(LoggingMixin):
|
|
45
45
|
self._url_loaded = url is not None
|
46
46
|
|
47
47
|
self._block_element_registry = (
|
48
|
-
BlockElementRegistryBuilder.
|
48
|
+
BlockElementRegistryBuilder.create_full_registry()
|
49
49
|
)
|
50
50
|
|
51
51
|
self._page_content_manager = PageContentManager(
|
@@ -1,9 +1,9 @@
|
|
1
1
|
from typing import Dict, Any, List, Optional
|
2
2
|
|
3
|
-
from notionary.elements.block_element_registry import (
|
3
|
+
from notionary.elements.registry.block_element_registry import (
|
4
4
|
BlockElementRegistry,
|
5
5
|
)
|
6
|
-
from notionary.elements.block_element_registry_builder import (
|
6
|
+
from notionary.elements.registry.block_element_registry_builder import (
|
7
7
|
BlockElementRegistryBuilder,
|
8
8
|
)
|
9
9
|
|
@@ -19,7 +19,7 @@ class NotionToMarkdownConverter:
|
|
19
19
|
block_registry: Optional registry of Notion block elements
|
20
20
|
"""
|
21
21
|
self._block_registry = (
|
22
|
-
block_registry or BlockElementRegistryBuilder().
|
22
|
+
block_registry or BlockElementRegistryBuilder().create_full_registry()
|
23
23
|
)
|
24
24
|
|
25
25
|
def convert(self, blocks: List[Dict[str, Any]]) -> str:
|
@@ -88,40 +88,40 @@ class NotionRelationManager(LoggingMixin):
|
|
88
88
|
]
|
89
89
|
|
90
90
|
async def get_relation_values(self, property_name: str) -> List[str]:
|
91
|
-
|
92
|
-
|
91
|
+
"""
|
92
|
+
Returns the titles of the pages linked via a relation property.
|
93
93
|
|
94
|
-
|
95
|
-
|
94
|
+
Args:
|
95
|
+
property_name: Name of the relation property
|
96
96
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
97
|
+
Returns:
|
98
|
+
List[str]: List of linked page titles
|
99
|
+
"""
|
100
|
+
properties = await self._get_page_properties()
|
101
101
|
|
102
|
-
|
103
|
-
|
102
|
+
if property_name not in properties:
|
103
|
+
return []
|
104
104
|
|
105
|
-
|
105
|
+
prop_data = properties[property_name]
|
106
106
|
|
107
|
-
|
108
|
-
|
107
|
+
if prop_data.get("type") != "relation" or "relation" not in prop_data:
|
108
|
+
return []
|
109
109
|
|
110
|
-
|
111
|
-
|
110
|
+
resolver = NotionPageTitleResolver(self._client)
|
111
|
+
titles = []
|
112
112
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
113
|
+
for rel in prop_data["relation"]:
|
114
|
+
page_id = rel.get("id")
|
115
|
+
if not page_id:
|
116
|
+
continue
|
117
117
|
|
118
|
-
|
119
|
-
|
120
|
-
|
118
|
+
title = await resolver.get_title_by_page_id(page_id)
|
119
|
+
if not title:
|
120
|
+
continue
|
121
121
|
|
122
|
-
|
122
|
+
titles.append(title)
|
123
123
|
|
124
|
-
|
124
|
+
return titles
|
125
125
|
|
126
126
|
async def get_relation_details(
|
127
127
|
self, property_name: str
|
@@ -52,7 +52,6 @@ class NotionPageTitleResolver(LoggingMixin):
|
|
52
52
|
self.logger.error("Error while searching for page '%s': %s", title, e)
|
53
53
|
return None
|
54
54
|
|
55
|
-
|
56
55
|
async def get_title_by_page_id(self, page_id: str) -> Optional[str]:
|
57
56
|
"""
|
58
57
|
Retrieves the title of a Notion page by its page ID.
|
@@ -84,4 +83,4 @@ class NotionPageTitleResolver(LoggingMixin):
|
|
84
83
|
|
85
84
|
except Exception as e:
|
86
85
|
self.logger.error("Error retrieving title for page ID '%s': %s", page_id, e)
|
87
|
-
return None
|
86
|
+
return None
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: notionary
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.21
|
4
4
|
Summary: A toolkit to convert between Markdown and Notion blocks
|
5
5
|
Home-page: https://github.com/mathisarends/notionary
|
6
6
|
Author: Mathis Arends
|
@@ -189,7 +189,7 @@ from notionary import NotionPage
|
|
189
189
|
from notionary.elements.block_element_registry_builder import BlockElementRegistryBuilder
|
190
190
|
|
191
191
|
# Create a registry with standard Notion elements
|
192
|
-
registry = BlockElementRegistryBuilder.
|
192
|
+
registry = BlockElementRegistryBuilder.create_full_registry()
|
193
193
|
|
194
194
|
# Or build a custom registry with only the elements you need
|
195
195
|
custom_registry = (
|
@@ -220,7 +220,7 @@ Notionary can automatically generate comprehensive system prompts for LLMs to un
|
|
220
220
|
```python
|
221
221
|
from notionary.elements.block_element_registry_builder import BlockElementRegistryBuilder
|
222
222
|
|
223
|
-
registry = BlockElementRegistryBuilder.
|
223
|
+
registry = BlockElementRegistryBuilder.create_full_registry()
|
224
224
|
llm_system_prompt = registry.generate_llm_prompt()
|
225
225
|
|
226
226
|
# Use this prompt with your LLM to generate Notion-compatible Markdown
|
@@ -0,0 +1,58 @@
|
|
1
|
+
notionary/__init__.py,sha256=ypCkbF1YEcwy5aE2kGFmtJOZq41Vs01lahJNqRO27fU,735
|
2
|
+
notionary/notion_client.py,sha256=9oYhjY-OhFzACP-gHczDx1sif-YzmjFKX3CmluJBeIw,6038
|
3
|
+
notionary/database/database_discovery.py,sha256=qDGFhXG9s-_6CXdRg8tMiwX4dvX7jLjgAUFPSNlYtlI,4506
|
4
|
+
notionary/database/database_info_service.py,sha256=Ig6gx8jUSPYORJvfgEV5kV6t72pZQsWU8HPMqd43B-o,1336
|
5
|
+
notionary/database/notion_database.py,sha256=YCOuzrWfKRJvMiWdVfEt8i3NAEqpKDwHj5SX4GUraEk,8017
|
6
|
+
notionary/database/notion_database_factory.py,sha256=Af57yaUHidD8TKJ8uyXOc2nnqHm7on6VGFdDRjxiq9o,6692
|
7
|
+
notionary/database/models/page_result.py,sha256=Vmm5_oYpYAkIIJVoTd1ZZGloeC3cmFLMYP255mAmtaw,233
|
8
|
+
notionary/elements/audio_element.py,sha256=KuPA30Ii0Bv0WcAOOze_XBB98W0kMZSSWZ3Anij9w3Q,5336
|
9
|
+
notionary/elements/bookmark_element.py,sha256=hnDpAQsNfN1nUORuxfsEyg6Tustck1wcfynNumlLSFI,7931
|
10
|
+
notionary/elements/bulleted_list_element.py,sha256=-0_CeCfjHOkgYmK6m8Jl6uQasp8HepwSojCJKh5NhPo,2721
|
11
|
+
notionary/elements/callout_element.py,sha256=GA5vIhepgy7tuf4o18LWroVwuVEP08Hc-8zuKHBQKGs,4037
|
12
|
+
notionary/elements/code_block_element.py,sha256=A7XTTPVCTd-djdgtY89qYG67RcLNeC3554qKegO4l3g,5573
|
13
|
+
notionary/elements/column_element.py,sha256=v2O5lgewFeA9YE99XqhPxp6ujtHW1LfMKclPDERqbeU,10794
|
14
|
+
notionary/elements/divider_element.py,sha256=FUYc2rn7cSyHbuOlQdECJWVfMYcyY5BPDaSCyXkIESs,1988
|
15
|
+
notionary/elements/embed_element.py,sha256=i4DaDk-xvCxIV-D-OwcEy1lng_eac8U1jDfKOyMVSnY,4382
|
16
|
+
notionary/elements/heading_element.py,sha256=nedfFC9txOGWMB91tWz15YJXvUo7O3aNyUcm0GUgWKE,2855
|
17
|
+
notionary/elements/image_element.py,sha256=xopVKFY80uAQ0oXJ0m8zVnzi8YqNUaIjIgLCpTGQ1Ng,4552
|
18
|
+
notionary/elements/mention_element.py,sha256=1E1VyP5N28wd1V-n1KIbMp1ohZ8pIxtBL4bnIQtsPSU,7977
|
19
|
+
notionary/elements/notion_block_element.py,sha256=7IUgssQQwJQjZccCEX2IiJkFWAPWAYTDxYtCvNPUGqo,1886
|
20
|
+
notionary/elements/numbered_list_element.py,sha256=H8SPEEaOE4QBNRg3cm-sEQv8dcQ5I4hmXZR-MFvxxZ0,2658
|
21
|
+
notionary/elements/paragraph_element.py,sha256=AFBlybX9OZZs9S76sla9vwM1Te1Dq_yhjd0ZXJFF0KY,2839
|
22
|
+
notionary/elements/qoute_element.py,sha256=HO10Yvfnf5N332g1wVfeL4FHU1sffM5LbLgB-2sY9RM,6108
|
23
|
+
notionary/elements/table_element.py,sha256=z3vHXUH-KGB_iTF6FIwggkDe0w_gtC9sfKbocJWGDXM,10953
|
24
|
+
notionary/elements/text_inline_formatter.py,sha256=wvUdbDPoiVXcSZEMWy_1RAN2UcwwAueaeu7-jWHLhBk,7659
|
25
|
+
notionary/elements/todo_lists.py,sha256=gyktOvG1tSQvta_SjDauowfP__woJ9ySUHzwMwlN7Cg,3914
|
26
|
+
notionary/elements/toggle_element.py,sha256=UZvvOeVlayMCoXi5bvYTreMq9-3W4TrP6Gs2uUJ8qsE,8149
|
27
|
+
notionary/elements/video_element.py,sha256=37KzUkbUrxXgIxbhrq0iDAR_Mr-q7b4FlLTn7IonoKg,5513
|
28
|
+
notionary/elements/prompts/element_prompt_content.py,sha256=DL60MqTLKSaSIT0AoByArw-L__glCkSf9y08oSpTLaE,666
|
29
|
+
notionary/elements/prompts/synthax_prompt_builder.py,sha256=PBK4s9KhfzqsJN6KtRkk9re1sHGpxjFBx7-ueid-Q2s,3707
|
30
|
+
notionary/elements/registry/block_element_registry.py,sha256=8SXhrDsuxg60W9NcLzb33nhq3rYY4E0OuHoMVPMlu0E,3325
|
31
|
+
notionary/elements/registry/block_element_registry_builder.py,sha256=N5SqUqSxDoNDxg4iOwCu9KsfTYj_KD0832oNpwS-pSw,9042
|
32
|
+
notionary/exceptions/database_exceptions.py,sha256=I-Tx6bYRLpi5pjGPtbT-Mqxvz3BFgYTiuZxknJeLxtI,2638
|
33
|
+
notionary/exceptions/page_creation_exception.py,sha256=4v7IuZD6GsQLrqhDLriGjuG3ML638gAO53zDCrLePuU,281
|
34
|
+
notionary/page/markdown_to_notion_converter.py,sha256=AY-b-qjqs4Xc1j1I9GwijXdOAPYpgvbHF9NRuUXgHVg,15081
|
35
|
+
notionary/page/notion_page.py,sha256=pJSy-vWFqQdCqmtFifL9AdUZpWoM0DzfblRBBBUTsTI,17649
|
36
|
+
notionary/page/notion_page_factory.py,sha256=UUEZ-cyEWL0OMVPrgjc4vJdcplEa1bO2yHCYooACYC8,8189
|
37
|
+
notionary/page/notion_to_markdown_converter.py,sha256=qZIeZjDpeGFgW5RGTrcfi0mVI6NT0VvXeHM7jpP6ZHo,8067
|
38
|
+
notionary/page/content/notion_page_content_chunker.py,sha256=xRks74Dqec-De6-AVTxMPnXs-MSJBzSm1HfJfaHiKr8,3330
|
39
|
+
notionary/page/content/page_content_manager.py,sha256=gOynb6VTPsczD_HnjogUwslWYra0u1BEC5L-iMKIML4,6126
|
40
|
+
notionary/page/metadata/metadata_editor.py,sha256=61uiw8oB25O8ePhytoJvZDetuof5sjPoM6aoHZGo4wc,4949
|
41
|
+
notionary/page/metadata/notion_icon_manager.py,sha256=ixZrWsHGVpmF05Ncy9LCt8vZlKAQHYFZW-2yI5JZZDI,1426
|
42
|
+
notionary/page/metadata/notion_page_cover_manager.py,sha256=qgQxQE-bx4oWjLFUQvpXD5GzO1Mx7w7htz1xC2BOqUg,1717
|
43
|
+
notionary/page/properites/database_property_service.py,sha256=AJuBGahbb53VQa6IGGHxBMoOgCy6vFZg08uR_eDjNUs,11570
|
44
|
+
notionary/page/properites/page_property_manager.py,sha256=Xl8Cwn8WVszqpFXT_NvASkmP5igpCTEgRVhG_F45424,6914
|
45
|
+
notionary/page/properites/property_formatter.py,sha256=d_Nr5XQxgjB6VIS0u3ey14MOUKY416o_BvdXjbkUNAQ,3667
|
46
|
+
notionary/page/properites/property_operation_result.py,sha256=PhxHJJxxG2BdDl7aswhWnMSmf9RQtoinKkRHDoqxwCs,3913
|
47
|
+
notionary/page/properites/property_value_extractor.py,sha256=1BfyCYrFzfIUmNTozavrLTjG--6P6Dy2tkewf6rHHwQ,2353
|
48
|
+
notionary/page/relations/notion_page_relation_manager.py,sha256=ooN-WxXNPBE_vkNJgbc1wH8iIWBlKa9FHgiMeJjbYdw,13032
|
49
|
+
notionary/page/relations/notion_page_title_resolver.py,sha256=XQpa5XY4hoh5UYqpewTYaaftNX52WHyk2XmM4r8B2uY,3016
|
50
|
+
notionary/page/relations/page_database_relation.py,sha256=F9aGXFjjL8ZLNbfTGeGm_QAyXhz2AEOw7GgDLdprEcE,2313
|
51
|
+
notionary/page/relations/relation_operation_result.py,sha256=NDxBzGntOxc_89ti-HG8xDSqfY6PwyGHKHrrKbCzNjM,5010
|
52
|
+
notionary/util/logging_mixin.py,sha256=fKsx9t90bwvL74ZX3dU-sXdC4TZCQyO6qU9I8txkw_U,1369
|
53
|
+
notionary/util/page_id_utils.py,sha256=EYNMxgf-7ghzL5K8lKZBZfW7g5CsdY0Xuj4IYmU8RPk,1381
|
54
|
+
notionary-0.1.21.dist-info/licenses/LICENSE,sha256=zOm3cRT1qD49eg7vgw95MI79rpUAZa1kRBFwL2FkAr8,1120
|
55
|
+
notionary-0.1.21.dist-info/METADATA,sha256=M7rUxxRbiAwAfAaNorGjJuSMbnkqahMTSYa_gLOkd5A,8342
|
56
|
+
notionary-0.1.21.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
|
57
|
+
notionary-0.1.21.dist-info/top_level.txt,sha256=fhONa6BMHQXqthx5PanWGbPL0b8rdFqhrJKVLf_adSs,10
|
58
|
+
notionary-0.1.21.dist-info/RECORD,,
|