notionary 0.2.26__py3-none-any.whl → 0.2.28__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 (387) hide show
  1. notionary/__init__.py +5 -20
  2. notionary/blocks/client.py +87 -215
  3. notionary/blocks/enums.py +167 -0
  4. notionary/blocks/rich_text/markdown_rich_text_converter.py +266 -0
  5. notionary/blocks/rich_text/models.py +164 -0
  6. notionary/blocks/rich_text/name_id_resolver/__init__.py +11 -0
  7. notionary/blocks/rich_text/name_id_resolver/database.py +31 -0
  8. notionary/blocks/rich_text/name_id_resolver/page.py +34 -0
  9. notionary/blocks/rich_text/name_id_resolver/person.py +37 -0
  10. notionary/blocks/rich_text/name_id_resolver/port.py +11 -0
  11. notionary/blocks/rich_text/rich_text_markdown_converter.py +132 -0
  12. notionary/blocks/rich_text/rich_text_patterns.py +39 -0
  13. notionary/blocks/schemas.py +746 -0
  14. notionary/comments/client.py +52 -187
  15. notionary/comments/factory.py +40 -0
  16. notionary/comments/models.py +5 -127
  17. notionary/comments/schemas.py +240 -0
  18. notionary/comments/service.py +34 -0
  19. notionary/data_source/http/client.py +11 -0
  20. notionary/data_source/http/data_source_instance_client.py +94 -0
  21. notionary/data_source/properties/models.py +406 -0
  22. notionary/data_source/query/builder.py +429 -0
  23. notionary/data_source/query/resolver.py +114 -0
  24. notionary/data_source/query/schema.py +304 -0
  25. notionary/data_source/query/validator.py +73 -0
  26. notionary/data_source/schemas.py +27 -0
  27. notionary/data_source/service.py +353 -0
  28. notionary/database/client.py +30 -135
  29. notionary/database/database_metadata_update_client.py +19 -0
  30. notionary/database/schemas.py +29 -0
  31. notionary/database/service.py +169 -0
  32. notionary/exceptions/__init__.py +33 -0
  33. notionary/exceptions/api.py +41 -0
  34. notionary/exceptions/base.py +2 -0
  35. notionary/exceptions/block_parsing.py +16 -0
  36. notionary/exceptions/data_source/__init__.py +6 -0
  37. notionary/exceptions/data_source/builder.py +182 -0
  38. notionary/exceptions/data_source/properties.py +34 -0
  39. notionary/exceptions/properties.py +58 -0
  40. notionary/exceptions/search.py +33 -0
  41. notionary/file_upload/client.py +18 -30
  42. notionary/file_upload/models.py +7 -8
  43. notionary/file_upload/{notion_file_upload.py → service.py} +29 -64
  44. notionary/http/client.py +205 -0
  45. notionary/http/models.py +49 -0
  46. notionary/page/blocks/client.py +1 -0
  47. notionary/page/content/factory.py +68 -0
  48. notionary/page/content/markdown/__init__.py +5 -0
  49. notionary/page/content/markdown/builder.py +304 -0
  50. notionary/page/content/markdown/nodes/__init__.py +54 -0
  51. notionary/page/content/markdown/nodes/audio.py +23 -0
  52. notionary/page/content/markdown/nodes/base.py +12 -0
  53. notionary/page/content/markdown/nodes/bookmark.py +25 -0
  54. notionary/page/content/markdown/nodes/breadcrumb.py +14 -0
  55. notionary/page/content/markdown/nodes/bulleted_list.py +18 -0
  56. notionary/page/content/markdown/nodes/callout.py +32 -0
  57. notionary/page/content/markdown/nodes/code.py +30 -0
  58. notionary/page/content/markdown/nodes/columns.py +51 -0
  59. notionary/page/content/markdown/nodes/divider.py +14 -0
  60. notionary/page/content/markdown/nodes/embed.py +23 -0
  61. notionary/page/content/markdown/nodes/equation.py +19 -0
  62. notionary/page/content/markdown/nodes/file.py +23 -0
  63. notionary/page/content/markdown/nodes/heading.py +16 -0
  64. notionary/page/content/markdown/nodes/image.py +23 -0
  65. notionary/page/content/markdown/nodes/mixins/caption.py +12 -0
  66. notionary/page/content/markdown/nodes/numbered_list.py +15 -0
  67. notionary/page/content/markdown/nodes/paragraph.py +14 -0
  68. notionary/page/content/markdown/nodes/pdf.py +23 -0
  69. notionary/page/content/markdown/nodes/quote.py +15 -0
  70. notionary/page/content/markdown/nodes/space.py +14 -0
  71. notionary/page/content/markdown/nodes/table.py +45 -0
  72. notionary/page/content/markdown/nodes/table_of_contents.py +14 -0
  73. notionary/page/content/markdown/nodes/todo.py +22 -0
  74. notionary/page/content/markdown/nodes/toggle.py +28 -0
  75. notionary/page/content/markdown/nodes/toggleable_heading.py +35 -0
  76. notionary/page/content/markdown/nodes/video.py +23 -0
  77. notionary/page/content/parser/context.py +49 -0
  78. notionary/page/content/parser/factory.py +219 -0
  79. notionary/page/content/parser/parsers/__init__.py +60 -0
  80. notionary/page/content/parser/parsers/audio.py +40 -0
  81. notionary/page/content/parser/parsers/base.py +30 -0
  82. notionary/page/content/parser/parsers/bookmark.py +33 -0
  83. notionary/page/content/parser/parsers/breadcrumb.py +33 -0
  84. notionary/page/content/parser/parsers/bulleted_list.py +41 -0
  85. notionary/page/content/parser/parsers/callout.py +129 -0
  86. notionary/page/content/parser/parsers/caption.py +55 -0
  87. notionary/page/content/parser/parsers/code.py +81 -0
  88. notionary/page/content/parser/parsers/column.py +117 -0
  89. notionary/page/content/parser/parsers/column_list.py +81 -0
  90. notionary/page/content/parser/parsers/divider.py +33 -0
  91. notionary/page/content/parser/parsers/embed.py +33 -0
  92. notionary/page/content/parser/parsers/equation.py +65 -0
  93. notionary/page/content/parser/parsers/file.py +42 -0
  94. notionary/page/content/parser/parsers/heading.py +58 -0
  95. notionary/page/content/parser/parsers/image.py +42 -0
  96. notionary/page/content/parser/parsers/numbered_list.py +45 -0
  97. notionary/page/content/parser/parsers/paragraph.py +36 -0
  98. notionary/page/content/parser/parsers/pdf.py +42 -0
  99. notionary/page/content/parser/parsers/quote.py +65 -0
  100. notionary/page/content/parser/parsers/space.py +35 -0
  101. notionary/page/content/parser/parsers/table.py +144 -0
  102. notionary/page/content/parser/parsers/table_of_contents.py +32 -0
  103. notionary/page/content/parser/parsers/todo.py +58 -0
  104. notionary/page/content/parser/parsers/toggle.py +127 -0
  105. notionary/page/content/parser/parsers/toggleable_heading.py +150 -0
  106. notionary/page/content/parser/parsers/video.py +42 -0
  107. notionary/page/content/parser/post_processing/handlers/__init__.py +5 -0
  108. notionary/page/content/parser/post_processing/handlers/rich_text_length.py +93 -0
  109. notionary/page/content/parser/post_processing/handlers/rich_text_length_truncation.py +93 -0
  110. notionary/page/content/parser/post_processing/port.py +9 -0
  111. notionary/page/content/parser/post_processing/service.py +16 -0
  112. notionary/page/content/parser/pre_processsing/handlers/__init__.py +9 -0
  113. notionary/page/content/parser/pre_processsing/handlers/column_syntax.py +80 -0
  114. notionary/page/content/parser/pre_processsing/handlers/port.py +7 -0
  115. notionary/page/content/parser/pre_processsing/handlers/whitespace.py +68 -0
  116. notionary/page/content/parser/pre_processsing/service.py +15 -0
  117. notionary/page/content/parser/service.py +69 -0
  118. notionary/page/content/renderer/context.py +48 -0
  119. notionary/page/content/renderer/factory.py +240 -0
  120. notionary/page/content/renderer/post_processing/handlers/__init__.py +5 -0
  121. notionary/page/content/renderer/post_processing/handlers/numbered_list_placeholdere.py +62 -0
  122. notionary/page/content/renderer/post_processing/port.py +7 -0
  123. notionary/page/content/renderer/post_processing/service.py +15 -0
  124. notionary/page/content/renderer/renderers/__init__.py +57 -0
  125. notionary/page/content/renderer/renderers/audio.py +31 -0
  126. notionary/page/content/renderer/renderers/base.py +31 -0
  127. notionary/page/content/renderer/renderers/bookmark.py +25 -0
  128. notionary/page/content/renderer/renderers/breadcrumb.py +21 -0
  129. notionary/page/content/renderer/renderers/bulleted_list.py +48 -0
  130. notionary/page/content/renderer/renderers/callout.py +65 -0
  131. notionary/page/content/renderer/renderers/captioned_block.py +58 -0
  132. notionary/page/content/renderer/renderers/code.py +34 -0
  133. notionary/page/content/renderer/renderers/column.py +44 -0
  134. notionary/page/content/renderer/renderers/column_list.py +31 -0
  135. notionary/page/content/renderer/renderers/divider.py +22 -0
  136. notionary/page/content/renderer/renderers/embed.py +25 -0
  137. notionary/page/content/renderer/renderers/equation.py +37 -0
  138. notionary/page/content/renderer/renderers/fallback.py +24 -0
  139. notionary/page/content/renderer/renderers/file.py +40 -0
  140. notionary/page/content/renderer/renderers/heading.py +69 -0
  141. notionary/page/content/renderer/renderers/image.py +31 -0
  142. notionary/page/content/renderer/renderers/numbered_list.py +41 -0
  143. notionary/page/content/renderer/renderers/paragraph.py +40 -0
  144. notionary/page/content/renderer/renderers/pdf.py +31 -0
  145. notionary/page/content/renderer/renderers/quote.py +49 -0
  146. notionary/page/content/renderer/renderers/table.py +115 -0
  147. notionary/page/content/renderer/renderers/table_of_contents.py +26 -0
  148. notionary/page/content/renderer/renderers/table_row.py +17 -0
  149. notionary/page/content/renderer/renderers/todo.py +56 -0
  150. notionary/page/content/renderer/renderers/toggle.py +53 -0
  151. notionary/page/content/renderer/renderers/toggleable_heading.py +78 -0
  152. notionary/page/content/renderer/renderers/video.py +31 -0
  153. notionary/page/content/renderer/service.py +50 -0
  154. notionary/page/content/service.py +65 -0
  155. notionary/page/content/syntax/models.py +68 -0
  156. notionary/page/content/syntax/service.py +453 -0
  157. notionary/page/page_context.py +7 -16
  158. notionary/page/page_http_client.py +15 -0
  159. notionary/page/page_metadata_update_client.py +19 -0
  160. notionary/page/properties/client.py +144 -0
  161. notionary/page/properties/factory.py +26 -0
  162. notionary/page/properties/models.py +307 -0
  163. notionary/page/properties/service.py +257 -0
  164. notionary/page/schemas.py +13 -0
  165. notionary/page/service.py +222 -0
  166. notionary/shared/entity/client.py +29 -0
  167. notionary/shared/entity/dto_parsers.py +53 -0
  168. notionary/shared/entity/entity_metadata_update_client.py +41 -0
  169. notionary/shared/entity/schemas.py +45 -0
  170. notionary/shared/entity/service.py +171 -0
  171. notionary/shared/models/cover.py +20 -0
  172. notionary/shared/models/file.py +21 -0
  173. notionary/shared/models/icon.py +28 -0
  174. notionary/shared/models/parent.py +41 -0
  175. notionary/shared/properties/type.py +30 -0
  176. notionary/user/__init__.py +4 -8
  177. notionary/user/base.py +89 -0
  178. notionary/user/bot.py +70 -0
  179. notionary/user/client.py +22 -111
  180. notionary/user/person.py +41 -0
  181. notionary/user/schemas.py +67 -0
  182. notionary/user/service.py +65 -0
  183. notionary/utils/async_retry.py +39 -0
  184. notionary/utils/date.py +51 -0
  185. notionary/utils/fuzzy.py +56 -0
  186. notionary/{util/logging_mixin.py → utils/mixins/logging.py} +4 -16
  187. notionary/utils/pagination.py +50 -0
  188. notionary/utils/singleton.py +13 -0
  189. notionary/utils/uuid_utils.py +20 -0
  190. notionary/workspace/__init__.py +3 -0
  191. notionary/workspace/client.py +62 -0
  192. notionary/workspace/query/builder.py +60 -0
  193. notionary/workspace/query/models.py +60 -0
  194. notionary/workspace/query/service.py +93 -0
  195. notionary/workspace/schemas.py +21 -0
  196. notionary/workspace/service.py +116 -0
  197. {notionary-0.2.26.dist-info → notionary-0.2.28.dist-info}/METADATA +54 -49
  198. notionary-0.2.28.dist-info/RECORD +200 -0
  199. {notionary-0.2.26.dist-info → notionary-0.2.28.dist-info}/WHEEL +1 -1
  200. {notionary-0.2.26.dist-info → notionary-0.2.28.dist-info/licenses}/LICENSE +9 -9
  201. notionary/base_notion_client.py +0 -219
  202. notionary/blocks/__init__.py +0 -5
  203. notionary/blocks/_bootstrap.py +0 -271
  204. notionary/blocks/audio/__init__.py +0 -11
  205. notionary/blocks/audio/audio_element.py +0 -158
  206. notionary/blocks/audio/audio_markdown_node.py +0 -24
  207. notionary/blocks/audio/audio_models.py +0 -10
  208. notionary/blocks/base_block_element.py +0 -42
  209. notionary/blocks/bookmark/__init__.py +0 -12
  210. notionary/blocks/bookmark/bookmark_element.py +0 -83
  211. notionary/blocks/bookmark/bookmark_markdown_node.py +0 -28
  212. notionary/blocks/bookmark/bookmark_models.py +0 -15
  213. notionary/blocks/breadcrumbs/__init__.py +0 -15
  214. notionary/blocks/breadcrumbs/breadcrumb_element.py +0 -39
  215. notionary/blocks/breadcrumbs/breadcrumb_markdown_node.py +0 -13
  216. notionary/blocks/breadcrumbs/breadcrumb_models.py +0 -12
  217. notionary/blocks/bulleted_list/__init__.py +0 -15
  218. notionary/blocks/bulleted_list/bulleted_list_element.py +0 -74
  219. notionary/blocks/bulleted_list/bulleted_list_markdown_node.py +0 -20
  220. notionary/blocks/bulleted_list/bulleted_list_models.py +0 -17
  221. notionary/blocks/callout/__init__.py +0 -12
  222. notionary/blocks/callout/callout_element.py +0 -99
  223. notionary/blocks/callout/callout_markdown_node.py +0 -19
  224. notionary/blocks/callout/callout_models.py +0 -33
  225. notionary/blocks/child_database/__init__.py +0 -14
  226. notionary/blocks/child_database/child_database_element.py +0 -59
  227. notionary/blocks/child_database/child_database_models.py +0 -12
  228. notionary/blocks/child_page/__init__.py +0 -9
  229. notionary/blocks/child_page/child_page_element.py +0 -94
  230. notionary/blocks/child_page/child_page_models.py +0 -12
  231. notionary/blocks/code/__init__.py +0 -11
  232. notionary/blocks/code/code_element.py +0 -149
  233. notionary/blocks/code/code_markdown_node.py +0 -80
  234. notionary/blocks/code/code_models.py +0 -94
  235. notionary/blocks/column/__init__.py +0 -25
  236. notionary/blocks/column/column_element.py +0 -65
  237. notionary/blocks/column/column_list_element.py +0 -52
  238. notionary/blocks/column/column_list_markdown_node.py +0 -34
  239. notionary/blocks/column/column_markdown_node.py +0 -42
  240. notionary/blocks/column/column_models.py +0 -26
  241. notionary/blocks/divider/__init__.py +0 -12
  242. notionary/blocks/divider/divider_element.py +0 -41
  243. notionary/blocks/divider/divider_markdown_node.py +0 -11
  244. notionary/blocks/divider/divider_models.py +0 -12
  245. notionary/blocks/embed/__init__.py +0 -12
  246. notionary/blocks/embed/embed_element.py +0 -98
  247. notionary/blocks/embed/embed_markdown_node.py +0 -19
  248. notionary/blocks/embed/embed_models.py +0 -14
  249. notionary/blocks/equation/__init__.py +0 -13
  250. notionary/blocks/equation/equation_element.py +0 -133
  251. notionary/blocks/equation/equation_element_markdown_node.py +0 -23
  252. notionary/blocks/equation/equation_models.py +0 -11
  253. notionary/blocks/file/__init__.py +0 -23
  254. notionary/blocks/file/file_element.py +0 -133
  255. notionary/blocks/file/file_element_markdown_node.py +0 -24
  256. notionary/blocks/file/file_element_models.py +0 -39
  257. notionary/blocks/heading/__init__.py +0 -19
  258. notionary/blocks/heading/heading_element.py +0 -112
  259. notionary/blocks/heading/heading_markdown_node.py +0 -16
  260. notionary/blocks/heading/heading_models.py +0 -29
  261. notionary/blocks/image_block/__init__.py +0 -11
  262. notionary/blocks/image_block/image_element.py +0 -130
  263. notionary/blocks/image_block/image_markdown_node.py +0 -25
  264. notionary/blocks/image_block/image_models.py +0 -10
  265. notionary/blocks/markdown/markdown_builder.py +0 -525
  266. notionary/blocks/markdown/markdown_document_model.py +0 -0
  267. notionary/blocks/markdown/markdown_node.py +0 -25
  268. notionary/blocks/mixins/captions/__init__.py +0 -4
  269. notionary/blocks/mixins/captions/caption_markdown_node_mixin.py +0 -31
  270. notionary/blocks/mixins/captions/caption_mixin.py +0 -92
  271. notionary/blocks/mixins/file_upload/__init__.py +0 -3
  272. notionary/blocks/mixins/file_upload/file_upload_mixin.py +0 -320
  273. notionary/blocks/models.py +0 -174
  274. notionary/blocks/numbered_list/__init__.py +0 -16
  275. notionary/blocks/numbered_list/numbered_list_element.py +0 -65
  276. notionary/blocks/numbered_list/numbered_list_markdown_node.py +0 -17
  277. notionary/blocks/numbered_list/numbered_list_models.py +0 -17
  278. notionary/blocks/paragraph/__init__.py +0 -15
  279. notionary/blocks/paragraph/paragraph_element.py +0 -58
  280. notionary/blocks/paragraph/paragraph_markdown_node.py +0 -16
  281. notionary/blocks/paragraph/paragraph_models.py +0 -16
  282. notionary/blocks/pdf/__init__.py +0 -11
  283. notionary/blocks/pdf/pdf_element.py +0 -146
  284. notionary/blocks/pdf/pdf_markdown_node.py +0 -24
  285. notionary/blocks/pdf/pdf_models.py +0 -11
  286. notionary/blocks/quote/__init__.py +0 -14
  287. notionary/blocks/quote/quote_element.py +0 -75
  288. notionary/blocks/quote/quote_markdown_node.py +0 -16
  289. notionary/blocks/quote/quote_models.py +0 -18
  290. notionary/blocks/registry/__init__.py +0 -3
  291. notionary/blocks/registry/block_registry.py +0 -150
  292. notionary/blocks/rich_text/__init__.py +0 -33
  293. notionary/blocks/rich_text/rich_text_models.py +0 -221
  294. notionary/blocks/rich_text/text_inline_formatter.py +0 -456
  295. notionary/blocks/syntax_prompt_builder.py +0 -137
  296. notionary/blocks/table/__init__.py +0 -19
  297. notionary/blocks/table/table_element.py +0 -225
  298. notionary/blocks/table/table_markdown_node.py +0 -42
  299. notionary/blocks/table/table_models.py +0 -28
  300. notionary/blocks/table_of_contents/__init__.py +0 -17
  301. notionary/blocks/table_of_contents/table_of_contents_element.py +0 -80
  302. notionary/blocks/table_of_contents/table_of_contents_markdown_node.py +0 -21
  303. notionary/blocks/table_of_contents/table_of_contents_models.py +0 -18
  304. notionary/blocks/todo/__init__.py +0 -12
  305. notionary/blocks/todo/todo_element.py +0 -81
  306. notionary/blocks/todo/todo_markdown_node.py +0 -21
  307. notionary/blocks/todo/todo_models.py +0 -18
  308. notionary/blocks/toggle/__init__.py +0 -12
  309. notionary/blocks/toggle/toggle_element.py +0 -112
  310. notionary/blocks/toggle/toggle_markdown_node.py +0 -31
  311. notionary/blocks/toggle/toggle_models.py +0 -17
  312. notionary/blocks/toggleable_heading/__init__.py +0 -11
  313. notionary/blocks/toggleable_heading/toggleable_heading_element.py +0 -115
  314. notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +0 -34
  315. notionary/blocks/types.py +0 -130
  316. notionary/blocks/video/__init__.py +0 -11
  317. notionary/blocks/video/video_element.py +0 -187
  318. notionary/blocks/video/video_element_models.py +0 -10
  319. notionary/blocks/video/video_markdown_node.py +0 -26
  320. notionary/comments/__init__.py +0 -26
  321. notionary/database/__init__.py +0 -4
  322. notionary/database/database.py +0 -480
  323. notionary/database/database_filter_builder.py +0 -173
  324. notionary/database/database_provider.py +0 -227
  325. notionary/database/exceptions.py +0 -13
  326. notionary/database/factory.py +0 -0
  327. notionary/database/models.py +0 -337
  328. notionary/database/notion_database.py +0 -487
  329. notionary/file_upload/__init__.py +0 -7
  330. notionary/page/client.py +0 -124
  331. notionary/page/markdown_whitespace_processor.py +0 -129
  332. notionary/page/models.py +0 -322
  333. notionary/page/notion_page.py +0 -674
  334. notionary/page/page_content_deleting_service.py +0 -117
  335. notionary/page/page_content_writer.py +0 -80
  336. notionary/page/property_formatter.py +0 -99
  337. notionary/page/reader/handler/__init__.py +0 -19
  338. notionary/page/reader/handler/base_block_renderer.py +0 -44
  339. notionary/page/reader/handler/block_processing_context.py +0 -35
  340. notionary/page/reader/handler/block_rendering_context.py +0 -48
  341. notionary/page/reader/handler/column_list_renderer.py +0 -51
  342. notionary/page/reader/handler/column_renderer.py +0 -60
  343. notionary/page/reader/handler/equation_renderer.py +0 -0
  344. notionary/page/reader/handler/line_renderer.py +0 -73
  345. notionary/page/reader/handler/numbered_list_renderer.py +0 -85
  346. notionary/page/reader/handler/toggle_renderer.py +0 -69
  347. notionary/page/reader/handler/toggleable_heading_renderer.py +0 -89
  348. notionary/page/reader/page_content_retriever.py +0 -81
  349. notionary/page/search_filter_builder.py +0 -132
  350. notionary/page/utils.py +0 -60
  351. notionary/page/writer/handler/__init__.py +0 -24
  352. notionary/page/writer/handler/code_handler.py +0 -72
  353. notionary/page/writer/handler/column_handler.py +0 -141
  354. notionary/page/writer/handler/column_list_handler.py +0 -139
  355. notionary/page/writer/handler/equation_handler.py +0 -74
  356. notionary/page/writer/handler/line_handler.py +0 -35
  357. notionary/page/writer/handler/line_processing_context.py +0 -54
  358. notionary/page/writer/handler/regular_line_handler.py +0 -86
  359. notionary/page/writer/handler/table_handler.py +0 -66
  360. notionary/page/writer/handler/toggle_handler.py +0 -159
  361. notionary/page/writer/handler/toggleable_heading_handler.py +0 -174
  362. notionary/page/writer/markdown_to_notion_converter.py +0 -139
  363. notionary/page/writer/markdown_to_notion_converter_context.py +0 -30
  364. notionary/page/writer/markdown_to_notion_text_length_post_processor.py +0 -0
  365. notionary/page/writer/notion_text_length_processor.py +0 -150
  366. notionary/schemas/__init__.py +0 -3
  367. notionary/schemas/base.py +0 -73
  368. notionary/shared/__init__.py +0 -3
  369. notionary/shared/name_to_id_resolver.py +0 -203
  370. notionary/telemetry/__init__.py +0 -19
  371. notionary/telemetry/service.py +0 -136
  372. notionary/telemetry/views.py +0 -73
  373. notionary/user/base_notion_user.py +0 -53
  374. notionary/user/models.py +0 -84
  375. notionary/user/notion_bot_user.py +0 -226
  376. notionary/user/notion_user.py +0 -255
  377. notionary/user/notion_user_manager.py +0 -101
  378. notionary/util/__init__.py +0 -15
  379. notionary/util/concurrency_limiter.py +0 -0
  380. notionary/util/factory_decorator.py +0 -0
  381. notionary/util/factory_only.py +0 -37
  382. notionary/util/fuzzy.py +0 -75
  383. notionary/util/page_id_utils.py +0 -27
  384. notionary/util/singleton.py +0 -18
  385. notionary/util/singleton_metaclass.py +0 -22
  386. notionary/workspace.py +0 -105
  387. notionary-0.2.26.dist-info/RECORD +0 -202
@@ -1,137 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from dataclasses import dataclass
4
- from textwrap import dedent
5
- from typing import TYPE_CHECKING, Optional
6
-
7
-
8
- if TYPE_CHECKING:
9
- from notionary.blocks.registry.block_registry import BlockRegistry
10
-
11
-
12
- @dataclass
13
- class BlockElementMarkdownInformation:
14
- """Metadata describing how a Notion block maps to Markdown syntax."""
15
-
16
- block_type: str
17
- description: str
18
- syntax_examples: list[str]
19
- usage_guidelines: str
20
-
21
-
22
- class SyntaxPromptBuilder:
23
- """
24
- Builds a comprehensive markdown syntax reference from a block registry.
25
- Iterates over all registered elements and collects their system prompt information.
26
- """
27
-
28
- def __init__(self, block_registry: BlockRegistry):
29
- self.block_registry = block_registry
30
-
31
- def build_markdown_reference(self) -> str:
32
- """
33
- Build a complete markdown syntax reference string.
34
- """
35
- sections = [
36
- self._build_header(),
37
- *self._build_element_sections(),
38
- ]
39
-
40
- return "\n\n".join(sections)
41
-
42
- def build_concise_reference(self) -> str:
43
- """
44
- Build a more concise reference suitable for system prompts.
45
- """
46
- lines = ["# Notionary Markdown Syntax"]
47
-
48
- for element_class in self.block_registry.get_elements():
49
- info: Optional[BlockElementMarkdownInformation] = (
50
- element_class.get_system_prompt_information()
51
- )
52
- if info and info.syntax_examples:
53
- # Just show the first example for conciseness
54
- example = info.syntax_examples[0]
55
- lines.append(f"- {info.block_type}: `{example}`")
56
-
57
- return "\n".join(lines)
58
-
59
- def get_blocks_with_information(self) -> list[str]:
60
- """Get list of block names that provide system prompt information."""
61
- blocks = []
62
-
63
- for element_class in self.block_registry.get_elements():
64
- info: Optional[BlockElementMarkdownInformation] = (
65
- element_class.get_system_prompt_information()
66
- )
67
- if info:
68
- blocks.append(info.block_type)
69
-
70
- return blocks
71
-
72
- def _build_header(self) -> str:
73
- """Build the header section of the reference."""
74
- return dedent(
75
- """
76
- # Notionary Markdown Syntax Reference
77
-
78
- This comprehensive reference documents all supported markdown syntax for converting between Markdown and Notion blocks.
79
-
80
- Each block type includes:
81
- - **Description:** What the block does
82
- - **When to use:** Guidelines for appropriate usage
83
- - **Syntax:** Complete syntax examples with variations
84
- """
85
- ).strip()
86
-
87
- def _build_element_sections(self) -> list[str]:
88
- """Build sections for all registered elements."""
89
- sections = []
90
-
91
- for element_class in self.block_registry.get_elements():
92
- info = element_class.get_system_prompt_information()
93
- if info:
94
- sections.append(self._build_element_section(info))
95
-
96
- return sections
97
-
98
- def _build_element_section(self, info: BlockElementMarkdownInformation) -> str:
99
- """Build a well-structured section for a single block element."""
100
- section_parts = [
101
- f"## {info.block_type}",
102
- "",
103
- f"**Description:** {info.description}",
104
- "",
105
- ]
106
-
107
- if info.usage_guidelines:
108
- section_parts.extend(["**When to use:**", info.usage_guidelines, ""])
109
-
110
- if info.syntax_examples:
111
- section_parts.extend(
112
- [
113
- "**Syntax:**",
114
- "",
115
- *self._format_syntax_examples(info.syntax_examples),
116
- "",
117
- ]
118
- )
119
-
120
- return "\n".join(section_parts).rstrip()
121
-
122
- def _format_syntax_examples(self, examples: list[str]) -> list[str]:
123
- """Format syntax examples with proper markdown and clear structure."""
124
- formatted = []
125
-
126
- for i, example in enumerate(examples, 1):
127
- if len(examples) > 1:
128
- formatted.append(f"**Example {i}:**")
129
-
130
- if "\n" in example:
131
- # Multi-line example - use code block
132
- formatted.extend(["```", example, "```", ""])
133
- else:
134
- # Single line - use inline code with description
135
- formatted.extend([f"`{example}`", ""])
136
-
137
- return formatted
@@ -1,19 +0,0 @@
1
- from notionary.blocks.table.table_element import TableElement
2
- from notionary.blocks.table.table_markdown_node import (
3
- TableMarkdownNode,
4
- )
5
- from notionary.blocks.table.table_models import (
6
- CreateTableBlock,
7
- CreateTableRowBlock,
8
- TableBlock,
9
- TableRowBlock,
10
- )
11
-
12
- __all__ = [
13
- "TableElement",
14
- "TableBlock",
15
- "TableRowBlock",
16
- "CreateTableRowBlock",
17
- "CreateTableBlock",
18
- "TableMarkdownNode",
19
- ]
@@ -1,225 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import re
4
- from typing import Optional
5
-
6
- from notionary.blocks.base_block_element import BaseBlockElement
7
- from notionary.blocks.syntax_prompt_builder import BlockElementMarkdownInformation
8
- from notionary.blocks.models import Block, BlockCreateResult
9
- from notionary.blocks.rich_text.rich_text_models import RichTextObject
10
- from notionary.blocks.rich_text.text_inline_formatter import TextInlineFormatter
11
- from notionary.blocks.table.table_models import (
12
- CreateTableBlock,
13
- TableBlock,
14
- CreateTableRowBlock,
15
- TableRowBlock,
16
- )
17
- from notionary.blocks.types import BlockType
18
-
19
-
20
- class TableElement(BaseBlockElement):
21
- """
22
- Handles conversion between Markdown tables and Notion table blocks.
23
- Now integrated into the LineProcessor stack system.
24
-
25
- Markdown table syntax:
26
- | Header 1 | Header 2 | Header 3 |
27
- | -------- | -------- | -------- |
28
- | Cell 1 | Cell 2 | Cell 3 |
29
- """
30
-
31
- ROW_PATTERN = re.compile(r"^\s*\|(.+)\|\s*$")
32
- SEPARATOR_PATTERN = re.compile(r"^\s*\|([\s\-:|]+)\|\s*$")
33
-
34
- @classmethod
35
- def match_notion(cls, block: Block) -> bool:
36
- """Check if block is a Notion table."""
37
- return block.type == BlockType.TABLE and block.table
38
-
39
- @classmethod
40
- async def markdown_to_notion(cls, text: str) -> BlockCreateResult:
41
- """Convert opening table row to Notion table block."""
42
- if not cls.ROW_PATTERN.match(text.strip()):
43
- return None
44
-
45
- # Parse the header row to determine column count
46
- header_cells = cls._parse_table_row(text)
47
- col_count = len(header_cells)
48
-
49
- table_block = TableBlock(
50
- table_width=col_count,
51
- has_column_header=True,
52
- has_row_header=False,
53
- children=[], # Will be populated by stack processor
54
- )
55
-
56
- return CreateTableBlock(table=table_block)
57
-
58
- @classmethod
59
- async def create_from_markdown_table(
60
- cls, table_lines: list[str]
61
- ) -> BlockCreateResult:
62
- """
63
- Create a complete table block from markdown table lines.
64
- """
65
- if not table_lines:
66
- return None
67
-
68
- first_row = None
69
- for line in table_lines:
70
- line = line.strip()
71
- if line and cls.ROW_PATTERN.match(line):
72
- first_row = line
73
- break
74
-
75
- if not first_row:
76
- return None
77
-
78
- # Parse header row to determine column count
79
- header_cells = cls._parse_table_row(first_row)
80
- col_count = len(header_cells)
81
-
82
- # Process all table lines
83
- table_rows, separator_found = await cls._process_table_lines(table_lines)
84
-
85
- # Create complete TableBlock
86
- table_block = TableBlock(
87
- table_width=col_count,
88
- has_column_header=separator_found,
89
- has_row_header=False,
90
- children=table_rows,
91
- )
92
-
93
- return CreateTableBlock(table=table_block)
94
-
95
- @classmethod
96
- async def _process_table_lines(
97
- cls, table_lines: list[str]
98
- ) -> tuple[list[CreateTableRowBlock], bool]:
99
- """Process all table lines and return rows and separator status."""
100
- table_rows = []
101
- separator_found = False
102
-
103
- for line in table_lines:
104
- line = line.strip()
105
- if not line:
106
- continue
107
-
108
- if cls._is_separator_line(line):
109
- separator_found = True
110
- continue
111
-
112
- if cls.ROW_PATTERN.match(line):
113
- table_row = await cls._create_table_row_from_line(line)
114
- table_rows.append(table_row)
115
-
116
- return table_rows, separator_found
117
-
118
- @classmethod
119
- def _is_separator_line(cls, line: str) -> bool:
120
- """Check if line is a table separator (|---|---|)."""
121
- return cls.SEPARATOR_PATTERN.match(line) is not None
122
-
123
- @classmethod
124
- async def _create_table_row_from_line(cls, line: str) -> CreateTableRowBlock:
125
- """Create a table row block from a markdown line."""
126
- cells = cls._parse_table_row(line)
127
- rich_text_cells = []
128
- for cell in cells:
129
- rich_text_cell = await cls._convert_cell_to_rich_text(cell)
130
- rich_text_cells.append(rich_text_cell)
131
- table_row = TableRowBlock(cells=rich_text_cells)
132
- return CreateTableRowBlock(table_row=table_row)
133
-
134
- @classmethod
135
- async def _convert_cell_to_rich_text(cls, cell: str) -> list[RichTextObject]:
136
- """Convert cell text to rich text objects."""
137
- rich_text = await TextInlineFormatter.parse_inline_formatting(cell)
138
- if not rich_text:
139
- rich_text = [RichTextObject.from_plain_text(cell)]
140
- return rich_text
141
-
142
- @classmethod
143
- async def notion_to_markdown(cls, block: Block) -> Optional[str]:
144
- """Convert Notion table block to markdown table."""
145
- if block.type != BlockType.TABLE:
146
- return None
147
-
148
- if not block.table:
149
- return None
150
-
151
- table_data = block.table
152
- children = block.children or []
153
-
154
- if not children:
155
- table_width = table_data.table_width or 3
156
- header = (
157
- "| " + " | ".join([f"Column {i+1}" for i in range(table_width)]) + " |"
158
- )
159
- separator = (
160
- "| " + " | ".join(["--------" for _ in range(table_width)]) + " |"
161
- )
162
- data_row = (
163
- "| " + " | ".join([" " for _ in range(table_width)]) + " |"
164
- )
165
- table_rows = [header, separator, data_row]
166
- return "\n".join(table_rows)
167
-
168
- table_rows = []
169
- header_processed = False
170
-
171
- for child in children:
172
- if child.type != BlockType.TABLE_ROW:
173
- continue
174
-
175
- if not child.table_row:
176
- continue
177
-
178
- row_data = child.table_row
179
- cells = row_data.cells or []
180
-
181
- row_cells = []
182
- for cell in cells:
183
- cell_text = await TextInlineFormatter.extract_text_with_formatting(cell)
184
- row_cells.append(cell_text or "")
185
-
186
- row = "| " + " | ".join(row_cells) + " |"
187
- table_rows.append(row)
188
-
189
- if not header_processed and table_data.has_column_header:
190
- header_processed = True
191
- separator = (
192
- "| " + " | ".join(["--------" for _ in range(len(cells))]) + " |"
193
- )
194
- table_rows.append(separator)
195
-
196
- return "\n".join(table_rows)
197
-
198
- @classmethod
199
- def _parse_table_row(cls, row_text: str) -> list[str]:
200
- """Convert table row text to cell contents."""
201
- row_content = row_text.strip()
202
-
203
- if row_content.startswith("|"):
204
- row_content = row_content[1:]
205
- if row_content.endswith("|"):
206
- row_content = row_content[:-1]
207
-
208
- return [cell.strip() for cell in row_content.split("|")]
209
-
210
- @classmethod
211
- def is_table_row(cls, line: str) -> bool:
212
- """Check if a line is a valid table row."""
213
- return bool(cls.ROW_PATTERN.match(line.strip()))
214
-
215
- @classmethod
216
- def get_system_prompt_information(cls) -> Optional[BlockElementMarkdownInformation]:
217
- """Get system prompt information for table blocks."""
218
- return BlockElementMarkdownInformation(
219
- block_type=cls.__name__,
220
- description="Table blocks create structured data in rows and columns with headers",
221
- syntax_examples=[
222
- "| Name | Age | City |\n| -------- | -------- | -------- |\n| Alice | 25 | Berlin |\n| Bob | 30 | Munich |"
223
- ],
224
- usage_guidelines="Use for structured data presentation. First row is header, second row is separator with dashes, following rows are data. Cells are separated by | characters.",
225
- )
@@ -1,42 +0,0 @@
1
- from pydantic import field_validator
2
-
3
- from notionary.blocks.markdown.markdown_node import MarkdownNode
4
-
5
-
6
- class TableMarkdownNode(MarkdownNode):
7
- """
8
- Enhanced Table node with Pydantic integration.
9
- Programmatic interface for creating Markdown tables.
10
- Example:
11
- | Header 1 | Header 2 | Header 3 |
12
- | -------- | -------- | -------- |
13
- | Cell 1 | Cell 2 | Cell 3 |
14
- | Cell 4 | Cell 5 | Cell 6 |
15
- """
16
-
17
- headers: list[str]
18
- rows: list[list[str]]
19
-
20
- @field_validator("headers")
21
- @classmethod
22
- def validate_headers(cls, v):
23
- if not v:
24
- raise ValueError("headers must not be empty")
25
- return v
26
-
27
- @field_validator("rows")
28
- @classmethod
29
- def validate_rows(cls, v):
30
- if not all(isinstance(row, list) for row in v):
31
- raise ValueError("rows must be a list of lists")
32
- return v
33
-
34
- def to_markdown(self) -> str:
35
- col_count = len(self.headers)
36
- # Header row
37
- header = "| " + " | ".join(self.headers) + " |"
38
- # Separator row
39
- separator = "| " + " | ".join(["--------"] * col_count) + " |"
40
- # Data rows
41
- data_rows = ["| " + " | ".join(row) + " |" for row in self.rows]
42
- return "\n".join([header, separator] + data_rows)
@@ -1,28 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import Literal
4
-
5
- from pydantic import BaseModel
6
-
7
- from notionary.blocks.rich_text.rich_text_models import RichTextObject
8
-
9
-
10
- class TableBlock(BaseModel):
11
- table_width: int
12
- has_column_header: bool = False
13
- has_row_header: bool = False
14
- children: list[CreateTableRowBlock] = []
15
-
16
-
17
- class TableRowBlock(BaseModel):
18
- cells: list[list[RichTextObject]]
19
-
20
-
21
- class CreateTableRowBlock(BaseModel):
22
- type: Literal["table_row"] = "table_row"
23
- table_row: TableRowBlock
24
-
25
-
26
- class CreateTableBlock(BaseModel):
27
- type: Literal["table"] = "table"
28
- table: TableBlock
@@ -1,17 +0,0 @@
1
- from notionary.blocks.table_of_contents.table_of_contents_element import (
2
- TableOfContentsElement,
3
- )
4
- from notionary.blocks.table_of_contents.table_of_contents_markdown_node import (
5
- TableOfContentsMarkdownNode,
6
- )
7
- from notionary.blocks.table_of_contents.table_of_contents_models import (
8
- CreateTableOfContentsBlock,
9
- TableOfContentsBlock,
10
- )
11
-
12
- __all__ = [
13
- "TableOfContentsElement",
14
- "TableOfContentsBlock",
15
- "CreateTableOfContentsBlock",
16
- "TableOfContentsMarkdownNode",
17
- ]
@@ -1,80 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import re
4
- from typing import Optional
5
-
6
- from notionary.blocks.base_block_element import BaseBlockElement
7
- from notionary.blocks.syntax_prompt_builder import BlockElementMarkdownInformation
8
- from notionary.blocks.models import Block, BlockCreateResult
9
- from notionary.blocks.table_of_contents.table_of_contents_models import (
10
- CreateTableOfContentsBlock,
11
- TableOfContentsBlock,
12
- )
13
- from notionary.blocks.types import BlockType, BlockColor
14
-
15
-
16
- class TableOfContentsElement(BaseBlockElement):
17
- """
18
- Handles conversion between Markdown [toc] syntax and Notion table_of_contents blocks.
19
-
20
- Markdown syntax:
21
- - [toc] → default color (enum default)
22
- - [toc](blue) → custom color
23
- - [toc](blue_background) → custom background color
24
- """
25
-
26
- PATTERN = re.compile(r"^\[toc\](?:\((?P<color>[a-z_]+)\))?$", re.IGNORECASE)
27
-
28
- @classmethod
29
- def match_notion(cls, block: Block) -> bool:
30
- return block.type == BlockType.TABLE_OF_CONTENTS and block.table_of_contents
31
-
32
- @classmethod
33
- async def markdown_to_notion(cls, text: str) -> BlockCreateResult:
34
- if not (input_match := cls.PATTERN.match(text.strip())):
35
- return None
36
-
37
- color_str = input_match.group("color")
38
- if color_str:
39
- # Validate against the enum; fallback to default if unknown
40
- try:
41
- color = BlockColor(color_str.lower())
42
- toc_payload = TableOfContentsBlock(color=color)
43
- except ValueError:
44
- # Unknown color → omit to use enum default
45
- toc_payload = TableOfContentsBlock()
46
- else:
47
- # No color provided → omit to let enum default apply
48
- toc_payload = TableOfContentsBlock()
49
-
50
- return CreateTableOfContentsBlock(table_of_contents=toc_payload)
51
-
52
- @classmethod
53
- async def notion_to_markdown(cls, block: Block) -> Optional[str]:
54
- # Correct guard: if not a TOC or missing payload → no match
55
- if block.type != BlockType.TABLE_OF_CONTENTS or not block.table_of_contents:
56
- return None
57
-
58
- color = block.table_of_contents.color
59
- # If None or default → plain [toc]
60
- if color is None or color == BlockColor.DEFAULT:
61
- return "[toc]"
62
- return f"[toc]({color.value})"
63
-
64
- @classmethod
65
- def get_system_prompt_information(cls) -> Optional[BlockElementMarkdownInformation]:
66
- """System prompt info for table of contents blocks."""
67
- return BlockElementMarkdownInformation(
68
- block_type=cls.__name__,
69
- description="Table of contents blocks automatically generate navigation for page headings.",
70
- syntax_examples=[
71
- "[toc]",
72
- "[toc](blue)",
73
- "[toc](blue_background)",
74
- "[toc](gray_background)",
75
- ],
76
- usage_guidelines=(
77
- "Use to auto-generate a clickable table of contents from page headings. "
78
- "The color parameter is optional; if omitted, the default enum color is used."
79
- ),
80
- )
@@ -1,21 +0,0 @@
1
- from typing import Optional
2
-
3
- from notionary.blocks.markdown.markdown_node import MarkdownNode
4
-
5
-
6
- class TableOfContentsMarkdownNode(MarkdownNode):
7
- """
8
- Enhanced Table of Contents node with Pydantic integration.
9
- Programmatic interface for creating Markdown table of contents blocks.
10
- Example:
11
- [toc]
12
- [toc](blue)
13
- [toc](blue_background)
14
- """
15
-
16
- color: Optional[str] = "default"
17
-
18
- def to_markdown(self) -> str:
19
- if self.color == "default":
20
- return "[toc]"
21
- return f"[toc]({self.color})"
@@ -1,18 +0,0 @@
1
- from typing import Literal, Optional
2
-
3
- from pydantic import BaseModel
4
-
5
- from notionary.blocks.types import BlockColor
6
-
7
-
8
- class TableOfContentsBlock(BaseModel):
9
- """Inneres Payload-Objekt: { table_of_contents: { color: ... } }"""
10
-
11
- color: Optional[BlockColor] = BlockColor.DEFAULT
12
-
13
-
14
- class CreateTableOfContentsBlock(BaseModel):
15
- """Create-Payload für den Block: { type: 'table_of_contents', table_of_contents: {...} }"""
16
-
17
- type: Literal["table_of_contents"] = "table_of_contents"
18
- table_of_contents: TableOfContentsBlock
@@ -1,12 +0,0 @@
1
- from notionary.blocks.todo.todo_element import TodoElement
2
- from notionary.blocks.todo.todo_markdown_node import (
3
- TodoMarkdownNode,
4
- )
5
- from notionary.blocks.todo.todo_models import CreateToDoBlock, ToDoBlock
6
-
7
- __all__ = [
8
- "TodoElement",
9
- "ToDoBlock",
10
- "CreateToDoBlock",
11
- "TodoMarkdownNode",
12
- ]
@@ -1,81 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import re
4
- from typing import TYPE_CHECKING, Optional
5
-
6
- from notionary.blocks.base_block_element import BaseBlockElement
7
- from notionary.blocks.syntax_prompt_builder import BlockElementMarkdownInformation
8
- from notionary.blocks.models import Block, BlockCreateResult, BlockType
9
- from notionary.blocks.rich_text.text_inline_formatter import TextInlineFormatter
10
- from notionary.blocks.todo.todo_models import CreateToDoBlock, ToDoBlock
11
-
12
-
13
- class TodoElement(BaseBlockElement):
14
- """
15
- Handles conversion between Markdown todo items and Notion to_do blocks.
16
-
17
- Markdown syntax examples:
18
- - [ ] Unchecked todo item
19
- - [x] Checked todo item
20
- * [ ] Also works with asterisk
21
- + [ ] Also works with plus sign
22
- """
23
-
24
- PATTERN = re.compile(r"^\s*[-*+]\s+\[ \]\s+(.+)$")
25
- DONE_PATTERN = re.compile(r"^\s*[-*+]\s+\[x\]\s+(.+)$", re.IGNORECASE)
26
-
27
- @classmethod
28
- def match_notion(cls, block: Block) -> bool:
29
- return block.type == BlockType.TO_DO and block.to_do
30
-
31
- @classmethod
32
- async def markdown_to_notion(cls, text: str) -> BlockCreateResult:
33
- """Convert markdown todo or done item to Notion to_do block."""
34
- m_done = cls.DONE_PATTERN.match(text)
35
- m_todo = None if m_done else cls.PATTERN.match(text)
36
-
37
- if m_done:
38
- content = m_done.group(1)
39
- checked = True
40
- elif m_todo:
41
- content = m_todo.group(1)
42
- checked = False
43
- else:
44
- return None
45
-
46
- # build rich text
47
- rich = await TextInlineFormatter.parse_inline_formatting(content)
48
-
49
- todo_content = ToDoBlock(
50
- rich_text=rich,
51
- checked=checked,
52
- color="default",
53
- )
54
- return CreateToDoBlock(to_do=todo_content)
55
-
56
- @classmethod
57
- async def notion_to_markdown(cls, block: Block) -> Optional[str]:
58
- """Convert Notion to_do block to markdown todo item."""
59
- if block.type != BlockType.TO_DO or not block.to_do:
60
- return None
61
-
62
- td = block.to_do
63
- content = await TextInlineFormatter.extract_text_with_formatting(td.rich_text)
64
- checkbox = "[x]" if td.checked else "[ ]"
65
- return f"- {checkbox} {content}"
66
-
67
- @classmethod
68
- def get_system_prompt_information(cls) -> Optional[BlockElementMarkdownInformation]:
69
- """Get system prompt information for todo blocks."""
70
- return BlockElementMarkdownInformation(
71
- block_type=cls.__name__,
72
- description="Todo blocks create interactive checkboxes for task management",
73
- syntax_examples=[
74
- "- [ ] Unchecked todo item",
75
- "- [x] Checked todo item",
76
- "* [ ] Todo with asterisk",
77
- "+ [ ] Todo with plus sign",
78
- "- [x] Completed task",
79
- ],
80
- usage_guidelines="Use for task lists and checkboxes. [ ] for unchecked, [x] for checked items. Supports -, *, or + as bullet markers. Interactive in Notion interface.",
81
- )