notionary 0.1.25__py3-none-any.whl → 0.1.27__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 (35) hide show
  1. notionary/elements/audio_element.py +41 -38
  2. notionary/elements/bookmark_element.py +36 -27
  3. notionary/elements/bulleted_list_element.py +28 -21
  4. notionary/elements/callout_element.py +39 -31
  5. notionary/elements/code_block_element.py +38 -26
  6. notionary/elements/divider_element.py +29 -18
  7. notionary/elements/embed_element.py +37 -28
  8. notionary/elements/heading_element.py +39 -24
  9. notionary/elements/image_element.py +33 -24
  10. notionary/elements/mention_element.py +40 -29
  11. notionary/elements/notion_block_element.py +13 -31
  12. notionary/elements/numbered_list_element.py +29 -20
  13. notionary/elements/paragraph_element.py +37 -31
  14. notionary/elements/prompts/element_prompt_content.py +91 -7
  15. notionary/elements/prompts/synthax_prompt_builder.py +63 -16
  16. notionary/elements/qoute_element.py +72 -74
  17. notionary/elements/registry/block_element_registry_builder.py +6 -9
  18. notionary/elements/table_element.py +49 -36
  19. notionary/elements/text_inline_formatter.py +23 -15
  20. notionary/elements/{todo_lists.py → todo_element.py} +34 -25
  21. notionary/elements/toggle_element.py +184 -108
  22. notionary/elements/toggleable_heading_element.py +269 -0
  23. notionary/elements/video_element.py +37 -28
  24. notionary/page/content/page_content_manager.py +3 -8
  25. notionary/page/markdown_to_notion_converter.py +269 -274
  26. notionary/page/metadata/notion_icon_manager.py +13 -7
  27. notionary/page/notion_page.py +3 -5
  28. notionary/page/notion_to_markdown_converter.py +20 -95
  29. {notionary-0.1.25.dist-info → notionary-0.1.27.dist-info}/METADATA +1 -1
  30. notionary-0.1.27.dist-info/RECORD +58 -0
  31. {notionary-0.1.25.dist-info → notionary-0.1.27.dist-info}/WHEEL +1 -1
  32. notionary/elements/column_element.py +0 -307
  33. notionary-0.1.25.dist-info/RECORD +0 -58
  34. {notionary-0.1.25.dist-info → notionary-0.1.27.dist-info}/licenses/LICENSE +0 -0
  35. {notionary-0.1.25.dist-info → notionary-0.1.27.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,10 @@
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
+ from notionary.elements.prompts.element_prompt_content import (
5
+ ElementPromptBuilder,
6
+ ElementPromptContent,
7
+ )
5
8
 
6
9
 
7
10
  class EmbedElement(NotionBlockElement):
@@ -20,19 +23,19 @@ class EmbedElement(NotionBlockElement):
20
23
  r"^<embed(?:\:(.*?))?>(?:\s*)" + r'\((https?://[^\s"]+)' + r"\)$"
21
24
  )
22
25
 
23
- @staticmethod
24
- def match_markdown(text: str) -> bool:
26
+ @classmethod
27
+ def match_markdown(cls, text: str) -> bool:
25
28
  """Check if text is a markdown embed."""
26
29
  text = text.strip()
27
30
  return text.startswith("<embed") and bool(EmbedElement.PATTERN.match(text))
28
31
 
29
- @staticmethod
30
- def match_notion(block: Dict[str, Any]) -> bool:
32
+ @classmethod
33
+ def match_notion(cls, block: Dict[str, Any]) -> bool:
31
34
  """Check if block is a Notion embed."""
32
35
  return block.get("type") == "embed"
33
36
 
34
- @staticmethod
35
- def markdown_to_notion(text: str) -> Optional[Dict[str, Any]]:
37
+ @classmethod
38
+ def markdown_to_notion(cls, text: str) -> Optional[Dict[str, Any]]:
36
39
  """Convert markdown embed to Notion embed block."""
37
40
  embed_match = EmbedElement.PATTERN.match(text.strip())
38
41
  if not embed_match:
@@ -58,8 +61,8 @@ class EmbedElement(NotionBlockElement):
58
61
 
59
62
  return embed_block
60
63
 
61
- @staticmethod
62
- def notion_to_markdown(block: Dict[str, Any]) -> Optional[str]:
64
+ @classmethod
65
+ def notion_to_markdown(cls, block: Dict[str, Any]) -> Optional[str]:
63
66
  """Convert Notion embed block to markdown embed."""
64
67
  if block.get("type") != "embed":
65
68
  return None
@@ -78,16 +81,16 @@ class EmbedElement(NotionBlockElement):
78
81
 
79
82
  if caption:
80
83
  return f"<embed:{caption}>({url})"
81
- else:
82
- return f"<embed>({url})"
83
84
 
84
- @staticmethod
85
- def is_multiline() -> bool:
85
+ return f"<embed>({url})"
86
+
87
+ @classmethod
88
+ def is_multiline(cls) -> bool:
86
89
  """Embeds are single-line elements."""
87
90
  return False
88
91
 
89
- @staticmethod
90
- def _extract_text_content(rich_text: List[Dict[str, Any]]) -> str:
92
+ @classmethod
93
+ def _extract_text_content(cls, rich_text: List[Dict[str, Any]]) -> str:
91
94
  """Extract plain text content from Notion rich_text elements."""
92
95
  result = ""
93
96
  for text_obj in rich_text:
@@ -102,18 +105,24 @@ class EmbedElement(NotionBlockElement):
102
105
  """
103
106
  Returns structured LLM prompt metadata for the embed element.
104
107
  """
105
- return {
106
- "description": "Embeds external content from websites, PDFs, Google Maps, and other sources directly in your document.",
107
- "when_to_use": (
108
+ return (
109
+ ElementPromptBuilder()
110
+ .with_description(
111
+ "Embeds external content from websites, PDFs, Google Maps, and other sources directly in your document."
112
+ )
113
+ .with_usage_guidelines(
108
114
  "Use embeds when you want to include external content that isn't just a video or image. "
109
115
  "Embeds are great for interactive content, reference materials, or live data sources."
110
- ),
111
- "syntax": "<embed:Caption>(https://example.com)",
112
- "examples": [
113
- "<embed:Course materials>(https://drive.google.com/file/d/123456/view)",
114
- "<embed:Our office location>(https://www.google.com/maps?q=San+Francisco)",
115
- "<embed:Latest announcement>(https://twitter.com/NotionHQ/status/1234567890)",
116
- "<embed:Project documentation>(https://github.com/username/repo)",
117
- "<embed>(https://example.com/important-reference.pdf)",
118
- ],
119
- }
116
+ )
117
+ .with_syntax("<embed:Caption>(https://example.com)")
118
+ .with_examples(
119
+ [
120
+ "<embed:Course materials>(https://drive.google.com/file/d/123456/view)",
121
+ "<embed:Our office location>(https://www.google.com/maps?q=San+Francisco)",
122
+ "<embed:Latest announcement>(https://twitter.com/NotionHQ/status/1234567890)",
123
+ "<embed:Project documentation>(https://github.com/username/repo)",
124
+ "<embed>(https://example.com/important-reference.pdf)",
125
+ ]
126
+ )
127
+ .build()
128
+ )
@@ -2,34 +2,40 @@ import re
2
2
  from typing import Dict, Any, Optional
3
3
 
4
4
  from notionary.elements.notion_block_element import NotionBlockElement
5
- from notionary.elements.prompts.element_prompt_content import ElementPromptContent
5
+ from notionary.elements.prompts.element_prompt_content import (
6
+ ElementPromptBuilder,
7
+ ElementPromptContent,
8
+ )
6
9
  from notionary.elements.text_inline_formatter import TextInlineFormatter
7
10
 
8
11
 
9
12
  class HeadingElement(NotionBlockElement):
10
13
  """Handles conversion between Markdown headings and Notion heading blocks."""
11
14
 
12
- PATTERN = re.compile(r"^(#{1,6})\s(.+)$")
15
+ PATTERN = re.compile(r"^(#{1,3})\s(.+)$")
13
16
 
14
- @staticmethod
15
- def match_markdown(text: str) -> bool:
17
+ @classmethod
18
+ def match_markdown(cls, text: str) -> bool:
16
19
  """Check if text is a markdown heading."""
17
20
  return bool(HeadingElement.PATTERN.match(text))
18
21
 
19
- @staticmethod
20
- def match_notion(block: Dict[str, Any]) -> bool:
22
+ @classmethod
23
+ def match_notion(cls, block: Dict[str, Any]) -> bool:
21
24
  """Check if block is a Notion heading."""
22
25
  block_type: str = block.get("type", "")
23
- return block_type.startswith("heading_") and block_type[-1] in "123456"
26
+ return block_type.startswith("heading_") and block_type[-1] in "123"
24
27
 
25
- @staticmethod
26
- def markdown_to_notion(text: str) -> Optional[Dict[str, Any]]:
28
+ @classmethod
29
+ def markdown_to_notion(cls, text: str) -> Optional[Dict[str, Any]]:
27
30
  """Convert markdown heading to Notion heading block."""
28
31
  header_match = HeadingElement.PATTERN.match(text)
29
32
  if not header_match:
30
33
  return None
31
34
 
32
35
  level = len(header_match.group(1))
36
+ if not 1 <= level <= 3:
37
+ return None
38
+
33
39
  content = header_match.group(2)
34
40
 
35
41
  return {
@@ -39,8 +45,8 @@ class HeadingElement(NotionBlockElement):
39
45
  },
40
46
  }
41
47
 
42
- @staticmethod
43
- def notion_to_markdown(block: Dict[str, Any]) -> Optional[str]:
48
+ @classmethod
49
+ def notion_to_markdown(cls, block: Dict[str, Any]) -> Optional[str]:
44
50
  """Convert Notion heading block to markdown heading."""
45
51
  block_type = block.get("type", "")
46
52
 
@@ -49,7 +55,8 @@ class HeadingElement(NotionBlockElement):
49
55
 
50
56
  try:
51
57
  level = int(block_type[-1])
52
- if not 1 <= level <= 6:
58
+ # Only allow levels 1-3
59
+ if not 1 <= level <= 3:
53
60
  return None
54
61
  except ValueError:
55
62
  return None
@@ -61,8 +68,8 @@ class HeadingElement(NotionBlockElement):
61
68
  prefix = "#" * level
62
69
  return f"{prefix} {text or ''}"
63
70
 
64
- @staticmethod
65
- def is_multiline() -> bool:
71
+ @classmethod
72
+ def is_multiline(cls) -> bool:
66
73
  return False
67
74
 
68
75
  @classmethod
@@ -70,13 +77,21 @@ class HeadingElement(NotionBlockElement):
70
77
  """
71
78
  Returns structured LLM prompt metadata for the heading element.
72
79
  """
73
- return {
74
- "description": "Use Markdown headings (#, ##, ###, etc.) to structure content hierarchically.",
75
- "when_to_use": "Use to group content into sections and define a visual hierarchy.",
76
- "syntax": "## Your Heading Text",
77
- "examples": [
78
- "# Main Title",
79
- "## Section Title",
80
- "### Subsection Title",
81
- ],
82
- }
80
+ return (
81
+ ElementPromptBuilder()
82
+ .with_description(
83
+ "Use Markdown headings (#, ##, ###) to structure content hierarchically."
84
+ )
85
+ .with_usage_guidelines(
86
+ "Use to group content into sections and define a visual hierarchy."
87
+ )
88
+ .with_syntax("## Your Heading Text")
89
+ .with_examples(
90
+ [
91
+ "# Main Title",
92
+ "## Section Title",
93
+ "### Subsection Title",
94
+ ]
95
+ )
96
+ .build()
97
+ )
@@ -1,7 +1,10 @@
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
+ from notionary.elements.prompts.element_prompt_content import (
5
+ ElementPromptBuilder,
6
+ ElementPromptContent,
7
+ )
5
8
 
6
9
 
7
10
  class ImageElement(NotionBlockElement):
@@ -22,20 +25,20 @@ class ImageElement(NotionBlockElement):
22
25
  + r"\)$" # closing parenthesis
23
26
  )
24
27
 
25
- @staticmethod
26
- def match_markdown(text: str) -> bool:
28
+ @classmethod
29
+ def match_markdown(cls, text: str) -> bool:
27
30
  """Check if text is a markdown image."""
28
31
  return text.strip().startswith("![") and bool(
29
32
  ImageElement.PATTERN.match(text.strip())
30
33
  )
31
34
 
32
- @staticmethod
33
- def match_notion(block: Dict[str, Any]) -> bool:
35
+ @classmethod
36
+ def match_notion(cls, block: Dict[str, Any]) -> bool:
34
37
  """Check if block is a Notion image."""
35
38
  return block.get("type") == "image"
36
39
 
37
- @staticmethod
38
- def markdown_to_notion(text: str) -> Optional[Dict[str, Any]]:
40
+ @classmethod
41
+ def markdown_to_notion(cls, text: str) -> Optional[Dict[str, Any]]:
39
42
  """Convert markdown image to Notion image block."""
40
43
  image_match = ImageElement.PATTERN.match(text.strip())
41
44
  if not image_match:
@@ -61,8 +64,8 @@ class ImageElement(NotionBlockElement):
61
64
 
62
65
  return image_block
63
66
 
64
- @staticmethod
65
- def notion_to_markdown(block: Dict[str, Any]) -> Optional[str]:
67
+ @classmethod
68
+ def notion_to_markdown(cls, block: Dict[str, Any]) -> Optional[str]:
66
69
  """Convert Notion image block to markdown image."""
67
70
  if block.get("type") != "image":
68
71
  return None
@@ -88,8 +91,8 @@ class ImageElement(NotionBlockElement):
88
91
 
89
92
  return f"![{caption}]({url})"
90
93
 
91
- @staticmethod
92
- def _extract_text_content(rich_text: List[Dict[str, Any]]) -> str:
94
+ @classmethod
95
+ def _extract_text_content(cls, rich_text: List[Dict[str, Any]]) -> str:
93
96
  """Extract plain text content from Notion rich_text elements."""
94
97
  result = ""
95
98
  for text_obj in rich_text:
@@ -99,8 +102,8 @@ class ImageElement(NotionBlockElement):
99
102
  result += text_obj.get("plain_text", "")
100
103
  return result
101
104
 
102
- @staticmethod
103
- def is_multiline() -> bool:
105
+ @classmethod
106
+ def is_multiline(cls) -> bool:
104
107
  return False
105
108
 
106
109
  @classmethod
@@ -108,17 +111,23 @@ class ImageElement(NotionBlockElement):
108
111
  """
109
112
  Returns structured LLM prompt metadata for the image element.
110
113
  """
111
- return {
112
- "description": "Embeds an image from an external URL into your document.",
113
- "when_to_use": (
114
+ return (
115
+ ElementPromptBuilder()
116
+ .with_description(
117
+ "Embeds an image from an external URL into your document."
118
+ )
119
+ .with_usage_guidelines(
114
120
  "Use images to include visual content such as diagrams, screenshots, charts, photos, or illustrations "
115
121
  "that enhance your document. Images can make complex information easier to understand, create visual interest, "
116
122
  "or provide evidence for your points."
117
- ),
118
- "syntax": "![Caption](https://example.com/image.jpg)",
119
- "examples": [
120
- "![Data visualization showing monthly trends](https://example.com/chart.png)",
121
- "![](https://example.com/screenshot.jpg)",
122
- '![Company logo](https://company.com/logo.png "Company Inc. logo")',
123
- ],
124
- }
123
+ )
124
+ .with_syntax("![Caption](https://example.com/image.jpg)")
125
+ .with_examples(
126
+ [
127
+ "![Data visualization showing monthly trends](https://example.com/chart.png)",
128
+ "![](https://example.com/screenshot.jpg)",
129
+ '![Company logo](https://company.com/logo.png "Company Inc. logo")',
130
+ ]
131
+ )
132
+ .build()
133
+ )
@@ -3,7 +3,10 @@ from typing import Dict, Any, Optional, List
3
3
  from typing_extensions import override
4
4
 
5
5
  from notionary.elements.notion_block_element import NotionBlockElement
6
- from notionary.elements.prompts.element_prompt_content import ElementPromptContent
6
+ from notionary.elements.prompts.element_prompt_content import (
7
+ ElementPromptBuilder,
8
+ ElementPromptContent,
9
+ )
7
10
 
8
11
 
9
12
  class MentionElement(NotionBlockElement):
@@ -46,16 +49,16 @@ class MentionElement(NotionBlockElement):
46
49
  },
47
50
  }
48
51
 
49
- @staticmethod
50
- def match_markdown(text: str) -> bool:
52
+ @classmethod
53
+ def match_markdown(cls, text: str) -> bool:
51
54
  """Check if text contains a markdown mention."""
52
55
  for mention_type in MentionElement.MENTION_TYPES.values():
53
56
  if re.search(mention_type["pattern"], text):
54
57
  return True
55
58
  return False
56
59
 
57
- @staticmethod
58
- def match_notion(block: Dict[str, Any]) -> bool:
60
+ @classmethod
61
+ def match_notion(cls, block: Dict[str, Any]) -> bool:
59
62
  """Check if block contains a mention."""
60
63
  supported_block_types = [
61
64
  "paragraph",
@@ -74,8 +77,8 @@ class MentionElement(NotionBlockElement):
74
77
 
75
78
  return any(text_item.get("type") == "mention" for text_item in rich_text)
76
79
 
77
- @staticmethod
78
- def markdown_to_notion(text: str) -> Optional[Dict[str, Any]]:
80
+ @classmethod
81
+ def markdown_to_notion(cls, text: str) -> Optional[Dict[str, Any]]:
79
82
  """Convert markdown text with mentions to a Notion paragraph block."""
80
83
  if not MentionElement.match_markdown(text):
81
84
  return None
@@ -87,8 +90,8 @@ class MentionElement(NotionBlockElement):
87
90
  "paragraph": {"rich_text": rich_text, "color": "default"},
88
91
  }
89
92
 
90
- @staticmethod
91
- def _process_markdown_with_mentions(text: str) -> List[Dict[str, Any]]:
93
+ @classmethod
94
+ def _process_markdown_with_mentions(cls, text: str) -> List[Dict[str, Any]]:
92
95
  """Convert markdown mentions to Notion rich_text format."""
93
96
  mentions = []
94
97
 
@@ -136,8 +139,8 @@ class MentionElement(NotionBlockElement):
136
139
 
137
140
  return rich_text
138
141
 
139
- @staticmethod
140
- def _create_text_item(content: str) -> Dict[str, Any]:
142
+ @classmethod
143
+ def _create_text_item(cls, content: str) -> Dict[str, Any]:
141
144
  """Create a text item with default annotations."""
142
145
  text_item = {
143
146
  "type": "text",
@@ -147,8 +150,8 @@ class MentionElement(NotionBlockElement):
147
150
  }
148
151
  return text_item
149
152
 
150
- @staticmethod
151
- def _default_annotations() -> Dict[str, Any]:
153
+ @classmethod
154
+ def _default_annotations(cls) -> Dict[str, Any]:
152
155
  """Return default annotations for rich text."""
153
156
  return {
154
157
  "bold": False,
@@ -159,8 +162,8 @@ class MentionElement(NotionBlockElement):
159
162
  "color": "default",
160
163
  }
161
164
 
162
- @staticmethod
163
- def notion_to_markdown(block: Dict[str, Any]) -> Optional[str]:
165
+ @classmethod
166
+ def notion_to_markdown(cls, block: Dict[str, Any]) -> Optional[str]:
164
167
  """Extract mentions from Notion block and convert to markdown format."""
165
168
  block_type = block.get("type")
166
169
  if not block_type or block_type not in block:
@@ -176,8 +179,8 @@ class MentionElement(NotionBlockElement):
176
179
 
177
180
  return None
178
181
 
179
- @staticmethod
180
- def _process_rich_text_with_mentions(rich_text: List[Dict[str, Any]]) -> str:
182
+ @classmethod
183
+ def _process_rich_text_with_mentions(cls, rich_text: List[Dict[str, Any]]) -> str:
181
184
  """Convert rich text with mentions to markdown string."""
182
185
  result = []
183
186
 
@@ -197,8 +200,8 @@ class MentionElement(NotionBlockElement):
197
200
 
198
201
  return "".join(result)
199
202
 
200
- @staticmethod
201
- def is_multiline() -> bool:
203
+ @classmethod
204
+ def is_multiline(cls) -> bool:
202
205
  return False
203
206
 
204
207
  @classmethod
@@ -206,13 +209,21 @@ class MentionElement(NotionBlockElement):
206
209
  """
207
210
  Returns structured LLM prompt metadata for the mention element.
208
211
  """
209
- return {
210
- "description": "References to Notion pages, databases, or dates within text content.",
211
- "when_to_use": "When you want to link to other Notion content within your text.",
212
- "syntax": "@[page-id]",
213
- "examples": [
214
- "Check the meeting notes at @[1a6389d5-7bd3-80c5-9a87-e90b034989d0]",
215
- "Deadline is @date[2023-12-31]",
216
- "Use the structure in @db[1a6389d5-7bd3-80e9-b199-000cfb3fa0b3]",
217
- ],
218
- }
212
+ return (
213
+ ElementPromptBuilder()
214
+ .with_description(
215
+ "References to Notion pages, databases, or dates within text content."
216
+ )
217
+ .with_usage_guidelines(
218
+ "When you want to link to other Notion content within your text."
219
+ )
220
+ .with_syntax("@[page-id]")
221
+ .with_examples(
222
+ [
223
+ "Check the meeting notes at @[1a6389d5-7bd3-80c5-9a87-e90b034989d0]",
224
+ "Deadline is @date[2023-12-31]",
225
+ "Use the structure in @db[1a6389d5-7bd3-80e9-b199-000cfb3fa0b3]",
226
+ ]
227
+ )
228
+ .build()
229
+ )
@@ -1,4 +1,3 @@
1
- import inspect
2
1
  from typing import Dict, Any, Optional
3
2
  from abc import ABC
4
3
 
@@ -8,45 +7,28 @@ from notionary.elements.prompts.element_prompt_content import ElementPromptConte
8
7
  class NotionBlockElement(ABC):
9
8
  """Base class for elements that can be converted between Markdown and Notion."""
10
9
 
11
- @staticmethod
12
- def markdown_to_notion(text: str) -> Optional[Dict[str, Any]]:
10
+ @classmethod
11
+ def markdown_to_notion(cls, text: str) -> Optional[Dict[str, Any]]:
13
12
  """Convert markdown to Notion block."""
14
13
 
15
- @staticmethod
16
- def notion_to_markdown(block: Dict[str, Any]) -> Optional[str]:
14
+ @classmethod
15
+ def notion_to_markdown(cls, block: Dict[str, Any]) -> Optional[str]:
17
16
  """Convert Notion block to markdown."""
18
17
 
19
- @staticmethod
20
- def match_markdown(text: str) -> bool:
18
+ @classmethod
19
+ def match_markdown(cls, text: str) -> bool:
21
20
  """Check if this element can handle the given markdown text."""
22
- return bool(NotionBlockElement.markdown_to_notion(text))
21
+ return bool(cls.markdown_to_notion(text)) # Now calls the class's version
23
22
 
24
- @staticmethod
25
- def match_notion(block: Dict[str, Any]) -> bool:
23
+ @classmethod
24
+ def match_notion(cls, block: Dict[str, Any]) -> bool:
26
25
  """Check if this element can handle the given Notion block."""
27
- return bool(NotionBlockElement.notion_to_markdown(block))
28
-
29
- @staticmethod
30
- def is_multiline() -> bool:
31
- return False
26
+ return bool(cls.notion_to_markdown(block)) # Now calls the class's version
32
27
 
33
28
  @classmethod
34
- def get_llm_documentation(cls) -> str:
35
- """
36
- Returns documentation specifically formatted for LLM system prompts.
37
- Can be overridden by subclasses to provide custom LLM-friendly documentation.
38
-
39
- By default, returns the class docstring.
40
- """
29
+ def is_multiline(cls) -> bool:
30
+ return False
41
31
 
42
32
  @classmethod
43
33
  def get_llm_prompt_content(cls) -> ElementPromptContent:
44
- """
45
- Returns a dictionary with information for LLM prompts about this element.
46
- This default implementation extracts information from the class docstring.
47
- Subclasses should override this method to provide more structured information.
48
-
49
- Returns:
50
- Dictionary with documentation information
51
- """
52
- return {"description": inspect.cleandoc(cls.__doc__ or ""), "examples": []}
34
+ """Returns a dictionary with information for LLM prompts about this element."""
@@ -1,15 +1,18 @@
1
1
  import re
2
2
  from typing import Dict, Any, Optional
3
3
  from notionary.elements.notion_block_element import NotionBlockElement
4
- from notionary.elements.prompts.element_prompt_content import ElementPromptContent
4
+ from notionary.elements.prompts.element_prompt_content import (
5
+ ElementPromptBuilder,
6
+ ElementPromptContent,
7
+ )
5
8
  from notionary.elements.text_inline_formatter import TextInlineFormatter
6
9
 
7
10
 
8
11
  class NumberedListElement(NotionBlockElement):
9
12
  """Class for converting between Markdown numbered lists and Notion numbered list items."""
10
13
 
11
- @staticmethod
12
- def markdown_to_notion(text: str) -> Optional[Dict[str, Any]]:
14
+ @classmethod
15
+ def markdown_to_notion(cls, text: str) -> Optional[Dict[str, Any]]:
13
16
  """Convert markdown numbered list item to Notion block."""
14
17
  pattern = re.compile(r"^\s*(\d+)\.\s+(.+)$")
15
18
  numbered_match = pattern.match(text)
@@ -26,8 +29,8 @@ class NumberedListElement(NotionBlockElement):
26
29
  "numbered_list_item": {"rich_text": rich_text, "color": "default"},
27
30
  }
28
31
 
29
- @staticmethod
30
- def notion_to_markdown(block: Dict[str, Any]) -> Optional[str]:
32
+ @classmethod
33
+ def notion_to_markdown(cls, block: Dict[str, Any]) -> Optional[str]:
31
34
  """Convert Notion numbered list item block to markdown."""
32
35
  if block.get("type") != "numbered_list_item":
33
36
  return None
@@ -37,19 +40,19 @@ class NumberedListElement(NotionBlockElement):
37
40
 
38
41
  return f"1. {content}"
39
42
 
40
- @staticmethod
41
- def match_markdown(text: str) -> bool:
43
+ @classmethod
44
+ def match_markdown(cls, text: str) -> bool:
42
45
  """Check if this element can handle the given markdown text."""
43
46
  pattern = re.compile(r"^\s*\d+\.\s+(.+)$")
44
47
  return bool(pattern.match(text))
45
48
 
46
- @staticmethod
47
- def match_notion(block: Dict[str, Any]) -> bool:
49
+ @classmethod
50
+ def match_notion(cls, block: Dict[str, Any]) -> bool:
48
51
  """Check if this element can handle the given Notion block."""
49
52
  return block.get("type") == "numbered_list_item"
50
53
 
51
- @staticmethod
52
- def is_multiline() -> bool:
54
+ @classmethod
55
+ def is_multiline(cls) -> bool:
53
56
  return False
54
57
 
55
58
  @classmethod
@@ -57,12 +60,18 @@ class NumberedListElement(NotionBlockElement):
57
60
  """
58
61
  Returns structured LLM prompt metadata for the numbered list element.
59
62
  """
60
- return {
61
- "description": "Creates numbered list items for ordered sequences.",
62
- "when_to_use": "Use for lists where order matters, such as steps, rankings, or sequential items.",
63
- "syntax": "1. Item text",
64
- "examples": [
65
- "1. First step\n2. Second step\n3. Third step",
66
- "1. Gather materials\n2. Assemble parts\n3. Test the result",
67
- ],
68
- }
63
+ return (
64
+ ElementPromptBuilder()
65
+ .with_description("Creates numbered list items for ordered sequences.")
66
+ .with_usage_guidelines(
67
+ "Use for lists where order matters, such as steps, rankings, or sequential items."
68
+ )
69
+ .with_syntax("1. Item text")
70
+ .with_examples(
71
+ [
72
+ "1. First step\n2. Second step\n3. Third step",
73
+ "1. Gather materials\n2. Assemble parts\n3. Test the result",
74
+ ]
75
+ )
76
+ .build()
77
+ )