notionary 0.2.17__py3-none-any.whl → 0.2.19__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 (113) hide show
  1. notionary/__init__.py +3 -2
  2. notionary/blocks/__init__.py +54 -25
  3. notionary/blocks/audio/__init__.py +7 -0
  4. notionary/blocks/audio/audio_element.py +152 -0
  5. notionary/blocks/audio/audio_markdown_node.py +29 -0
  6. notionary/blocks/audio/audio_models.py +59 -0
  7. notionary/blocks/bookmark/__init__.py +7 -0
  8. notionary/blocks/{bookmark_element.py → bookmark/bookmark_element.py} +20 -65
  9. notionary/blocks/bookmark/bookmark_markdown_node.py +43 -0
  10. notionary/blocks/bookmark/bookmark_models.py +0 -0
  11. notionary/blocks/bulleted_list/__init__.py +7 -0
  12. notionary/blocks/{bulleted_list_element.py → bulleted_list/bulleted_list_element.py} +7 -3
  13. notionary/blocks/bulleted_list/bulleted_list_markdown_node.py +33 -0
  14. notionary/blocks/bulleted_list/bulleted_list_models.py +0 -0
  15. notionary/blocks/callout/__init__.py +7 -0
  16. notionary/blocks/callout/callout_element.py +132 -0
  17. notionary/blocks/callout/callout_markdown_node.py +31 -0
  18. notionary/blocks/callout/callout_models.py +0 -0
  19. notionary/blocks/code/__init__.py +7 -0
  20. notionary/blocks/{code_block_element.py → code/code_element.py} +72 -40
  21. notionary/blocks/code/code_markdown_node.py +43 -0
  22. notionary/blocks/code/code_models.py +0 -0
  23. notionary/blocks/column/__init__.py +5 -0
  24. notionary/blocks/{column_element.py → column/column_element.py} +24 -55
  25. notionary/blocks/column/column_models.py +0 -0
  26. notionary/blocks/divider/__init__.py +7 -0
  27. notionary/blocks/{divider_element.py → divider/divider_element.py} +11 -3
  28. notionary/blocks/divider/divider_markdown_node.py +24 -0
  29. notionary/blocks/divider/divider_models.py +0 -0
  30. notionary/blocks/document/__init__.py +7 -0
  31. notionary/blocks/document/document_element.py +102 -0
  32. notionary/blocks/document/document_markdown_node.py +31 -0
  33. notionary/blocks/document/document_models.py +0 -0
  34. notionary/blocks/embed/__init__.py +7 -0
  35. notionary/blocks/{embed_element.py → embed/embed_element.py} +50 -32
  36. notionary/blocks/embed/embed_markdown_node.py +30 -0
  37. notionary/blocks/embed/embed_models.py +0 -0
  38. notionary/blocks/heading/__init__.py +7 -0
  39. notionary/blocks/{heading_element.py → heading/heading_element.py} +25 -17
  40. notionary/blocks/heading/heading_markdown_node.py +29 -0
  41. notionary/blocks/heading/heading_models.py +0 -0
  42. notionary/blocks/image/__init__.py +7 -0
  43. notionary/blocks/{image_element.py → image/image_element.py} +62 -42
  44. notionary/blocks/image/image_markdown_node.py +33 -0
  45. notionary/blocks/image/image_models.py +0 -0
  46. notionary/blocks/markdown_builder.py +356 -0
  47. notionary/blocks/markdown_node.py +29 -0
  48. notionary/blocks/mention/__init__.py +7 -0
  49. notionary/blocks/{mention_element.py → mention/mention_element.py} +6 -2
  50. notionary/blocks/mention/mention_markdown_node.py +38 -0
  51. notionary/blocks/mention/mention_models.py +0 -0
  52. notionary/blocks/numbered_list/__init__.py +7 -0
  53. notionary/blocks/{numbered_list_element.py → numbered_list/numbered_list_element.py} +10 -6
  54. notionary/blocks/numbered_list/numbered_list_markdown_node.py +29 -0
  55. notionary/blocks/numbered_list/numbered_list_models.py +0 -0
  56. notionary/blocks/paragraph/__init__.py +7 -0
  57. notionary/blocks/{paragraph_element.py → paragraph/paragraph_element.py} +7 -3
  58. notionary/blocks/paragraph/paragraph_markdown_node.py +25 -0
  59. notionary/blocks/paragraph/paragraph_models.py +0 -0
  60. notionary/blocks/quote/__init__.py +7 -0
  61. notionary/blocks/quote/quote_element.py +92 -0
  62. notionary/blocks/quote/quote_markdown_node.py +23 -0
  63. notionary/blocks/quote/quote_models.py +0 -0
  64. notionary/blocks/registry/block_registry.py +17 -3
  65. notionary/blocks/registry/block_registry_builder.py +90 -178
  66. notionary/blocks/shared/__init__.py +0 -0
  67. notionary/blocks/shared/block_client.py +256 -0
  68. notionary/blocks/shared/models.py +713 -0
  69. notionary/blocks/{notion_block_element.py → shared/notion_block_element.py} +8 -5
  70. notionary/blocks/{text_inline_formatter.py → shared/text_inline_formatter.py} +14 -14
  71. notionary/blocks/shared/text_inline_formatter_new.py +139 -0
  72. notionary/blocks/table/__init__.py +7 -0
  73. notionary/blocks/{table_element.py → table/table_element.py} +23 -11
  74. notionary/blocks/table/table_markdown_node.py +40 -0
  75. notionary/blocks/table/table_models.py +0 -0
  76. notionary/blocks/todo/__init__.py +7 -0
  77. notionary/blocks/{todo_element.py → todo/todo_element.py} +8 -4
  78. notionary/blocks/todo/todo_markdown_node.py +31 -0
  79. notionary/blocks/todo/todo_models.py +0 -0
  80. notionary/blocks/toggle/__init__.py +4 -0
  81. notionary/blocks/{toggle_element.py → toggle/toggle_element.py} +7 -3
  82. notionary/blocks/toggle/toggle_markdown_node.py +35 -0
  83. notionary/blocks/toggle/toggle_models.py +0 -0
  84. notionary/blocks/toggleable_heading/__init__.py +9 -0
  85. notionary/blocks/{toggleable_heading_element.py → toggleable_heading/toggleable_heading_element.py} +8 -4
  86. notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +43 -0
  87. notionary/blocks/toggleable_heading/toggleable_heading_models.py +0 -0
  88. notionary/blocks/video/__init__.py +7 -0
  89. notionary/blocks/{video_element.py → video/video_element.py} +82 -57
  90. notionary/blocks/video/video_markdown_node.py +30 -0
  91. notionary/file_upload/notion_file_upload.py +1 -1
  92. notionary/page/content/markdown_whitespace_processor.py +80 -0
  93. notionary/page/content/notion_text_length_utils.py +87 -0
  94. notionary/page/content/page_content_retriever.py +18 -10
  95. notionary/page/content/page_content_writer.py +97 -148
  96. notionary/page/formatting/line_processor.py +153 -0
  97. notionary/page/formatting/markdown_to_notion_converter.py +104 -425
  98. notionary/page/notion_page.py +9 -11
  99. notionary/page/notion_to_markdown_converter.py +9 -13
  100. notionary/util/factory_decorator.py +0 -0
  101. notionary/workspace.py +0 -1
  102. {notionary-0.2.17.dist-info → notionary-0.2.19.dist-info}/METADATA +1 -1
  103. notionary-0.2.19.dist-info/RECORD +150 -0
  104. notionary/blocks/audio_element.py +0 -144
  105. notionary/blocks/callout_element.py +0 -122
  106. notionary/blocks/document_element.py +0 -194
  107. notionary/blocks/notion_block_client.py +0 -26
  108. notionary/blocks/qoute_element.py +0 -169
  109. notionary/page/content/notion_page_content_chunker.py +0 -84
  110. notionary/page/formatting/spacer_rules.py +0 -483
  111. notionary-0.2.17.dist-info/RECORD +0 -85
  112. {notionary-0.2.17.dist-info → notionary-0.2.19.dist-info}/LICENSE +0 -0
  113. {notionary-0.2.17.dist-info → notionary-0.2.19.dist-info}/WHEEL +0 -0
@@ -1,6 +1,4 @@
1
- from typing import Dict, Any, List, Optional
2
-
3
- from notionary.blocks import BlockRegistry, BlockRegistryBuilder
1
+ from typing import Dict, Any
4
2
 
5
3
 
6
4
  class NotionToMarkdownConverter:
@@ -9,15 +7,13 @@ class NotionToMarkdownConverter:
9
7
  TOGGLE_ELEMENT_TYPES = ["toggle", "toggleable_heading"]
10
8
  LIST_ITEM_TYPES = ["numbered_list_item", "bulleted_list_item"]
11
9
 
12
- def __init__(self, block_registry: Optional[BlockRegistry] = None):
10
+ def __init__(self, block_registry):
13
11
  """
14
12
  Initialize the NotionToMarkdownConverter.
15
13
  """
16
- self._block_registry = (
17
- block_registry or BlockRegistryBuilder().create_full_registry()
18
- )
14
+ self._block_registry = block_registry
19
15
 
20
- def convert(self, blocks: List[Dict[str, Any]]) -> str:
16
+ def convert(self, blocks: list[Dict[str, Any]]) -> str:
21
17
  """
22
18
  Convert Notion blocks to Markdown text, handling nested structures.
23
19
  """
@@ -102,7 +98,7 @@ class NotionToMarkdownConverter:
102
98
  indent = " " * spaces
103
99
  return "\n".join([f"{indent}{line}" for line in text.split("\n")])
104
100
 
105
- def extract_toggle_content(self, blocks: List[Dict[str, Any]]) -> str:
101
+ def extract_toggle_content(self, blocks: list[Dict[str, Any]]) -> str:
106
102
  """
107
103
  Extract only the content of toggles from blocks.
108
104
  """
@@ -117,7 +113,7 @@ class NotionToMarkdownConverter:
117
113
  return "\n".join(toggle_contents)
118
114
 
119
115
  def _extract_toggle_content_recursive(
120
- self, block: Dict[str, Any], result: List[str]
116
+ self, block: Dict[str, Any], result: list[str]
121
117
  ) -> None:
122
118
  """
123
119
  Recursively extract toggle content from a block and its children.
@@ -137,7 +133,7 @@ class NotionToMarkdownConverter:
137
133
  return block.get("type") in self.TOGGLE_ELEMENT_TYPES and "children" in block
138
134
 
139
135
  def _add_toggle_header_to_result(
140
- self, block: Dict[str, Any], result: List[str]
136
+ self, block: Dict[str, Any], result: list[str]
141
137
  ) -> None:
142
138
  """
143
139
  Add toggle header text to result list.
@@ -156,7 +152,7 @@ class NotionToMarkdownConverter:
156
152
  result.append(f"### {toggle_text}")
157
153
 
158
154
  def _add_toggle_children_to_result(
159
- self, block: Dict[str, Any], result: List[str]
155
+ self, block: Dict[str, Any], result: list[str]
160
156
  ) -> None:
161
157
  """
162
158
  Add formatted toggle children to result list.
@@ -173,7 +169,7 @@ class NotionToMarkdownConverter:
173
169
  if child_text:
174
170
  result.append(f"- {child_text}")
175
171
 
176
- def _extract_text_from_rich_text(self, rich_text: List[Dict[str, Any]]) -> str:
172
+ def _extract_text_from_rich_text(self, rich_text: list[Dict[str, Any]]) -> str:
177
173
  """
178
174
  Extract plain text from Notion's rich text array.
179
175
  """
File without changes
notionary/workspace.py CHANGED
@@ -28,7 +28,6 @@ class NotionWorkspace(LoggingMixin):
28
28
  Search for pages globally across Notion workspace.
29
29
  """
30
30
  response = await self.page_client.search_pages(query, limit=limit)
31
- # Parallelisiere die Erzeugung der NotionPage-Instanzen
32
31
  return await asyncio.gather(
33
32
  *(NotionPage.from_page_id(page.id) for page in response.results)
34
33
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: notionary
3
- Version: 0.2.17
3
+ Version: 0.2.19
4
4
  Summary: Python library for programmatic Notion workspace management - databases, pages, and content with advanced Markdown support
5
5
  License: MIT
6
6
  Author: Mathis Arends
@@ -0,0 +1,150 @@
1
+ notionary/__init__.py,sha256=klSdVgq1HZ6OU8bPo3YsyG7RTKCth5MjM8SkI7EH7Is,534
2
+ notionary/base_notion_client.py,sha256=WIAIKZeGCeAwtHWnL4Kfcmzv2TBlxvz7cfGF26i89y0,7067
3
+ notionary/blocks/__init__.py,sha256=CzHZg3ml2HD96fXRIgu-WXlH86UfQrlV77NdXN1C6UI,3155
4
+ notionary/blocks/audio/__init__.py,sha256=0GSTSbjAu4RV56qm22_xd7JkDRvrJNRDgGPTJT1leIQ,158
5
+ notionary/blocks/audio/audio_element.py,sha256=sjKTJR23whKTdp5pzkphTmd4q2hIFMwQvo6Qyoov3c0,5344
6
+ notionary/blocks/audio/audio_markdown_node.py,sha256=y0-qgrUM06XUFLdHhszC5OChhSRHpHKYXmOhEXrtetQ,831
7
+ notionary/blocks/audio/audio_models.py,sha256=rMNzvvhj8gYFKNALCT1oDdmuI6I5zlJgmVyENzij21s,1472
8
+ notionary/blocks/bookmark/__init__.py,sha256=ewtAXUCrqzY3VZ30A3SJf3lf5x_aX1K7u_HGDj0mVR8,176
9
+ notionary/blocks/bookmark/bookmark_element.py,sha256=OrDRXdCO6VzIY6OuNj9BNJuobEoGM3IUoO1fVjz_SoM,6148
10
+ notionary/blocks/bookmark/bookmark_markdown_node.py,sha256=39Uh518tTutU4_UDFQlpAY8lHgiCLW0_a9Kt7EMhsvg,1440
11
+ notionary/blocks/bookmark/bookmark_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ notionary/blocks/bulleted_list/__init__.py,sha256=7hlIuGEp29mCZX_HOA2LksJr1wOUggwGKe-g08WxadY,202
13
+ notionary/blocks/bulleted_list/bulleted_list_element.py,sha256=g6nYmLisJh8zhXTPZO6DPsNZK4NaeZp8fqB2YJ89Pqo,2639
14
+ notionary/blocks/bulleted_list/bulleted_list_markdown_node.py,sha256=B7MP6dwCgwoyaeGmbGdvCsPNUhLHUl7oElV8-h-rzhY,823
15
+ notionary/blocks/bulleted_list/bulleted_list_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ notionary/blocks/callout/__init__.py,sha256=PQnqH15cj1u5GVvbGm6jsWA_zN9SH7maSNNPP7quiUg,170
17
+ notionary/blocks/callout/callout_element.py,sha256=jn8DOCW86fuavZrjRu3AvW3aEj_P0jXmOyc7Av4tfVs,4553
18
+ notionary/blocks/callout/callout_markdown_node.py,sha256=sRy-F5kXPQRQU1HEnOPbZaJZ-nxDD8XmLHBIQFQOUDE,942
19
+ notionary/blocks/callout/callout_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ notionary/blocks/code/__init__.py,sha256=24uLJhL8tcGXWX1eNT9YYzZ6qKobQnxYoe5lASTOwzc,152
21
+ notionary/blocks/code/code_element.py,sha256=EV21-3VhW6ItrGq497bAgG_SKl65YuXb486XjixJIes,8732
22
+ notionary/blocks/code/code_markdown_node.py,sha256=DxWeiovmO9aP4eTX98ihMNQfwdZeItXOgO2J0YfkNf0,1191
23
+ notionary/blocks/code/code_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ notionary/blocks/column/__init__.py,sha256=QAC1nPTy8fQIBke1liI5sILFCyvN92yrjBTIRnVd6lE,83
25
+ notionary/blocks/column/column_element.py,sha256=MU6fY0WdzJz5XI8MHe-Nl_vadSXWHCrHXQKWgvEnVAY,11615
26
+ notionary/blocks/column/column_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ notionary/blocks/divider/__init__.py,sha256=gxDX3HtNXSjqqyu3j7LcpcxnxobTjKlS2nj_Zf9VSpc,170
28
+ notionary/blocks/divider/divider_element.py,sha256=RGM0X7Y_mQnBnPC2rRb9rdlYuHDhaiCRurHkaGJf4H8,2443
29
+ notionary/blocks/divider/divider_markdown_node.py,sha256=PtUyYSDGAiGBfP7AKEpAP3XERpEi75qyz2_MFZ0U4jk,579
30
+ notionary/blocks/divider/divider_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ notionary/blocks/document/__init__.py,sha256=KF_7ISXLqvEESomvERpLFwUxy2g5IYWR-uuZajfjt0Y,176
32
+ notionary/blocks/document/document_element.py,sha256=7gEOpv3CeryxkOQ5mrJI-yVKYFq8nzq7d5af0qVEmAo,4022
33
+ notionary/blocks/document/document_markdown_node.py,sha256=vtqTgyZ2xnxbIocpfg2UYCGffx4aCp7Ng9mvK14v9DA,1058
34
+ notionary/blocks/document/document_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
+ notionary/blocks/embed/__init__.py,sha256=7fEUdAsekiE3wc2YjbUOEFXqD77602q22KyPKqP9ns0,158
36
+ notionary/blocks/embed/embed_element.py,sha256=A0hX_wBbvEbq0yd5pcWpNQIOcNBVn0JDBC1p3HJ9_2U,5080
37
+ notionary/blocks/embed/embed_markdown_node.py,sha256=HFh9lMjV3zQz0HPEG7ib77i2PKt6PwZIXpokcjrdh8U,902
38
+ notionary/blocks/embed/embed_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ notionary/blocks/heading/__init__.py,sha256=OUFLp3Oketw4BTiqqxld9Hp-I-_oUWYL630IltZK6xA,170
40
+ notionary/blocks/heading/heading_element.py,sha256=BQDjSwnd9vpu-qxaKgOb0TBqfy8koT5YH6BTDgtbXm0,3447
41
+ notionary/blocks/heading/heading_markdown_node.py,sha256=XIfoxPdBihykAySQTfV94-WIU0cMsUxtfbhgiEIiP7Y,877
42
+ notionary/blocks/heading/heading_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
+ notionary/blocks/image/__init__.py,sha256=4ky2S6bYkrsfswati_bRwrl6IVaFqCJlLDJROS7IvOA,158
44
+ notionary/blocks/image/image_element.py,sha256=5MjO3ZaJTh2ld8J5f9JlgSU9O4mqmKV8-ztBqTSGppY,5432
45
+ notionary/blocks/image/image_markdown_node.py,sha256=hxSASo5lXEBbFHXXu9U8xPz5Z7wpWGLJqSu-RRIRhWE,1029
46
+ notionary/blocks/image/image_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
+ notionary/blocks/markdown_builder.py,sha256=HJKN1mmxBO_zI3D9JPPKXX10brdN1bf8Q2FEJg1ay4Q,10387
48
+ notionary/blocks/markdown_node.py,sha256=ZIbdok878aCMHnMh6k1kAftcPexQgiWFyHcSMNWepZo,715
49
+ notionary/blocks/mention/__init__.py,sha256=C6l5WqMjrD8MrA_rE0e22U-gSddlVWNVtGg8lcYfFyk,170
50
+ notionary/blocks/mention/mention_element.py,sha256=wEmw6l65CIin9rfrM4Hnb9kraRA5US0LKB-SpstjlqA,8155
51
+ notionary/blocks/mention/mention_markdown_node.py,sha256=zcKMRIWXHJzPg8C8nj5U_r2Q-WZrIPmNMcTwC-pTU60,1325
52
+ notionary/blocks/mention/mention_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
+ notionary/blocks/numbered_list/__init__.py,sha256=T7IMAp542u56X8vooRbs1NcbggMRDQ778QSCxMyifbA,202
54
+ notionary/blocks/numbered_list/numbered_list_element.py,sha256=UA_VKldZ8bxRSe4qnikvTMcTyIM5BsRZf5QOlmAZxo8,2630
55
+ notionary/blocks/numbered_list/numbered_list_markdown_node.py,sha256=BTyfhoInvTcw-6zSRtIzBNjIOpQvHPtqoXBp3bKrkgY,779
56
+ notionary/blocks/numbered_list/numbered_list_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
+ notionary/blocks/paragraph/__init__.py,sha256=XudhEdGaD2uIdJM4saygESClU5w3TBIq38kpR8huLps,182
58
+ notionary/blocks/paragraph/paragraph_element.py,sha256=mBYiRP-pqCQuDGr9hz1qpqXNeSwbE6uoAkjOaaCsbns,3228
59
+ notionary/blocks/paragraph/paragraph_markdown_node.py,sha256=-7e5hyGVaIU3G9nqyyqlANoGjRRZKZIWKGCIAExl6vs,665
60
+ notionary/blocks/paragraph/paragraph_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
+ notionary/blocks/prompts/element_prompt_builder.py,sha256=rYMKPmpEFyk26JFZlwcTzMHATpvHnn4Dn284vewFog0,2953
62
+ notionary/blocks/prompts/element_prompt_content.py,sha256=ItnhGwKsHGnnY9E_LGgZZeTCT9ZfnkJY8xad4wFViWk,1567
63
+ notionary/blocks/quote/__init__.py,sha256=rZ8-t7a2TAN57flHXkaynodRat8vLZ07y2Rz3rpbur0,158
64
+ notionary/blocks/quote/quote_element.py,sha256=KuRi22nMC621JtYCCxItGJSTSkYrxZqaxUFXviX7xV4,3174
65
+ notionary/blocks/quote/quote_markdown_node.py,sha256=XNlo-8rm3s6k08dy4m-kQ7llo5jdm_EKSicN9xcK2Z0,636
66
+ notionary/blocks/quote/quote_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
+ notionary/blocks/registry/block_registry.py,sha256=O0yo3B6QIZa-a6gClt_rzaxO_ijwsYc5clv2B0NLCQw,5366
68
+ notionary/blocks/registry/block_registry_builder.py,sha256=r7wVIjvfCRZWby9RabX9zBSeH_BuoqrRNCl-8yHwt5I,6551
69
+ notionary/blocks/shared/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
+ notionary/blocks/shared/block_client.py,sha256=EF2xYcrpJ2pF5LYSc9UNDw74Izf25gw5a05-P4CRmZE,8997
71
+ notionary/blocks/shared/models.py,sha256=lpLtDOLxpiEQzEYAroaLpCgjCn4XoInsVyJHK-bBcDE,18007
72
+ notionary/blocks/shared/notion_block_element.py,sha256=pKsGRPrSa_IqZHmer4HL5DCzFuhqo34vYXptXoXToX0,1443
73
+ notionary/blocks/shared/text_inline_formatter.py,sha256=mCqFS05oJwSU5fPoUUHVeud_hU8G4Z5mYFx7KeMY-s8,8564
74
+ notionary/blocks/shared/text_inline_formatter_new.py,sha256=nYmoFQVuAkfouCpGYULxFr4hHVCnRgvf3zxoiHBxIKg,4665
75
+ notionary/blocks/table/__init__.py,sha256=mul3r3dU5U9Z1hqa1QMlQc9aIwHM-9yKru9-RbLmWs8,158
76
+ notionary/blocks/table/table_element.py,sha256=oZV0p7gIbm7344SzSz-fKmQYmA5KS4-lcZiD8ZvxBH8,11479
77
+ notionary/blocks/table/table_markdown_node.py,sha256=pzdegpxB5bYRXsWQd7oUy-p2YjuEFdWd7NeHSd4PrRI,1398
78
+ notionary/blocks/table/table_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
+ notionary/blocks/todo/__init__.py,sha256=4hbX7RIqbFn1H2Tz9mb2jkmSbav6AMdleTYKfVhGGIc,152
80
+ notionary/blocks/todo/todo_element.py,sha256=WFA9chSa9Nvh0MgMObeh4DXkjTBBGJpYmMFKjQikkhI,4075
81
+ notionary/blocks/todo/todo_markdown_node.py,sha256=X578oPFA_KBzqCeY5-Be3_5TZ45QEyWayzt0MitIli8,992
82
+ notionary/blocks/todo/todo_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
+ notionary/blocks/toggle/__init__.py,sha256=N_-3QGKf4RPBmCF6GmYqbbmcY7K7KD10KpwsMLWAp1Y,206
84
+ notionary/blocks/toggle/toggle_element.py,sha256=Oj1Pmvdik7RmliME_maa0FfdoMM6Hvy5cS2aFyFQ114,11026
85
+ notionary/blocks/toggle/toggle_markdown_node.py,sha256=joEPiUQoC-D0fhypeJF3GaZHOYw4vuyry5OGSEZF4tY,1065
86
+ notionary/blocks/toggle/toggle_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
87
+ notionary/blocks/toggleable_heading/__init__.py,sha256=rn-8AsL9Fp04k4dA7ugmhZ0RxLJ1vuqdCHAORcvt6Ns,243
88
+ notionary/blocks/toggleable_heading/toggleable_heading_element.py,sha256=_5Acptg4wFDhxSyMm3C0UJkSv8bssS0J7p_TmNfA6Pg,9909
89
+ notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py,sha256=KFX1Xba4zW60zQf6_AWZG0YPbERZq1f7CmTqQgGNnQo,1409
90
+ notionary/blocks/toggleable_heading/toggleable_heading_models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
+ notionary/blocks/video/__init__.py,sha256=kEhoKaHblyDyapIYj4DFhFlKm_0aQy3SCVyI5WmavJQ,158
92
+ notionary/blocks/video/video_element.py,sha256=fSPZ8yfFw6njFyZP0mGwxmHZXvM4m9Ayjb4ACc6MmhQ,6452
93
+ notionary/blocks/video/video_markdown_node.py,sha256=v4KgYJPLFy75a1d-ETya2JDf_JHy79QiQJNLw1l_jMU,903
94
+ notionary/database/__init__.py,sha256=4tdML0fBzkOCpiWT6q-L--5NELFLbTPD0IUA_E8yZno,155
95
+ notionary/database/client.py,sha256=ZcfydeYlpgGJt6wV1ib33KeXUiL-cGNJ1qraQZ4RVRc,4775
96
+ notionary/database/database.py,sha256=7KBe6DWbtsakPvjUO45eCphD2sq0ZKuYHY3kXJsk4P8,16582
97
+ notionary/database/database_filter_builder.py,sha256=PCnq3M9REt-NHRgBIfSrTCIPykUqBs5RqZK13WOAHKA,5950
98
+ notionary/database/database_provider.py,sha256=MveBSMkYG8nLUzKTS7KjbFVH8H-vLdH0t6yGArs-vPQ,8976
99
+ notionary/database/exceptions.py,sha256=jwFdxoIQHLO3mO3p5t890--1FjbTX60fNyqBAe-sszo,452
100
+ notionary/database/factory.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
101
+ notionary/database/models/page_result.py,sha256=Vmm5_oYpYAkIIJVoTd1ZZGloeC3cmFLMYP255mAmtaw,233
102
+ notionary/database/notion_database.py,sha256=wSqPfVtOnDL-aKRrE9BSMP1cpHe0_8RYyfCMxrlJSNo,16746
103
+ notionary/elements/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
104
+ notionary/file_upload/__init__.py,sha256=7TNyiIgLMD_IGRXTwRiAmStokF3rLoG4zXPwNb9KQqk,168
105
+ notionary/file_upload/client.py,sha256=qlxgu7_Ia0wbBflInoGki4mR8Po_RZgfLjO2wa279jY,8581
106
+ notionary/file_upload/models.py,sha256=0mYtuGkZ_eh_YmX0uxqye5vg3wWgqWuwOupAmLJXMUY,1625
107
+ notionary/file_upload/notion_file_upload.py,sha256=kUwFOoYclwbyesfPWPOJPbANFJORskzUvSgC8fsn8VM,13175
108
+ notionary/models/notion_block_response.py,sha256=gzL4C6K9QPcaMS6NbAZaRceSEnMbNwYBVVzxysza5VU,6002
109
+ notionary/models/notion_database_response.py,sha256=3kvADIP1dSxgITSK4n8Ex3QpF8n_Lxnu_IXbPVGcq4o,7648
110
+ notionary/models/notion_page_response.py,sha256=7ZwDYhlyK-avix_joQpGuNQZopjlQFI8jS3nvNNumoc,1544
111
+ notionary/models/search_response.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
112
+ notionary/page/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
113
+ notionary/page/client.py,sha256=XQ72lOEwn-gO8fmhKSKHqSHs3hRmoKH0TkJ3TtblcAg,4030
114
+ notionary/page/content/markdown_whitespace_processor.py,sha256=azsYau4eDrFN9CY7kzlG-ketoVKSkqSTc1bFq_i7ggQ,2942
115
+ notionary/page/content/notion_text_length_utils.py,sha256=RZqlcolvBBR1krlTMGS8q9xiZYYDGTyxZAjKhhONQyk,2757
116
+ notionary/page/content/page_content_retriever.py,sha256=NOJ4ubLgZJECtQYcactVkeB6eiIYRBTM1llk5fh_6uc,1901
117
+ notionary/page/content/page_content_writer.py,sha256=0evYwdR7dSWECer_nHGAQsXbbkcbpnGQuacNXp14nG8,5656
118
+ notionary/page/formatting/line_processor.py,sha256=zr1P2zG0lSGgBlP1KbFvcnazOUTHGnF_uQeFUtLakfw,5404
119
+ notionary/page/formatting/markdown_to_notion_converter.py,sha256=tbgaoEPJ96-JfCsyEsEK5-abdfmXapm9F2CAEX2rpig,6073
120
+ notionary/page/markdown_syntax_prompt_generator.py,sha256=uHCPNV9aQi3GzLVimyUKwza29hfxu6DTMVIa_QevJbk,4987
121
+ notionary/page/notion_page.py,sha256=5RbKxlA2RBoGiNXjO4bvgV9OMIIKwsTPbM3XolDOU2w,19026
122
+ notionary/page/notion_to_markdown_converter.py,sha256=3zvP1HSnUp3YlvK3PfIqh8GUi7xAuVWGQB0c38uK5VU,6117
123
+ notionary/page/properites/property_value_extractor.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
124
+ notionary/page/property_formatter.py,sha256=_978ViH83gfcr-XtDscWTfyBI2srGW2hzC-gzgp5NR8,3788
125
+ notionary/page/search_filter_builder.py,sha256=wZpW_KHmPXql3sNIyQd9EzZ2-ERy2i0vYNdoLkoBUfc,4597
126
+ notionary/page/utils.py,sha256=2nfBrWeczBdPH13R3q8dKP4OY4MwEdfKbcs2UJ9kg1o,2041
127
+ notionary/telemetry/__init__.py,sha256=Y7KyXeN4PiA6GtzV3NnwoH4hJnPwdjikWP22ckPYuHM,511
128
+ notionary/telemetry/service.py,sha256=DD7RbkSN0HWRK2YpOJTgFD7PeXGhSe9KrLkhiVIaC7Y,4763
129
+ notionary/telemetry/views.py,sha256=FgFZGYaxP7pRYx-9wg18skMh_MJAwf4W3rCfe9JOZe4,1796
130
+ notionary/user/__init__.py,sha256=D8r_WtQimdT-l3P1wd8O9Iki5JXF7jg2KV_hOgzWraw,281
131
+ notionary/user/base_notion_user.py,sha256=QB1701CfQTeu1ZNWOHYnGvTSHZuiritr6xYNMqyVg_U,1500
132
+ notionary/user/client.py,sha256=v8-lpyKzY_gSWPdWkBEjqxEPSg1WCy9AYSAJLXRrfKA,4563
133
+ notionary/user/models.py,sha256=3WPUysO96hMZUZYUWoCH5cdqNvnWgdiw5Qd7QKOv2UY,2063
134
+ notionary/user/notion_bot_user.py,sha256=cwrwmfst5RbAgppIjoFMJjExms1epfRM9VBd-S-3y5Q,7784
135
+ notionary/user/notion_user.py,sha256=l0GOMakk_xzsUUt7SsDJ5j-3dbtX64cUyyQPxn0r0Zc,8512
136
+ notionary/user/notion_user_manager.py,sha256=JQddAvbKJiLCLCn0mfxmvoi5uLW95vHhMWEYZD_F9zk,6339
137
+ notionary/user/notion_user_provider.py,sha256=7ImQ7T76g88W4YyHGOoO0aUJQfdGlhbh1fMT9PzR1mU,19
138
+ notionary/util/__init__.py,sha256=Bu2yGFd3xPasBrMRMk-6DcmMXfkdXn-KfFRETApBcP8,351
139
+ notionary/util/factory_decorator.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
140
+ notionary/util/factory_only.py,sha256=q-ZXUEvQ8lsuD1JQwx-ai6e9Lhie65waRE1BcRhCR_4,1235
141
+ notionary/util/fuzzy.py,sha256=lTlWuYEs0lhLa7QIRre3GVJ8-biIV_NmcJnMzBYFF5U,2061
142
+ notionary/util/logging_mixin.py,sha256=t08dx3nhSJq2-6_N8G39aydPEkQ76D4MlRfymxCsCVM,1690
143
+ notionary/util/page_id_utils.py,sha256=AA00kRO-g3Cc50tf_XW_tb5RBuPKLuBxRa0D8LYhLXg,736
144
+ notionary/util/singleton.py,sha256=CKAvykndwPRZsA3n3MAY_XdCR59MBjjKP0vtm2BcvF0,428
145
+ notionary/util/singleton_metaclass.py,sha256=uNeHiqS6TwhljvG1RE4NflIp2HyMuMmrCg2xI-vxmHE,809
146
+ notionary/workspace.py,sha256=hp5JPVT_aQsZNuxg2R-DiODobcGlVP4CusxNhzpnxKw,3813
147
+ notionary-0.2.19.dist-info/LICENSE,sha256=zOm3cRT1qD49eg7vgw95MI79rpUAZa1kRBFwL2FkAr8,1120
148
+ notionary-0.2.19.dist-info/METADATA,sha256=iKAerIgfYBeA0i8JunODWf3Wr54rsL9ZDmmJLLWy6Ms,6867
149
+ notionary-0.2.19.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
150
+ notionary-0.2.19.dist-info/RECORD,,
@@ -1,144 +0,0 @@
1
- from __future__ import annotations
2
- from typing import Dict, Any, Optional, List
3
- import re
4
-
5
- from notionary.blocks.notion_block_element import NotionBlockElement
6
- from notionary.blocks import (
7
- ElementPromptBuilder,
8
- ElementPromptContent,
9
- )
10
-
11
-
12
- class AudioElement(NotionBlockElement):
13
- """
14
- Handles conversion between Markdown audio embeds and Notion audio blocks.
15
-
16
- Markdown audio syntax (custom format since standard Markdown doesn't support audio):
17
- - $[Caption](https://example.com/audio.mp3) - Basic audio with caption
18
- - $[](https://example.com/audio.mp3) - Audio without caption
19
- - $[Caption](https://storage.googleapis.com/audio_summaries/example.mp3) - CDN hosted audio
20
-
21
- Supports various audio URLs including direct audio file links from CDNs and other sources.
22
- """
23
-
24
- PATTERN = re.compile(r"^\$\[(.*?)\]" + r'\((https?://[^\s"]+)' + r"\)$")
25
-
26
- AUDIO_EXTENSIONS = [".mp3", ".wav", ".ogg", ".m4a", ".flac", ".aac"]
27
-
28
- @classmethod
29
- def match_markdown(cls, text: str) -> bool:
30
- """Check if text is a markdown audio embed."""
31
- text = text.strip()
32
- return text.startswith("$[") and bool(cls.PATTERN.match(text))
33
-
34
- @classmethod
35
- def match_notion(cls, block: Dict[str, Any]) -> bool:
36
- """Check if block is a Notion audio."""
37
- return block.get("type") == "audio"
38
-
39
- @classmethod
40
- def is_audio_url(cls, url: str) -> bool:
41
- """Check if URL points to an audio file."""
42
- return (
43
- any(url.lower().endswith(ext) for ext in cls.AUDIO_EXTENSIONS)
44
- or "audio" in url.lower()
45
- or "storage.googleapis.com/audio_summaries" in url.lower()
46
- )
47
-
48
- @classmethod
49
- def markdown_to_notion(cls, text: str) -> Optional[Dict[str, Any]]:
50
- """Convert markdown audio embed to Notion audio block."""
51
- audio_match = cls.PATTERN.match(text.strip())
52
- if not audio_match:
53
- return None
54
-
55
- caption = audio_match.group(1)
56
- url = audio_match.group(2)
57
-
58
- if not url:
59
- return None
60
-
61
- # Make sure this is an audio URL
62
- if not cls.is_audio_url(url):
63
- # If not obviously an audio URL, we'll still accept it as the user might know better
64
- pass
65
-
66
- # Prepare the audio block
67
- audio_block = {
68
- "type": "audio",
69
- "audio": {"type": "external", "external": {"url": url}},
70
- }
71
-
72
- # Add caption if provided
73
- if caption:
74
- audio_block["audio"]["caption"] = [
75
- {"type": "text", "text": {"content": caption}}
76
- ]
77
-
78
- return audio_block
79
-
80
- @classmethod
81
- def notion_to_markdown(cls, block: Dict[str, Any]) -> Optional[str]:
82
- """Convert Notion audio block to markdown audio embed."""
83
- if block.get("type") != "audio":
84
- return None
85
-
86
- audio_data = block.get("audio", {})
87
-
88
- # Handle both external and file (uploaded) audios
89
- if audio_data.get("type") == "external":
90
- url = audio_data.get("external", {}).get("url", "")
91
- elif audio_data.get("type") == "file":
92
- url = audio_data.get("file", {}).get("url", "")
93
- else:
94
- return None
95
-
96
- if not url:
97
- return None
98
-
99
- # Extract caption if available
100
- caption = ""
101
- caption_rich_text = audio_data.get("caption", [])
102
- if caption_rich_text:
103
- caption = cls._extract_text_content(caption_rich_text)
104
-
105
- return f"$[{caption}]({url})"
106
-
107
- @classmethod
108
- def is_multiline(cls) -> bool:
109
- """Audio embeds are single-line elements."""
110
- return False
111
-
112
- @classmethod
113
- def _extract_text_content(cls, rich_text: List[Dict[str, Any]]) -> str:
114
- """Extract plain text content from Notion rich_text elements."""
115
- result = ""
116
- for text_obj in rich_text:
117
- if text_obj.get("type") == "text":
118
- result += text_obj.get("text", {}).get("content", "")
119
- elif "plain_text" in text_obj:
120
- result += text_obj.get("plain_text", "")
121
- return result
122
-
123
- @classmethod
124
- def get_llm_prompt_content(cls) -> ElementPromptContent:
125
- """Returns information for LLM prompts about this element."""
126
- return (
127
- ElementPromptBuilder()
128
- .with_description(
129
- "Embeds audio content from external sources like CDNs or direct audio URLs."
130
- )
131
- .with_syntax("$[Caption](https://example.com/audio.mp3)")
132
- .with_examples(
133
- [
134
- "$[Podcast Episode](https://storage.googleapis.com/audio_summaries/ep_ai_summary_127d02ec-ca12-4312-a5ed-cb14b185480c.mp3)",
135
- "$[Voice recording](https://example.com/audio/recording.mp3)",
136
- "$[](https://storage.googleapis.com/audio_summaries/example.mp3)",
137
- ]
138
- )
139
- .with_usage_guidelines(
140
- "Use audio embeds when you want to include audio content directly in your document. "
141
- "Audio embeds are useful for podcasts, music, voice recordings, or any content that benefits from audio explanation."
142
- )
143
- .build()
144
- )
@@ -1,122 +0,0 @@
1
- import re
2
- from typing import Dict, Any, Optional
3
-
4
- from notionary.blocks import ElementPromptContent, ElementPromptBuilder
5
- from notionary.blocks.text_inline_formatter import TextInlineFormatter
6
- from notionary.blocks.notion_block_element import NotionBlockElement
7
-
8
-
9
- class CalloutElement(NotionBlockElement):
10
- """
11
- Handles conversion between Markdown callouts and Notion callout blocks.
12
-
13
- Markdown callout syntax:
14
- - !> [emoji] Text - Callout with custom emoji
15
- - !> Text - Simple callout with default emoji
16
-
17
- Where:
18
- - [emoji] is any emoji character
19
- - Text is the callout content with optional inline formatting
20
- """
21
-
22
- EMOJI_PATTERN = r"(?:\[([^\]]+)\])?\s*"
23
- TEXT_PATTERN = r"(.+)"
24
-
25
- PATTERN = re.compile(r"^!>\s+" + EMOJI_PATTERN + TEXT_PATTERN + r"$")
26
-
27
- DEFAULT_EMOJI = "💡"
28
- DEFAULT_COLOR = "gray_background"
29
-
30
- @classmethod
31
- def match_markdown(cls, text: str) -> bool:
32
- """Check if text is a markdown callout."""
33
- return text.strip().startswith("!>") and bool(
34
- CalloutElement.PATTERN.match(text)
35
- )
36
-
37
- @classmethod
38
- def match_notion(cls, block: Dict[str, Any]) -> bool:
39
- """Check if block is a Notion callout."""
40
- return block.get("type") == "callout"
41
-
42
- @classmethod
43
- def markdown_to_notion(cls, text: str) -> Optional[Dict[str, Any]]:
44
- """Convert markdown callout to Notion callout block."""
45
- callout_match = CalloutElement.PATTERN.match(text)
46
- if not callout_match:
47
- return None
48
-
49
- emoji = callout_match.group(1)
50
- content = callout_match.group(2)
51
-
52
- if not emoji:
53
- emoji = CalloutElement.DEFAULT_EMOJI
54
-
55
- return {
56
- "type": "callout",
57
- "callout": {
58
- "rich_text": TextInlineFormatter.parse_inline_formatting(content),
59
- "icon": {"type": "emoji", "emoji": emoji},
60
- "color": CalloutElement.DEFAULT_COLOR,
61
- },
62
- }
63
-
64
- @classmethod
65
- def notion_to_markdown(cls, block: Dict[str, Any]) -> Optional[str]:
66
- """Convert Notion callout block to markdown callout."""
67
- if block.get("type") != "callout":
68
- return None
69
-
70
- callout_data = block.get("callout", {})
71
- rich_text = callout_data.get("rich_text", [])
72
- icon = callout_data.get("icon", {})
73
-
74
- text = TextInlineFormatter.extract_text_with_formatting(rich_text)
75
- if not text:
76
- return None
77
-
78
- emoji = ""
79
- if icon and icon.get("type") == "emoji":
80
- emoji = icon.get("emoji", "")
81
-
82
- emoji_str = ""
83
- if emoji and emoji != CalloutElement.DEFAULT_EMOJI:
84
- emoji_str = f"[{emoji}] "
85
-
86
- return f"!> {emoji_str}{text}"
87
-
88
- @classmethod
89
- def is_multiline(cls) -> bool:
90
- return False
91
-
92
- @classmethod
93
- def get_llm_prompt_content(cls) -> ElementPromptContent:
94
- """
95
- Returns structured LLM prompt metadata for the callout element.
96
- Includes description, usage guidance, syntax options, and examples.
97
- """
98
- return (
99
- ElementPromptBuilder()
100
- .with_description(
101
- "Creates a callout block to highlight important information with an icon."
102
- )
103
- .with_usage_guidelines(
104
- "Use callouts when you want to draw attention to important information, "
105
- "tips, warnings, or notes that stand out from the main content. "
106
- "The emoji MUST be enclosed in square brackets to properly display."
107
- )
108
- .with_syntax("!> [emoji] Text")
109
- .with_examples(
110
- [
111
- "!> [💡] This is a default callout with the light bulb emoji",
112
- "!> [🔔] This is a callout with a bell emoji",
113
- "!> [⚠️] Warning: This is an important note to pay attention to",
114
- "!> [💡] Tip: Add emoji that matches your content's purpose",
115
- ]
116
- )
117
- .with_avoidance_guidelines(
118
- "NEVER omit the square brackets around the emoji. The format MUST be !> [emoji] and not !> emoji. "
119
- "Without the square brackets, Notion will not properly render the callout with the specified emoji."
120
- )
121
- .build()
122
- )