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
@@ -0,0 +1,31 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.schemas import Block, BlockType
4
+ from notionary.page.content.renderer.renderers.captioned_block import CaptionedBlockRenderer
5
+
6
+
7
+ class VideoRenderer(CaptionedBlockRenderer):
8
+ @override
9
+ def _can_handle(self, block: Block) -> bool:
10
+ return block.type == BlockType.VIDEO
11
+
12
+ @override
13
+ async def _render_main_content(self, block: Block) -> str:
14
+ url = self._extract_video_url(block)
15
+
16
+ if not url:
17
+ return ""
18
+
19
+ syntax = self._syntax_registry.get_video_syntax()
20
+ return f"{syntax.start_delimiter}{url}{syntax.end_delimiter}"
21
+
22
+ def _extract_video_url(self, block: Block) -> str:
23
+ if not block.video:
24
+ return ""
25
+
26
+ if block.video.external:
27
+ return block.video.external.url or ""
28
+ elif block.video.file:
29
+ return block.video.file.url or ""
30
+
31
+ return ""
@@ -0,0 +1,50 @@
1
+ from notionary.blocks.schemas import Block
2
+ from notionary.page.content.renderer.context import MarkdownRenderingContext
3
+ from notionary.page.content.renderer.post_processing.service import MarkdownRenderingPostProcessor
4
+ from notionary.page.content.renderer.renderers import BlockRenderer
5
+ from notionary.utils.mixins.logging import LoggingMixin
6
+
7
+
8
+ class NotionToMarkdownConverter(LoggingMixin):
9
+ def __init__(
10
+ self,
11
+ renderer_chain: BlockRenderer,
12
+ post_processor: MarkdownRenderingPostProcessor,
13
+ ) -> None:
14
+ self._renderer_chain = renderer_chain
15
+ self._post_processor = post_processor
16
+
17
+ async def convert(self, blocks: list[Block], indent_level: int = 0) -> str:
18
+ if not blocks:
19
+ return ""
20
+
21
+ rendered_block_parts = []
22
+ current_block_index = 0
23
+
24
+ while current_block_index < len(blocks):
25
+ context = self._create_rendering_context(blocks, current_block_index, indent_level)
26
+ await self._renderer_chain.handle(context)
27
+
28
+ if context.markdown_result:
29
+ rendered_block_parts.append(context.markdown_result)
30
+
31
+ current_block_index += 1
32
+
33
+ result = self._join_rendered_blocks(rendered_block_parts, indent_level)
34
+ result = self._post_processor.process(result)
35
+
36
+ return result
37
+
38
+ def _create_rendering_context(
39
+ self, blocks: list[Block], block_index: int, indent_level: int
40
+ ) -> MarkdownRenderingContext:
41
+ block = blocks[block_index]
42
+ return MarkdownRenderingContext(
43
+ block=block,
44
+ indent_level=indent_level,
45
+ convert_children_callback=self.convert,
46
+ )
47
+
48
+ def _join_rendered_blocks(self, rendered_parts: list[str], indent_level: int) -> str:
49
+ separator = "\n\n" if indent_level == 0 else "\n"
50
+ return separator.join(rendered_parts)
@@ -0,0 +1,65 @@
1
+ import asyncio
2
+ from collections.abc import Callable
3
+
4
+ from notionary.blocks.client import NotionBlockHttpClient
5
+ from notionary.blocks.schemas import Block
6
+ from notionary.page.content.markdown.builder import MarkdownBuilder
7
+ from notionary.page.content.parser.service import MarkdownToNotionConverter
8
+ from notionary.page.content.renderer.service import NotionToMarkdownConverter
9
+ from notionary.utils.async_retry import async_retry
10
+ from notionary.utils.mixins.logging import LoggingMixin
11
+
12
+
13
+ class PageContentService(LoggingMixin):
14
+ def __init__(
15
+ self,
16
+ page_id: str,
17
+ block_client: NotionBlockHttpClient,
18
+ markdown_converter: MarkdownToNotionConverter,
19
+ notion_to_markdown_converter: NotionToMarkdownConverter,
20
+ ) -> None:
21
+ self._page_id = page_id
22
+ self._block_client = block_client
23
+ self._markdown_converter = markdown_converter
24
+ self._notion_to_markdown_converter = notion_to_markdown_converter
25
+
26
+ async def get_as_markdown(self) -> str:
27
+ blocks = await self._block_client.get_block_tree(parent_block_id=self._page_id)
28
+ return await self._notion_to_markdown_converter.convert(blocks=blocks)
29
+
30
+ async def clear(self) -> None:
31
+ children_response = await self._block_client.get_block_children(block_id=self._page_id)
32
+
33
+ if not children_response or not children_response.results:
34
+ self.logger.debug("No blocks to delete for page: %s", self._page_id)
35
+ return
36
+
37
+ await asyncio.gather(*[self._delete_single_block(block) for block in children_response.results])
38
+
39
+ @async_retry(max_retries=10, initial_delay=0.2, backoff_factor=1.5)
40
+ async def _delete_single_block(self, block: Block) -> None:
41
+ self.logger.debug("Deleting block: %s", block.id)
42
+ await self._block_client.delete_block(block.id)
43
+
44
+ async def append_markdown(self, content: str | Callable[[MarkdownBuilder], MarkdownBuilder]) -> None:
45
+ markdown = self._extract_markdown(content)
46
+ if not markdown:
47
+ self.logger.debug("No markdown content to append for page: %s", self._page_id)
48
+ return
49
+
50
+ blocks = await self._markdown_converter.convert(markdown)
51
+ await self._append_blocks(blocks)
52
+
53
+ def _extract_markdown(self, content: str | Callable[[MarkdownBuilder], MarkdownBuilder]) -> str:
54
+ if isinstance(content, str):
55
+ return content
56
+
57
+ if callable(content):
58
+ builder = MarkdownBuilder()
59
+ content(builder)
60
+ return builder.build()
61
+
62
+ raise ValueError("content must be either a string or a callable that takes a MarkdownBuilder")
63
+
64
+ async def _append_blocks(self, blocks: list[Block]) -> None:
65
+ await self._block_client.append_block_children(block_id=self._page_id, children=blocks)
@@ -0,0 +1,68 @@
1
+ import re
2
+ from dataclasses import dataclass
3
+ from enum import StrEnum
4
+
5
+
6
+ class SyntaxRegistryKey(StrEnum):
7
+ AUDIO = "audio"
8
+ BOOKMARK = "bookmark"
9
+ IMAGE = "image"
10
+ VIDEO = "video"
11
+ FILE = "file"
12
+ PDF = "pdf"
13
+
14
+ # List blocks
15
+ BULLETED_LIST = "bulleted_list"
16
+ NUMBERED_LIST = "numbered_list"
17
+ TO_DO = "todo"
18
+ TO_DO_DONE = "todo_done"
19
+
20
+ TOGGLE = "toggle"
21
+ TOGGLEABLE_HEADING = "toggleable_heading"
22
+ CALLOUT = "callout"
23
+ QUOTE = "quote"
24
+ CODE = "code"
25
+
26
+ COLUMN_LIST = "column_list"
27
+ COLUMN = "column"
28
+
29
+ # Heading blocks
30
+ HEADING_1 = "heading_1"
31
+ HEADING_2 = "heading_2"
32
+ HEADING_3 = "heading_3"
33
+ HEADING = "heading" # Shared pattern for regular headings
34
+
35
+ DIVIDER = "divider"
36
+ BREADCRUMB = "breadcrumb"
37
+ TABLE_OF_CONTENTS = "table_of_contents"
38
+ EQUATION = "equation"
39
+ EMBED = "embed"
40
+ TABLE = "table"
41
+ TABLE_ROW = "table_row"
42
+
43
+ CAPTION = "caption"
44
+ SPACE = "space"
45
+
46
+
47
+ # some elemente need closing delimiters, others not
48
+ # either use union type or validate config in service
49
+ @dataclass(frozen=True)
50
+ class SyntaxDefinition:
51
+ """
52
+ Defines the syntax pattern for a block type.
53
+
54
+ Attributes:
55
+ start_delimiter: The opening delimiter (e.g., "```", "+++", ">")
56
+ end_delimiter: The optional closing delimiter (empty string if none)
57
+ regex_pattern: The compiled regex pattern to match this syntax
58
+ end_regex_pattern: Optional compiled regex pattern for end delimiter
59
+ is_multiline_block: Whether this block can contain child blocks
60
+ is_inline: Whether this is an inline syntax (like [audio](url))
61
+ """
62
+
63
+ start_delimiter: str
64
+ end_delimiter: str
65
+ regex_pattern: re.Pattern
66
+ end_regex_pattern: re.Pattern | None = None
67
+ is_multiline_block: bool = False
68
+ is_inline: bool = False
@@ -0,0 +1,453 @@
1
+ import re
2
+
3
+ from notionary.page.content.syntax.models import SyntaxDefinition, SyntaxRegistryKey
4
+
5
+
6
+ class SyntaxRegistry:
7
+ MULTI_LINE_BLOCK_DELIMITER = ":::"
8
+ TOGGLE_DELIMITER = "+++"
9
+ TABLE_DELIMITER = "|"
10
+
11
+ def __init__(self) -> None:
12
+ self._definitions: dict[SyntaxRegistryKey, SyntaxDefinition] = {}
13
+ self._register_defaults()
14
+
15
+ def get_audio_syntax(self) -> SyntaxDefinition:
16
+ return self._definitions[SyntaxRegistryKey.AUDIO]
17
+
18
+ def get_bookmark_syntax(self) -> SyntaxDefinition:
19
+ return self._definitions[SyntaxRegistryKey.BOOKMARK]
20
+
21
+ def get_breadcrumb_syntax(self) -> SyntaxDefinition:
22
+ return self._definitions[SyntaxRegistryKey.BREADCRUMB]
23
+
24
+ def get_bulleted_list_syntax(self) -> SyntaxDefinition:
25
+ return self._definitions[SyntaxRegistryKey.BULLETED_LIST]
26
+
27
+ def get_callout_syntax(self) -> SyntaxDefinition:
28
+ return self._definitions[SyntaxRegistryKey.CALLOUT]
29
+
30
+ def get_code_syntax(self) -> SyntaxDefinition:
31
+ return self._definitions[SyntaxRegistryKey.CODE]
32
+
33
+ def get_column_syntax(self) -> SyntaxDefinition:
34
+ return self._definitions[SyntaxRegistryKey.COLUMN]
35
+
36
+ def get_column_list_syntax(self) -> SyntaxDefinition:
37
+ return self._definitions[SyntaxRegistryKey.COLUMN_LIST]
38
+
39
+ def get_divider_syntax(self) -> SyntaxDefinition:
40
+ return self._definitions[SyntaxRegistryKey.DIVIDER]
41
+
42
+ def get_embed_syntax(self) -> SyntaxDefinition:
43
+ return self._definitions[SyntaxRegistryKey.EMBED]
44
+
45
+ def get_equation_syntax(self) -> SyntaxDefinition:
46
+ return self._definitions[SyntaxRegistryKey.EQUATION]
47
+
48
+ def get_file_syntax(self) -> SyntaxDefinition:
49
+ return self._definitions[SyntaxRegistryKey.FILE]
50
+
51
+ def get_image_syntax(self) -> SyntaxDefinition:
52
+ return self._definitions[SyntaxRegistryKey.IMAGE]
53
+
54
+ def get_numbered_list_syntax(self) -> SyntaxDefinition:
55
+ return self._definitions[SyntaxRegistryKey.NUMBERED_LIST]
56
+
57
+ def get_pdf_syntax(self) -> SyntaxDefinition:
58
+ return self._definitions[SyntaxRegistryKey.PDF]
59
+
60
+ def get_quote_syntax(self) -> SyntaxDefinition:
61
+ return self._definitions[SyntaxRegistryKey.QUOTE]
62
+
63
+ def get_table_syntax(self) -> SyntaxDefinition:
64
+ return self._definitions[SyntaxRegistryKey.TABLE]
65
+
66
+ def get_table_row_syntax(self) -> SyntaxDefinition:
67
+ return self._definitions[SyntaxRegistryKey.TABLE_ROW]
68
+
69
+ def get_table_of_contents_syntax(self) -> SyntaxDefinition:
70
+ return self._definitions[SyntaxRegistryKey.TABLE_OF_CONTENTS]
71
+
72
+ def get_todo_syntax(self) -> SyntaxDefinition:
73
+ return self._definitions[SyntaxRegistryKey.TO_DO]
74
+
75
+ def get_todo_done_syntax(self) -> SyntaxDefinition:
76
+ return self._definitions[SyntaxRegistryKey.TO_DO_DONE]
77
+
78
+ def get_toggle_syntax(self) -> SyntaxDefinition:
79
+ return self._definitions[SyntaxRegistryKey.TOGGLE]
80
+
81
+ def get_toggleable_heading_syntax(self) -> SyntaxDefinition:
82
+ return self._definitions[SyntaxRegistryKey.TOGGLEABLE_HEADING]
83
+
84
+ def get_video_syntax(self) -> SyntaxDefinition:
85
+ return self._definitions[SyntaxRegistryKey.VIDEO]
86
+
87
+ def get_caption_syntax(self) -> SyntaxDefinition:
88
+ return self._definitions[SyntaxRegistryKey.CAPTION]
89
+
90
+ def get_space_syntax(self) -> SyntaxDefinition:
91
+ return self._definitions[SyntaxRegistryKey.SPACE]
92
+
93
+ def get_heading_syntax(self) -> SyntaxDefinition:
94
+ return self._definitions[SyntaxRegistryKey.HEADING]
95
+
96
+ def _register_defaults(self) -> None:
97
+ self._register_audio_syntax()
98
+ self._register_bookmark_syntax()
99
+ self._register_image_syntax()
100
+ self._register_video_syntax()
101
+ self._register_file_syntax()
102
+ self._register_pdf_syntax()
103
+
104
+ # List blocks
105
+ self._register_bulleted_list_syntax()
106
+ self._register_numbered_list_syntax()
107
+ self._register_todo_syntax()
108
+ self._register_todo_done_syntax()
109
+
110
+ # Container blocks
111
+ self._register_toggle_syntax()
112
+ self._register_toggleable_heading_syntax()
113
+ self._register_callout_syntax()
114
+ self._register_quote_syntax()
115
+ self._register_code_syntax()
116
+
117
+ # Column layout blocks
118
+ self._register_column_list_syntax()
119
+ self._register_column_syntax()
120
+
121
+ self._register_heading_1_syntax()
122
+ self._register_heading_2_syntax()
123
+ self._register_heading_3_syntax()
124
+ self._register_heading_syntax() # Shared pattern for regular headings
125
+
126
+ self._register_divider_syntax()
127
+ self._register_breadcrumb_syntax()
128
+ self._register_table_of_contents_syntax()
129
+ self._register_equation_syntax()
130
+ self._register_embed_syntax()
131
+ self._register_table_syntax()
132
+ self._register_table_row_syntax()
133
+
134
+ # Post-processing and utility blocks
135
+ self._register_caption_syntax()
136
+ self._register_space_syntax()
137
+
138
+ def _register_audio_syntax(self) -> None:
139
+ definition = SyntaxDefinition(
140
+ start_delimiter="[audio](",
141
+ end_delimiter=")",
142
+ regex_pattern=re.compile(r"\[audio\]\(([^)]+)\)"),
143
+ is_multiline_block=False,
144
+ is_inline=True,
145
+ )
146
+ self._definitions[SyntaxRegistryKey.AUDIO] = definition
147
+
148
+ def _register_bookmark_syntax(self) -> None:
149
+ definition = SyntaxDefinition(
150
+ start_delimiter="[bookmark](",
151
+ end_delimiter=")",
152
+ regex_pattern=re.compile(r"\[bookmark\]\((https?://[^\s\"]+)\)"),
153
+ is_multiline_block=False,
154
+ is_inline=True,
155
+ )
156
+ self._definitions[SyntaxRegistryKey.BOOKMARK] = definition
157
+
158
+ def _register_breadcrumb_syntax(self) -> None:
159
+ definition = SyntaxDefinition(
160
+ start_delimiter="[breadcrumb]",
161
+ end_delimiter="",
162
+ regex_pattern=re.compile(r"^\[breadcrumb\]\s*$", re.IGNORECASE),
163
+ is_multiline_block=False,
164
+ is_inline=False,
165
+ )
166
+ self._definitions[SyntaxRegistryKey.BREADCRUMB] = definition
167
+
168
+ def _register_bulleted_list_syntax(self) -> None:
169
+ definition = SyntaxDefinition(
170
+ start_delimiter="- ",
171
+ end_delimiter="",
172
+ regex_pattern=re.compile(r"^(\s*)-\s+(?!\[[ xX]\])(.+)$"),
173
+ is_multiline_block=False,
174
+ is_inline=False,
175
+ )
176
+ self._definitions[SyntaxRegistryKey.BULLETED_LIST] = definition
177
+
178
+ def _register_callout_syntax(self) -> None:
179
+ definition = SyntaxDefinition(
180
+ start_delimiter=f"{self.MULTI_LINE_BLOCK_DELIMITER} callout",
181
+ end_delimiter=self.MULTI_LINE_BLOCK_DELIMITER,
182
+ regex_pattern=re.compile(
183
+ rf"^{re.escape(self.MULTI_LINE_BLOCK_DELIMITER)}\s*callout(?:\s+(\S+))?\s*$", re.IGNORECASE
184
+ ),
185
+ end_regex_pattern=re.compile(rf"^{re.escape(self.MULTI_LINE_BLOCK_DELIMITER)}\s*$"),
186
+ is_multiline_block=True,
187
+ is_inline=False,
188
+ )
189
+ self._definitions[SyntaxRegistryKey.CALLOUT] = definition
190
+
191
+ def _register_code_syntax(self) -> None:
192
+ code_delimiter = "```"
193
+ definition = SyntaxDefinition(
194
+ start_delimiter=code_delimiter,
195
+ end_delimiter=code_delimiter,
196
+ regex_pattern=re.compile("^" + re.escape(code_delimiter) + r"(\w*)\s*$"),
197
+ end_regex_pattern=re.compile("^" + re.escape(code_delimiter) + r"\s*$"),
198
+ is_multiline_block=False,
199
+ is_inline=False,
200
+ )
201
+ self._definitions[SyntaxRegistryKey.CODE] = definition
202
+
203
+ def _register_column_syntax(self) -> None:
204
+ definition = SyntaxDefinition(
205
+ start_delimiter=f"{self.MULTI_LINE_BLOCK_DELIMITER} column",
206
+ end_delimiter=self.MULTI_LINE_BLOCK_DELIMITER,
207
+ regex_pattern=re.compile(
208
+ rf"^{re.escape(self.MULTI_LINE_BLOCK_DELIMITER)}\s*column(?:\s+(0?\.\d+|1(?:\.0?)?))??\s*$",
209
+ re.IGNORECASE | re.MULTILINE,
210
+ ),
211
+ end_regex_pattern=re.compile(rf"^{re.escape(self.MULTI_LINE_BLOCK_DELIMITER)}\s*$", re.MULTILINE),
212
+ is_multiline_block=True,
213
+ is_inline=False,
214
+ )
215
+ self._definitions[SyntaxRegistryKey.COLUMN] = definition
216
+
217
+ def _register_column_list_syntax(self) -> None:
218
+ definition = SyntaxDefinition(
219
+ start_delimiter=f"{self.MULTI_LINE_BLOCK_DELIMITER} columns",
220
+ end_delimiter=self.MULTI_LINE_BLOCK_DELIMITER,
221
+ regex_pattern=re.compile(rf"^{re.escape(self.MULTI_LINE_BLOCK_DELIMITER)}\s*columns?\s*$", re.IGNORECASE),
222
+ end_regex_pattern=re.compile(rf"^{re.escape(self.MULTI_LINE_BLOCK_DELIMITER)}\s*$"),
223
+ is_multiline_block=True,
224
+ is_inline=False,
225
+ )
226
+ self._definitions[SyntaxRegistryKey.COLUMN_LIST] = definition
227
+
228
+ def _register_divider_syntax(self) -> None:
229
+ definition = SyntaxDefinition(
230
+ start_delimiter="---",
231
+ end_delimiter="",
232
+ regex_pattern=re.compile(r"^\s*-{3,}\s*$"),
233
+ is_multiline_block=False,
234
+ is_inline=False,
235
+ )
236
+ self._definitions[SyntaxRegistryKey.DIVIDER] = definition
237
+
238
+ def _register_embed_syntax(self) -> None:
239
+ definition = SyntaxDefinition(
240
+ start_delimiter="[embed](",
241
+ end_delimiter=")",
242
+ regex_pattern=re.compile(r"\[embed\]\((https?://[^\s)]+)\)"),
243
+ is_multiline_block=False,
244
+ is_inline=True,
245
+ )
246
+ self._definitions[SyntaxRegistryKey.EMBED] = definition
247
+
248
+ def _register_equation_syntax(self) -> None:
249
+ definition = SyntaxDefinition(
250
+ start_delimiter="$$",
251
+ end_delimiter="$$",
252
+ regex_pattern=re.compile(r"^\$\$\s*$"),
253
+ is_multiline_block=False,
254
+ is_inline=False,
255
+ )
256
+ self._definitions[SyntaxRegistryKey.EQUATION] = definition
257
+
258
+ def _register_file_syntax(self) -> None:
259
+ definition = SyntaxDefinition(
260
+ start_delimiter="[file](",
261
+ end_delimiter=")",
262
+ regex_pattern=re.compile(r"\[file\]\(([^)]+)\)"),
263
+ is_multiline_block=False,
264
+ is_inline=True,
265
+ )
266
+ self._definitions[SyntaxRegistryKey.FILE] = definition
267
+
268
+ def _register_heading_1_syntax(self) -> None:
269
+ definition = SyntaxDefinition(
270
+ start_delimiter="# ",
271
+ end_delimiter="",
272
+ regex_pattern=re.compile(r"^#\s+(.+)$"),
273
+ is_multiline_block=False,
274
+ is_inline=False,
275
+ )
276
+ self._definitions[SyntaxRegistryKey.HEADING_1] = definition
277
+
278
+ def _register_heading_2_syntax(self) -> None:
279
+ definition = SyntaxDefinition(
280
+ start_delimiter="## ",
281
+ end_delimiter="",
282
+ regex_pattern=re.compile(r"^#{2}\s+(.+)$"),
283
+ is_multiline_block=False,
284
+ is_inline=False,
285
+ )
286
+ self._definitions[SyntaxRegistryKey.HEADING_2] = definition
287
+
288
+ def _register_heading_3_syntax(self) -> None:
289
+ definition = SyntaxDefinition(
290
+ start_delimiter="### ",
291
+ end_delimiter="",
292
+ regex_pattern=re.compile(r"^#{3}\s+(.+)$"),
293
+ is_multiline_block=False,
294
+ is_inline=False,
295
+ )
296
+ self._definitions[SyntaxRegistryKey.HEADING_3] = definition
297
+
298
+ def _register_image_syntax(self) -> None:
299
+ definition = SyntaxDefinition(
300
+ start_delimiter="[image](",
301
+ end_delimiter=")",
302
+ regex_pattern=re.compile(r"(?<!!)\[image\]\(([^)]+)\)"),
303
+ is_multiline_block=False,
304
+ is_inline=True,
305
+ )
306
+ self._definitions[SyntaxRegistryKey.IMAGE] = definition
307
+
308
+ def _register_numbered_list_syntax(self) -> None:
309
+ definition = SyntaxDefinition(
310
+ start_delimiter="1. ",
311
+ end_delimiter="",
312
+ regex_pattern=re.compile(r"^(\s*)(\d+)\.\s+(.+)$"),
313
+ is_multiline_block=False,
314
+ is_inline=False,
315
+ )
316
+ self._definitions[SyntaxRegistryKey.NUMBERED_LIST] = definition
317
+
318
+ def _register_pdf_syntax(self) -> None:
319
+ definition = SyntaxDefinition(
320
+ start_delimiter="[pdf](",
321
+ end_delimiter=")",
322
+ regex_pattern=re.compile(r"\[pdf\]\(([^)]+)\)"),
323
+ is_multiline_block=False,
324
+ is_inline=True,
325
+ )
326
+ self._definitions[SyntaxRegistryKey.PDF] = definition
327
+
328
+ def _register_quote_syntax(self) -> None:
329
+ definition = SyntaxDefinition(
330
+ start_delimiter="> ",
331
+ end_delimiter="",
332
+ regex_pattern=re.compile(r"^>(?!>)\s*(.+)$"),
333
+ is_multiline_block=False,
334
+ is_inline=False,
335
+ )
336
+ self._definitions[SyntaxRegistryKey.QUOTE] = definition
337
+
338
+ def _register_table_syntax(self) -> None:
339
+ definition = SyntaxDefinition(
340
+ start_delimiter=self.TABLE_DELIMITER,
341
+ end_delimiter="",
342
+ regex_pattern=re.compile(
343
+ rf"^\s*{re.escape(self.TABLE_DELIMITER)}(.+){re.escape(self.TABLE_DELIMITER)}\s*$"
344
+ ),
345
+ is_multiline_block=False,
346
+ is_inline=False,
347
+ )
348
+ self._definitions[SyntaxRegistryKey.TABLE] = definition
349
+
350
+ def _register_table_row_syntax(self) -> None:
351
+ definition = SyntaxDefinition(
352
+ start_delimiter=self.TABLE_DELIMITER,
353
+ end_delimiter="",
354
+ regex_pattern=re.compile(
355
+ rf"^\s*{re.escape(self.TABLE_DELIMITER)}([\s\-:|]+){re.escape(self.TABLE_DELIMITER)}\s*$"
356
+ ),
357
+ is_multiline_block=False,
358
+ is_inline=False,
359
+ )
360
+ self._definitions[SyntaxRegistryKey.TABLE_ROW] = definition
361
+
362
+ def _register_table_of_contents_syntax(self) -> None:
363
+ definition = SyntaxDefinition(
364
+ start_delimiter="[toc]",
365
+ end_delimiter="",
366
+ regex_pattern=re.compile(r"^\[toc\]$", re.IGNORECASE),
367
+ is_multiline_block=False,
368
+ is_inline=False,
369
+ )
370
+ self._definitions[SyntaxRegistryKey.TABLE_OF_CONTENTS] = definition
371
+
372
+ def _register_todo_syntax(self) -> None:
373
+ definition = SyntaxDefinition(
374
+ start_delimiter="- [ ]",
375
+ end_delimiter="",
376
+ regex_pattern=re.compile(r"^\s*-\s+\[ \]\s+(.+)$"),
377
+ is_multiline_block=False,
378
+ is_inline=False,
379
+ )
380
+ self._definitions[SyntaxRegistryKey.TO_DO] = definition
381
+
382
+ def _register_todo_done_syntax(self) -> None:
383
+ definition = SyntaxDefinition(
384
+ start_delimiter="- [x]",
385
+ end_delimiter="",
386
+ regex_pattern=re.compile(r"^\s*-\s+\[x\]\s+(.+)$", re.IGNORECASE),
387
+ is_multiline_block=False,
388
+ is_inline=False,
389
+ )
390
+ self._definitions[SyntaxRegistryKey.TO_DO_DONE] = definition
391
+
392
+ def _register_toggle_syntax(self) -> None:
393
+ definition = SyntaxDefinition(
394
+ start_delimiter=self.TOGGLE_DELIMITER,
395
+ end_delimiter=self.TOGGLE_DELIMITER,
396
+ regex_pattern=re.compile(rf"^{re.escape(self.TOGGLE_DELIMITER)}\s+(.+)$"),
397
+ end_regex_pattern=re.compile(rf"^{re.escape(self.TOGGLE_DELIMITER)}\s*$"),
398
+ is_multiline_block=True,
399
+ is_inline=False,
400
+ )
401
+ self._definitions[SyntaxRegistryKey.TOGGLE] = definition
402
+
403
+ def _register_toggleable_heading_syntax(self) -> None:
404
+ escaped_delimiter = re.escape(self.TOGGLE_DELIMITER)
405
+ definition = SyntaxDefinition(
406
+ start_delimiter=f"{self.TOGGLE_DELIMITER} #",
407
+ end_delimiter=self.TOGGLE_DELIMITER,
408
+ regex_pattern=re.compile(rf"^{escaped_delimiter}\s*(?P<level>#{{1,3}})(?!#)\s*(.+)$", re.IGNORECASE),
409
+ end_regex_pattern=re.compile(rf"^{escaped_delimiter}\s*$"),
410
+ is_multiline_block=True,
411
+ is_inline=False,
412
+ )
413
+ self._definitions[SyntaxRegistryKey.TOGGLEABLE_HEADING] = definition
414
+
415
+ def _register_video_syntax(self) -> None:
416
+ definition = SyntaxDefinition(
417
+ start_delimiter="[video](",
418
+ end_delimiter=")",
419
+ regex_pattern=re.compile(r"\[video\]\(([^)]+)\)"),
420
+ is_multiline_block=False,
421
+ is_inline=True,
422
+ )
423
+ self._definitions[SyntaxRegistryKey.VIDEO] = definition
424
+
425
+ def _register_caption_syntax(self) -> None:
426
+ definition = SyntaxDefinition(
427
+ start_delimiter="[caption]",
428
+ end_delimiter="",
429
+ regex_pattern=re.compile(r"^\[caption\]\s+(\S.*)$"),
430
+ is_multiline_block=False,
431
+ is_inline=False,
432
+ )
433
+ self._definitions[SyntaxRegistryKey.CAPTION] = definition
434
+
435
+ def _register_space_syntax(self) -> None:
436
+ definition = SyntaxDefinition(
437
+ start_delimiter="[space]",
438
+ end_delimiter="",
439
+ regex_pattern=re.compile(r"^\[space\]\s*$"),
440
+ is_multiline_block=False,
441
+ is_inline=False,
442
+ )
443
+ self._definitions[SyntaxRegistryKey.SPACE] = definition
444
+
445
+ def _register_heading_syntax(self) -> None:
446
+ definition = SyntaxDefinition(
447
+ start_delimiter="#",
448
+ end_delimiter="",
449
+ regex_pattern=re.compile(r"^(#{1,3})[ \t]+(.+)$"),
450
+ is_multiline_block=False,
451
+ is_inline=False,
452
+ )
453
+ self._definitions[SyntaxRegistryKey.HEADING] = definition