notionary 0.2.27__py3-none-any.whl → 0.3.0__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 (395) hide show
  1. notionary/__init__.py +5 -20
  2. notionary/blocks/__init__.py +4 -4
  3. notionary/blocks/client.py +90 -216
  4. notionary/blocks/enums.py +167 -0
  5. notionary/blocks/rich_text/markdown_rich_text_converter.py +280 -0
  6. notionary/blocks/rich_text/models.py +178 -0
  7. notionary/blocks/rich_text/name_id_resolver/__init__.py +13 -0
  8. notionary/blocks/rich_text/name_id_resolver/data_source.py +32 -0
  9. notionary/blocks/rich_text/name_id_resolver/database.py +31 -0
  10. notionary/blocks/rich_text/name_id_resolver/page.py +34 -0
  11. notionary/blocks/rich_text/name_id_resolver/person.py +37 -0
  12. notionary/blocks/rich_text/name_id_resolver/port.py +11 -0
  13. notionary/blocks/rich_text/rich_text_markdown_converter.py +144 -0
  14. notionary/blocks/rich_text/rich_text_patterns.py +42 -0
  15. notionary/blocks/schemas.py +778 -0
  16. notionary/comments/__init__.py +1 -22
  17. notionary/comments/client.py +52 -187
  18. notionary/comments/factory.py +38 -0
  19. notionary/comments/models.py +5 -127
  20. notionary/comments/schemas.py +240 -0
  21. notionary/comments/service.py +34 -0
  22. notionary/data_source/http/client.py +11 -0
  23. notionary/data_source/http/data_source_instance_client.py +104 -0
  24. notionary/data_source/properties/schemas.py +402 -0
  25. notionary/data_source/query/builder.py +448 -0
  26. notionary/data_source/query/resolver.py +114 -0
  27. notionary/data_source/query/schema.py +302 -0
  28. notionary/data_source/query/validator.py +73 -0
  29. notionary/data_source/schema/registry.py +104 -0
  30. notionary/data_source/schema/service.py +136 -0
  31. notionary/data_source/schemas.py +27 -0
  32. notionary/data_source/service.py +377 -0
  33. notionary/database/client.py +30 -135
  34. notionary/database/database_metadata_update_client.py +19 -0
  35. notionary/database/schemas.py +29 -0
  36. notionary/database/service.py +168 -0
  37. notionary/exceptions/__init__.py +33 -0
  38. notionary/exceptions/api.py +41 -0
  39. notionary/exceptions/base.py +2 -0
  40. notionary/exceptions/block_parsing.py +16 -0
  41. notionary/exceptions/data_source/__init__.py +6 -0
  42. notionary/exceptions/data_source/builder.py +182 -0
  43. notionary/exceptions/data_source/properties.py +34 -0
  44. notionary/exceptions/properties.py +58 -0
  45. notionary/exceptions/search.py +57 -0
  46. notionary/file_upload/client.py +18 -30
  47. notionary/file_upload/models.py +7 -8
  48. notionary/file_upload/{notion_file_upload.py → service.py} +29 -64
  49. notionary/http/client.py +204 -0
  50. notionary/http/models.py +50 -0
  51. notionary/page/blocks/client.py +1 -0
  52. notionary/page/content/factory.py +73 -0
  53. notionary/page/content/markdown/__init__.py +5 -0
  54. notionary/page/content/markdown/builder.py +226 -0
  55. notionary/page/content/markdown/nodes/__init__.py +52 -0
  56. notionary/page/content/markdown/nodes/audio.py +23 -0
  57. notionary/page/content/markdown/nodes/base.py +12 -0
  58. notionary/page/content/markdown/nodes/bookmark.py +25 -0
  59. notionary/page/content/markdown/nodes/breadcrumb.py +14 -0
  60. notionary/page/content/markdown/nodes/bulleted_list.py +41 -0
  61. notionary/page/content/markdown/nodes/callout.py +34 -0
  62. notionary/page/content/markdown/nodes/code.py +28 -0
  63. notionary/page/content/markdown/nodes/columns.py +69 -0
  64. notionary/page/content/markdown/nodes/container.py +64 -0
  65. notionary/page/content/markdown/nodes/divider.py +14 -0
  66. notionary/page/content/markdown/nodes/embed.py +23 -0
  67. notionary/page/content/markdown/nodes/equation.py +19 -0
  68. notionary/page/content/markdown/nodes/file.py +23 -0
  69. notionary/page/content/markdown/nodes/heading.py +36 -0
  70. notionary/page/content/markdown/nodes/image.py +23 -0
  71. notionary/page/content/markdown/nodes/mixins/__init__.py +5 -0
  72. notionary/page/content/markdown/nodes/mixins/caption.py +12 -0
  73. notionary/page/content/markdown/nodes/numbered_list.py +38 -0
  74. notionary/page/content/markdown/nodes/paragraph.py +14 -0
  75. notionary/page/content/markdown/nodes/pdf.py +23 -0
  76. notionary/page/content/markdown/nodes/quote.py +27 -0
  77. notionary/page/content/markdown/nodes/space.py +14 -0
  78. notionary/page/content/markdown/nodes/table.py +45 -0
  79. notionary/page/content/markdown/nodes/table_of_contents.py +14 -0
  80. notionary/page/content/markdown/nodes/todo.py +38 -0
  81. notionary/page/content/markdown/nodes/toggle.py +27 -0
  82. notionary/page/content/markdown/nodes/video.py +23 -0
  83. notionary/page/content/parser/context.py +126 -0
  84. notionary/page/content/parser/factory.py +210 -0
  85. notionary/page/content/parser/parsers/__init__.py +58 -0
  86. notionary/page/content/parser/parsers/audio.py +40 -0
  87. notionary/page/content/parser/parsers/base.py +30 -0
  88. notionary/page/content/parser/parsers/bookmark.py +33 -0
  89. notionary/page/content/parser/parsers/breadcrumb.py +33 -0
  90. notionary/page/content/parser/parsers/bulleted_list.py +85 -0
  91. notionary/page/content/parser/parsers/callout.py +100 -0
  92. notionary/page/content/parser/parsers/caption.py +55 -0
  93. notionary/page/content/parser/parsers/code.py +81 -0
  94. notionary/page/content/parser/parsers/column.py +76 -0
  95. notionary/page/content/parser/parsers/column_list.py +81 -0
  96. notionary/page/content/parser/parsers/divider.py +33 -0
  97. notionary/page/content/parser/parsers/embed.py +33 -0
  98. notionary/page/content/parser/parsers/equation.py +65 -0
  99. notionary/page/content/parser/parsers/file.py +42 -0
  100. notionary/page/content/parser/parsers/heading.py +115 -0
  101. notionary/page/content/parser/parsers/image.py +42 -0
  102. notionary/page/content/parser/parsers/numbered_list.py +89 -0
  103. notionary/page/content/parser/parsers/paragraph.py +37 -0
  104. notionary/page/content/parser/parsers/pdf.py +42 -0
  105. notionary/page/content/parser/parsers/quote.py +125 -0
  106. notionary/page/content/parser/parsers/space.py +41 -0
  107. notionary/page/content/parser/parsers/table.py +144 -0
  108. notionary/page/content/parser/parsers/table_of_contents.py +32 -0
  109. notionary/page/content/parser/parsers/todo.py +96 -0
  110. notionary/page/content/parser/parsers/toggle.py +70 -0
  111. notionary/page/content/parser/parsers/video.py +42 -0
  112. notionary/page/content/parser/post_processing/handlers/__init__.py +5 -0
  113. notionary/page/content/parser/post_processing/handlers/rich_text_length.py +95 -0
  114. notionary/page/content/parser/post_processing/handlers/rich_text_length_truncation.py +114 -0
  115. notionary/page/content/parser/post_processing/port.py +9 -0
  116. notionary/page/content/parser/post_processing/service.py +16 -0
  117. notionary/page/content/parser/pre_processsing/handlers/__init__.py +11 -0
  118. notionary/page/content/parser/pre_processsing/handlers/column_syntax.py +130 -0
  119. notionary/page/content/parser/pre_processsing/handlers/indentation.py +84 -0
  120. notionary/page/content/parser/pre_processsing/handlers/port.py +7 -0
  121. notionary/page/content/parser/pre_processsing/handlers/whitespace.py +73 -0
  122. notionary/page/content/parser/pre_processsing/service.py +15 -0
  123. notionary/page/content/parser/service.py +78 -0
  124. notionary/page/content/renderer/context.py +51 -0
  125. notionary/page/content/renderer/factory.py +231 -0
  126. notionary/page/content/renderer/post_processing/handlers/__init__.py +5 -0
  127. notionary/page/content/renderer/post_processing/handlers/numbered_list.py +156 -0
  128. notionary/page/content/renderer/post_processing/port.py +7 -0
  129. notionary/page/content/renderer/post_processing/service.py +15 -0
  130. notionary/page/content/renderer/renderers/__init__.py +55 -0
  131. notionary/page/content/renderer/renderers/audio.py +31 -0
  132. notionary/page/content/renderer/renderers/base.py +31 -0
  133. notionary/page/content/renderer/renderers/bookmark.py +25 -0
  134. notionary/page/content/renderer/renderers/breadcrumb.py +21 -0
  135. notionary/page/content/renderer/renderers/bulleted_list.py +48 -0
  136. notionary/page/content/renderer/renderers/callout.py +50 -0
  137. notionary/page/content/renderer/renderers/captioned_block.py +58 -0
  138. notionary/page/content/renderer/renderers/code.py +34 -0
  139. notionary/page/content/renderer/renderers/column.py +53 -0
  140. notionary/page/content/renderer/renderers/column_list.py +44 -0
  141. notionary/page/content/renderer/renderers/divider.py +22 -0
  142. notionary/page/content/renderer/renderers/embed.py +25 -0
  143. notionary/page/content/renderer/renderers/equation.py +37 -0
  144. notionary/page/content/renderer/renderers/fallback.py +24 -0
  145. notionary/page/content/renderer/renderers/file.py +40 -0
  146. notionary/page/content/renderer/renderers/heading.py +95 -0
  147. notionary/page/content/renderer/renderers/image.py +31 -0
  148. notionary/page/content/renderer/renderers/numbered_list.py +42 -0
  149. notionary/page/content/renderer/renderers/paragraph.py +40 -0
  150. notionary/page/content/renderer/renderers/pdf.py +31 -0
  151. notionary/page/content/renderer/renderers/quote.py +49 -0
  152. notionary/page/content/renderer/renderers/table.py +115 -0
  153. notionary/page/content/renderer/renderers/table_of_contents.py +26 -0
  154. notionary/page/content/renderer/renderers/table_row.py +17 -0
  155. notionary/page/content/renderer/renderers/todo.py +56 -0
  156. notionary/page/content/renderer/renderers/toggle.py +52 -0
  157. notionary/page/content/renderer/renderers/video.py +31 -0
  158. notionary/page/content/renderer/service.py +50 -0
  159. notionary/page/content/service.py +68 -0
  160. notionary/page/content/syntax/__init__.py +4 -0
  161. notionary/page/content/syntax/grammar.py +10 -0
  162. notionary/page/content/syntax/models.py +66 -0
  163. notionary/page/content/syntax/registry.py +393 -0
  164. notionary/page/page_context.py +7 -16
  165. notionary/page/page_http_client.py +15 -0
  166. notionary/page/page_metadata_update_client.py +19 -0
  167. notionary/page/properties/client.py +144 -0
  168. notionary/page/properties/factory.py +26 -0
  169. notionary/page/properties/models.py +308 -0
  170. notionary/page/properties/service.py +261 -0
  171. notionary/page/schemas.py +13 -0
  172. notionary/page/service.py +225 -0
  173. notionary/shared/entity/client.py +29 -0
  174. notionary/shared/entity/dto_parsers.py +53 -0
  175. notionary/shared/entity/entity_metadata_update_client.py +41 -0
  176. notionary/shared/entity/schemas.py +45 -0
  177. notionary/shared/entity/service.py +171 -0
  178. notionary/shared/models/cover.py +20 -0
  179. notionary/shared/models/file.py +21 -0
  180. notionary/shared/models/icon.py +28 -0
  181. notionary/shared/models/parent.py +41 -0
  182. notionary/shared/properties/type.py +30 -0
  183. notionary/shared/typings.py +3 -0
  184. notionary/user/__init__.py +4 -8
  185. notionary/user/base.py +138 -0
  186. notionary/user/bot.py +70 -0
  187. notionary/user/client.py +22 -111
  188. notionary/user/person.py +41 -0
  189. notionary/user/schemas.py +67 -0
  190. notionary/user/service.py +65 -0
  191. notionary/utils/date.py +51 -0
  192. notionary/utils/decorators.py +122 -0
  193. notionary/utils/fuzzy.py +68 -0
  194. notionary/utils/mixins/logging.py +58 -0
  195. notionary/utils/pagination.py +100 -0
  196. notionary/utils/uuid_utils.py +20 -0
  197. notionary/workspace/__init__.py +4 -0
  198. notionary/workspace/client.py +62 -0
  199. notionary/workspace/query/__init__.py +3 -0
  200. notionary/workspace/query/builder.py +60 -0
  201. notionary/workspace/query/models.py +61 -0
  202. notionary/workspace/query/service.py +100 -0
  203. notionary/workspace/schemas.py +21 -0
  204. notionary/workspace/service.py +116 -0
  205. notionary-0.3.0.dist-info/METADATA +201 -0
  206. notionary-0.3.0.dist-info/RECORD +209 -0
  207. {notionary-0.2.27.dist-info → notionary-0.3.0.dist-info}/WHEEL +1 -1
  208. {notionary-0.2.27.dist-info → notionary-0.3.0.dist-info/licenses}/LICENSE +9 -9
  209. notionary/base_notion_client.py +0 -219
  210. notionary/blocks/_bootstrap.py +0 -271
  211. notionary/blocks/audio/__init__.py +0 -11
  212. notionary/blocks/audio/audio_element.py +0 -158
  213. notionary/blocks/audio/audio_markdown_node.py +0 -24
  214. notionary/blocks/audio/audio_models.py +0 -10
  215. notionary/blocks/base_block_element.py +0 -42
  216. notionary/blocks/bookmark/__init__.py +0 -12
  217. notionary/blocks/bookmark/bookmark_element.py +0 -83
  218. notionary/blocks/bookmark/bookmark_markdown_node.py +0 -28
  219. notionary/blocks/bookmark/bookmark_models.py +0 -15
  220. notionary/blocks/breadcrumbs/__init__.py +0 -15
  221. notionary/blocks/breadcrumbs/breadcrumb_element.py +0 -39
  222. notionary/blocks/breadcrumbs/breadcrumb_markdown_node.py +0 -13
  223. notionary/blocks/breadcrumbs/breadcrumb_models.py +0 -12
  224. notionary/blocks/bulleted_list/__init__.py +0 -15
  225. notionary/blocks/bulleted_list/bulleted_list_element.py +0 -74
  226. notionary/blocks/bulleted_list/bulleted_list_markdown_node.py +0 -20
  227. notionary/blocks/bulleted_list/bulleted_list_models.py +0 -17
  228. notionary/blocks/callout/__init__.py +0 -12
  229. notionary/blocks/callout/callout_element.py +0 -99
  230. notionary/blocks/callout/callout_markdown_node.py +0 -19
  231. notionary/blocks/callout/callout_models.py +0 -33
  232. notionary/blocks/child_database/__init__.py +0 -14
  233. notionary/blocks/child_database/child_database_element.py +0 -59
  234. notionary/blocks/child_database/child_database_models.py +0 -12
  235. notionary/blocks/child_page/__init__.py +0 -9
  236. notionary/blocks/child_page/child_page_element.py +0 -94
  237. notionary/blocks/child_page/child_page_models.py +0 -12
  238. notionary/blocks/code/__init__.py +0 -11
  239. notionary/blocks/code/code_element.py +0 -149
  240. notionary/blocks/code/code_markdown_node.py +0 -80
  241. notionary/blocks/code/code_models.py +0 -94
  242. notionary/blocks/column/__init__.py +0 -25
  243. notionary/blocks/column/column_element.py +0 -65
  244. notionary/blocks/column/column_list_element.py +0 -52
  245. notionary/blocks/column/column_list_markdown_node.py +0 -34
  246. notionary/blocks/column/column_markdown_node.py +0 -42
  247. notionary/blocks/column/column_models.py +0 -26
  248. notionary/blocks/divider/__init__.py +0 -12
  249. notionary/blocks/divider/divider_element.py +0 -41
  250. notionary/blocks/divider/divider_markdown_node.py +0 -11
  251. notionary/blocks/divider/divider_models.py +0 -12
  252. notionary/blocks/embed/__init__.py +0 -12
  253. notionary/blocks/embed/embed_element.py +0 -98
  254. notionary/blocks/embed/embed_markdown_node.py +0 -19
  255. notionary/blocks/embed/embed_models.py +0 -14
  256. notionary/blocks/equation/__init__.py +0 -13
  257. notionary/blocks/equation/equation_element.py +0 -133
  258. notionary/blocks/equation/equation_element_markdown_node.py +0 -23
  259. notionary/blocks/equation/equation_models.py +0 -11
  260. notionary/blocks/file/__init__.py +0 -23
  261. notionary/blocks/file/file_element.py +0 -133
  262. notionary/blocks/file/file_element_markdown_node.py +0 -24
  263. notionary/blocks/file/file_element_models.py +0 -39
  264. notionary/blocks/heading/__init__.py +0 -19
  265. notionary/blocks/heading/heading_element.py +0 -112
  266. notionary/blocks/heading/heading_markdown_node.py +0 -16
  267. notionary/blocks/heading/heading_models.py +0 -29
  268. notionary/blocks/image_block/__init__.py +0 -11
  269. notionary/blocks/image_block/image_element.py +0 -130
  270. notionary/blocks/image_block/image_markdown_node.py +0 -25
  271. notionary/blocks/image_block/image_models.py +0 -10
  272. notionary/blocks/markdown/markdown_builder.py +0 -525
  273. notionary/blocks/markdown/markdown_document_model.py +0 -0
  274. notionary/blocks/markdown/markdown_node.py +0 -25
  275. notionary/blocks/mixins/captions/__init__.py +0 -4
  276. notionary/blocks/mixins/captions/caption_markdown_node_mixin.py +0 -31
  277. notionary/blocks/mixins/captions/caption_mixin.py +0 -92
  278. notionary/blocks/mixins/file_upload/__init__.py +0 -3
  279. notionary/blocks/mixins/file_upload/file_upload_mixin.py +0 -320
  280. notionary/blocks/models.py +0 -174
  281. notionary/blocks/numbered_list/__init__.py +0 -16
  282. notionary/blocks/numbered_list/numbered_list_element.py +0 -65
  283. notionary/blocks/numbered_list/numbered_list_markdown_node.py +0 -17
  284. notionary/blocks/numbered_list/numbered_list_models.py +0 -17
  285. notionary/blocks/paragraph/__init__.py +0 -15
  286. notionary/blocks/paragraph/paragraph_element.py +0 -58
  287. notionary/blocks/paragraph/paragraph_markdown_node.py +0 -16
  288. notionary/blocks/paragraph/paragraph_models.py +0 -16
  289. notionary/blocks/pdf/__init__.py +0 -11
  290. notionary/blocks/pdf/pdf_element.py +0 -146
  291. notionary/blocks/pdf/pdf_markdown_node.py +0 -24
  292. notionary/blocks/pdf/pdf_models.py +0 -11
  293. notionary/blocks/quote/__init__.py +0 -14
  294. notionary/blocks/quote/quote_element.py +0 -75
  295. notionary/blocks/quote/quote_markdown_node.py +0 -16
  296. notionary/blocks/quote/quote_models.py +0 -18
  297. notionary/blocks/registry/__init__.py +0 -3
  298. notionary/blocks/registry/block_registry.py +0 -150
  299. notionary/blocks/rich_text/__init__.py +0 -33
  300. notionary/blocks/rich_text/rich_text_models.py +0 -221
  301. notionary/blocks/rich_text/text_inline_formatter.py +0 -456
  302. notionary/blocks/syntax_prompt_builder.py +0 -137
  303. notionary/blocks/table/__init__.py +0 -19
  304. notionary/blocks/table/table_element.py +0 -225
  305. notionary/blocks/table/table_markdown_node.py +0 -42
  306. notionary/blocks/table/table_models.py +0 -28
  307. notionary/blocks/table_of_contents/__init__.py +0 -17
  308. notionary/blocks/table_of_contents/table_of_contents_element.py +0 -80
  309. notionary/blocks/table_of_contents/table_of_contents_markdown_node.py +0 -21
  310. notionary/blocks/table_of_contents/table_of_contents_models.py +0 -18
  311. notionary/blocks/todo/__init__.py +0 -12
  312. notionary/blocks/todo/todo_element.py +0 -81
  313. notionary/blocks/todo/todo_markdown_node.py +0 -21
  314. notionary/blocks/todo/todo_models.py +0 -18
  315. notionary/blocks/toggle/__init__.py +0 -12
  316. notionary/blocks/toggle/toggle_element.py +0 -112
  317. notionary/blocks/toggle/toggle_markdown_node.py +0 -31
  318. notionary/blocks/toggle/toggle_models.py +0 -17
  319. notionary/blocks/toggleable_heading/__init__.py +0 -11
  320. notionary/blocks/toggleable_heading/toggleable_heading_element.py +0 -115
  321. notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +0 -34
  322. notionary/blocks/types.py +0 -130
  323. notionary/blocks/video/__init__.py +0 -11
  324. notionary/blocks/video/video_element.py +0 -187
  325. notionary/blocks/video/video_element_models.py +0 -10
  326. notionary/blocks/video/video_markdown_node.py +0 -26
  327. notionary/database/__init__.py +0 -4
  328. notionary/database/database.py +0 -480
  329. notionary/database/database_filter_builder.py +0 -173
  330. notionary/database/database_provider.py +0 -227
  331. notionary/database/exceptions.py +0 -13
  332. notionary/database/models.py +0 -337
  333. notionary/database/notion_database.py +0 -487
  334. notionary/file_upload/__init__.py +0 -7
  335. notionary/page/client.py +0 -124
  336. notionary/page/markdown_whitespace_processor.py +0 -129
  337. notionary/page/models.py +0 -322
  338. notionary/page/notion_page.py +0 -712
  339. notionary/page/page_content_deleting_service.py +0 -117
  340. notionary/page/page_content_writer.py +0 -80
  341. notionary/page/property_formatter.py +0 -99
  342. notionary/page/reader/handler/__init__.py +0 -19
  343. notionary/page/reader/handler/base_block_renderer.py +0 -44
  344. notionary/page/reader/handler/block_processing_context.py +0 -35
  345. notionary/page/reader/handler/block_rendering_context.py +0 -48
  346. notionary/page/reader/handler/column_list_renderer.py +0 -51
  347. notionary/page/reader/handler/column_renderer.py +0 -60
  348. notionary/page/reader/handler/equation_renderer.py +0 -0
  349. notionary/page/reader/handler/line_renderer.py +0 -73
  350. notionary/page/reader/handler/numbered_list_renderer.py +0 -85
  351. notionary/page/reader/handler/toggle_renderer.py +0 -69
  352. notionary/page/reader/handler/toggleable_heading_renderer.py +0 -89
  353. notionary/page/reader/page_content_retriever.py +0 -81
  354. notionary/page/search_filter_builder.py +0 -132
  355. notionary/page/utils.py +0 -60
  356. notionary/page/writer/handler/__init__.py +0 -24
  357. notionary/page/writer/handler/code_handler.py +0 -72
  358. notionary/page/writer/handler/column_handler.py +0 -141
  359. notionary/page/writer/handler/column_list_handler.py +0 -139
  360. notionary/page/writer/handler/equation_handler.py +0 -74
  361. notionary/page/writer/handler/line_handler.py +0 -35
  362. notionary/page/writer/handler/line_processing_context.py +0 -54
  363. notionary/page/writer/handler/regular_line_handler.py +0 -86
  364. notionary/page/writer/handler/table_handler.py +0 -66
  365. notionary/page/writer/handler/toggle_handler.py +0 -159
  366. notionary/page/writer/handler/toggleable_heading_handler.py +0 -174
  367. notionary/page/writer/markdown_to_notion_converter.py +0 -139
  368. notionary/page/writer/markdown_to_notion_converter_context.py +0 -30
  369. notionary/page/writer/markdown_to_notion_text_length_post_processor.py +0 -0
  370. notionary/page/writer/notion_text_length_processor.py +0 -150
  371. notionary/schemas/__init__.py +0 -3
  372. notionary/schemas/base.py +0 -73
  373. notionary/shared/__init__.py +0 -3
  374. notionary/shared/name_to_id_resolver.py +0 -203
  375. notionary/telemetry/__init__.py +0 -19
  376. notionary/telemetry/service.py +0 -136
  377. notionary/telemetry/views.py +0 -73
  378. notionary/user/base_notion_user.py +0 -53
  379. notionary/user/models.py +0 -84
  380. notionary/user/notion_bot_user.py +0 -226
  381. notionary/user/notion_user.py +0 -255
  382. notionary/user/notion_user_manager.py +0 -101
  383. notionary/util/__init__.py +0 -15
  384. notionary/util/concurrency_limiter.py +0 -0
  385. notionary/util/factory_decorator.py +0 -0
  386. notionary/util/factory_only.py +0 -37
  387. notionary/util/fuzzy.py +0 -75
  388. notionary/util/logging_mixin.py +0 -59
  389. notionary/util/page_id_utils.py +0 -27
  390. notionary/util/singleton.py +0 -18
  391. notionary/util/singleton_metaclass.py +0 -22
  392. notionary/workspace.py +0 -105
  393. notionary-0.2.27.dist-info/METADATA +0 -270
  394. notionary-0.2.27.dist-info/RECORD +0 -202
  395. /notionary/{database → user}/factory.py +0 -0
@@ -0,0 +1,210 @@
1
+ from notionary.blocks.rich_text.markdown_rich_text_converter import (
2
+ MarkdownRichTextConverter,
3
+ )
4
+ from notionary.page.content.parser.parsers import (
5
+ AudioParser,
6
+ BookmarkParser,
7
+ BreadcrumbParser,
8
+ BulletedListParser,
9
+ CalloutParser,
10
+ CaptionParser,
11
+ CodeParser,
12
+ ColumnListParser,
13
+ ColumnParser,
14
+ DividerParser,
15
+ EmbedParser,
16
+ EquationParser,
17
+ FileParser,
18
+ HeadingParser,
19
+ ImageParser,
20
+ LineParser,
21
+ NumberedListParser,
22
+ ParagraphParser,
23
+ PdfParser,
24
+ QuoteParser,
25
+ SpaceParser,
26
+ TableOfContentsParser,
27
+ TableParser,
28
+ TodoParser,
29
+ ToggleParser,
30
+ VideoParser,
31
+ )
32
+ from notionary.page.content.syntax import SyntaxRegistry
33
+
34
+
35
+ class ConverterChainFactory:
36
+ def __init__(
37
+ self,
38
+ rich_text_converter: MarkdownRichTextConverter | None = None,
39
+ syntax_registry: SyntaxRegistry | None = None,
40
+ ) -> None:
41
+ self._rich_text_converter = rich_text_converter or MarkdownRichTextConverter()
42
+ self._syntax_registry = syntax_registry or SyntaxRegistry()
43
+
44
+ def create(self) -> LineParser:
45
+ # multi-line (structural) blocks
46
+ code_parser = self._create_code_parser()
47
+ equation_parser = self._create_equation_parser()
48
+ table_parser = self._create_table_parser()
49
+ column_parser = self._create_column_parser()
50
+ column_list_parser = self._create_column_list_parser()
51
+ toggle_parser = self._create_toggle_parser()
52
+
53
+ # Single-line blocks
54
+ divider_parser = self._create_divider_parser()
55
+ breadcrumb_parser = self._create_breadcrumb_parser()
56
+ table_of_contents_parser = self._create_table_of_contents_parser()
57
+ space_parser = self._create_space_parser()
58
+ heading_parser = self._create_heading_parser()
59
+ quote_parser = self._create_quote_parser()
60
+ callout_parser = self._create_callout_parser()
61
+ todo_parser = self._create_todo_parser()
62
+ bulleted_list_parser = self._create_bulleted_list_parser()
63
+ numbered_list_parser = self._create_numbered_list_parser()
64
+
65
+ # Media blocks
66
+ bookmark_parser = self._create_bookmark_parser()
67
+ embed_parser = self._create_embed_parser()
68
+ image_parser = self._create_image_parser()
69
+ video_parser = self._create_video_parser()
70
+ audio_parser = self._create_audio_parser()
71
+ file_parser = self._create_file_parser()
72
+ pdf_parser = self._create_pdf_parser()
73
+
74
+ # Caption and Fallback
75
+ caption_parser = self._create_caption_parser()
76
+ paragraph_parser = self._create_paragraph_parser()
77
+
78
+ (
79
+ code_parser.set_next(equation_parser)
80
+ .set_next(table_parser)
81
+ .set_next(column_parser)
82
+ .set_next(column_list_parser)
83
+ .set_next(toggle_parser)
84
+ .set_next(divider_parser)
85
+ .set_next(breadcrumb_parser)
86
+ .set_next(table_of_contents_parser)
87
+ .set_next(space_parser)
88
+ .set_next(heading_parser)
89
+ .set_next(quote_parser)
90
+ .set_next(callout_parser)
91
+ .set_next(todo_parser)
92
+ .set_next(bulleted_list_parser)
93
+ .set_next(numbered_list_parser)
94
+ .set_next(bookmark_parser)
95
+ .set_next(embed_parser)
96
+ .set_next(image_parser)
97
+ .set_next(video_parser)
98
+ .set_next(audio_parser)
99
+ .set_next(file_parser)
100
+ .set_next(pdf_parser)
101
+ .set_next(caption_parser)
102
+ .set_next(paragraph_parser)
103
+ )
104
+
105
+ return code_parser
106
+
107
+ def _create_code_parser(self) -> CodeParser:
108
+ return CodeParser(
109
+ syntax_registry=self._syntax_registry,
110
+ rich_text_converter=self._rich_text_converter,
111
+ )
112
+
113
+ def _create_equation_parser(self) -> EquationParser:
114
+ return EquationParser(syntax_registry=self._syntax_registry)
115
+
116
+ def _create_table_parser(self) -> TableParser:
117
+ return TableParser(
118
+ syntax_registry=self._syntax_registry,
119
+ rich_text_converter=self._rich_text_converter,
120
+ )
121
+
122
+ def _create_column_parser(self) -> ColumnParser:
123
+ return ColumnParser(syntax_registry=self._syntax_registry)
124
+
125
+ def _create_column_list_parser(self) -> ColumnListParser:
126
+ return ColumnListParser(syntax_registry=self._syntax_registry)
127
+
128
+ def _create_toggle_parser(self) -> ToggleParser:
129
+ return ToggleParser(
130
+ syntax_registry=self._syntax_registry,
131
+ rich_text_converter=self._rich_text_converter,
132
+ )
133
+
134
+ def _create_divider_parser(self) -> DividerParser:
135
+ return DividerParser(syntax_registry=self._syntax_registry)
136
+
137
+ def _create_breadcrumb_parser(self) -> BreadcrumbParser:
138
+ return BreadcrumbParser(syntax_registry=self._syntax_registry)
139
+
140
+ def _create_table_of_contents_parser(self) -> TableOfContentsParser:
141
+ return TableOfContentsParser(syntax_registry=self._syntax_registry)
142
+
143
+ def _create_space_parser(self) -> SpaceParser:
144
+ return SpaceParser(syntax_registry=self._syntax_registry)
145
+
146
+ def _create_heading_parser(self) -> HeadingParser:
147
+ return HeadingParser(
148
+ syntax_registry=self._syntax_registry,
149
+ rich_text_converter=self._rich_text_converter,
150
+ )
151
+
152
+ def _create_quote_parser(self) -> QuoteParser:
153
+ return QuoteParser(
154
+ syntax_registry=self._syntax_registry,
155
+ rich_text_converter=self._rich_text_converter,
156
+ )
157
+
158
+ def _create_callout_parser(self) -> CalloutParser:
159
+ return CalloutParser(
160
+ syntax_registry=self._syntax_registry,
161
+ rich_text_converter=self._rich_text_converter,
162
+ )
163
+
164
+ def _create_todo_parser(self) -> TodoParser:
165
+ return TodoParser(
166
+ syntax_registry=self._syntax_registry,
167
+ rich_text_converter=self._rich_text_converter,
168
+ )
169
+
170
+ def _create_bulleted_list_parser(self) -> BulletedListParser:
171
+ return BulletedListParser(
172
+ syntax_registry=self._syntax_registry,
173
+ rich_text_converter=self._rich_text_converter,
174
+ )
175
+
176
+ def _create_numbered_list_parser(self) -> NumberedListParser:
177
+ return NumberedListParser(
178
+ syntax_registry=self._syntax_registry,
179
+ rich_text_converter=self._rich_text_converter,
180
+ )
181
+
182
+ def _create_bookmark_parser(self) -> BookmarkParser:
183
+ return BookmarkParser(syntax_registry=self._syntax_registry)
184
+
185
+ def _create_embed_parser(self) -> EmbedParser:
186
+ return EmbedParser(syntax_registry=self._syntax_registry)
187
+
188
+ def _create_image_parser(self) -> ImageParser:
189
+ return ImageParser(syntax_registry=self._syntax_registry)
190
+
191
+ def _create_video_parser(self) -> VideoParser:
192
+ return VideoParser(syntax_registry=self._syntax_registry)
193
+
194
+ def _create_audio_parser(self) -> AudioParser:
195
+ return AudioParser(syntax_registry=self._syntax_registry)
196
+
197
+ def _create_file_parser(self) -> FileParser:
198
+ return FileParser(syntax_registry=self._syntax_registry)
199
+
200
+ def _create_pdf_parser(self) -> PdfParser:
201
+ return PdfParser(syntax_registry=self._syntax_registry)
202
+
203
+ def _create_caption_parser(self) -> CaptionParser:
204
+ return CaptionParser(
205
+ syntax_registry=self._syntax_registry,
206
+ rich_text_converter=self._rich_text_converter,
207
+ )
208
+
209
+ def _create_paragraph_parser(self) -> ParagraphParser:
210
+ return ParagraphParser(rich_text_converter=self._rich_text_converter)
@@ -0,0 +1,58 @@
1
+ from ..context import BlockParsingContext, ParentBlockContext
2
+ from .audio import AudioParser
3
+ from .base import LineParser
4
+ from .bookmark import BookmarkParser
5
+ from .breadcrumb import BreadcrumbParser
6
+ from .bulleted_list import BulletedListParser
7
+ from .callout import CalloutParser
8
+ from .caption import CaptionParser
9
+ from .code import CodeParser
10
+ from .column import ColumnParser
11
+ from .column_list import ColumnListParser
12
+ from .divider import DividerParser
13
+ from .embed import EmbedParser
14
+ from .equation import EquationParser
15
+ from .file import FileParser
16
+ from .heading import HeadingParser
17
+ from .image import ImageParser
18
+ from .numbered_list import NumberedListParser
19
+ from .paragraph import ParagraphParser
20
+ from .pdf import PdfParser
21
+ from .quote import QuoteParser
22
+ from .space import SpaceParser
23
+ from .table import TableParser
24
+ from .table_of_contents import TableOfContentsParser
25
+ from .todo import TodoParser
26
+ from .toggle import ToggleParser
27
+ from .video import VideoParser
28
+
29
+ __all__ = [
30
+ "AudioParser",
31
+ "BlockParsingContext",
32
+ "BookmarkParser",
33
+ "BreadcrumbParser",
34
+ "BulletedListParser",
35
+ "CalloutParser",
36
+ "CaptionParser",
37
+ "CodeParser",
38
+ "ColumnListParser",
39
+ "ColumnParser",
40
+ "DividerParser",
41
+ "EmbedParser",
42
+ "EquationParser",
43
+ "FileParser",
44
+ "HeadingParser",
45
+ "ImageParser",
46
+ "LineParser",
47
+ "NumberedListParser",
48
+ "ParagraphParser",
49
+ "ParentBlockContext",
50
+ "PdfParser",
51
+ "QuoteParser",
52
+ "SpaceParser",
53
+ "TableOfContentsParser",
54
+ "TableParser",
55
+ "TodoParser",
56
+ "ToggleParser",
57
+ "VideoParser",
58
+ ]
@@ -0,0 +1,40 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.schemas import (
4
+ CreateAudioBlock,
5
+ ExternalFile,
6
+ FileData,
7
+ FileType,
8
+ )
9
+ from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
10
+ from notionary.page.content.syntax import SyntaxRegistry
11
+
12
+
13
+ class AudioParser(LineParser):
14
+ def __init__(self, syntax_registry: SyntaxRegistry) -> None:
15
+ super().__init__(syntax_registry)
16
+ self._syntax = syntax_registry.get_audio_syntax()
17
+
18
+ @override
19
+ def _can_handle(self, context: BlockParsingContext) -> bool:
20
+ if context.is_inside_parent_context():
21
+ return False
22
+ return self._syntax.regex_pattern.search(context.line) is not None
23
+
24
+ @override
25
+ async def _process(self, context: BlockParsingContext) -> None:
26
+ url = self._extract_url(context.line)
27
+ if url is None:
28
+ return
29
+
30
+ audio_data = FileData(
31
+ type=FileType.EXTERNAL,
32
+ external=ExternalFile(url=url),
33
+ caption=[],
34
+ )
35
+ block = CreateAudioBlock(audio=audio_data)
36
+ context.result_blocks.append(block)
37
+
38
+ def _extract_url(self, line: str) -> str | None:
39
+ match = self._syntax.regex_pattern.search(line)
40
+ return match.group(1).strip() if match else None
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+ from notionary.page.content.parser.context import BlockParsingContext
6
+ from notionary.page.content.syntax import SyntaxRegistry
7
+
8
+
9
+ class LineParser(ABC):
10
+ def __init__(self, syntax_registry: SyntaxRegistry | None = None) -> None:
11
+ self._next_handler: LineParser | None = None
12
+ self._syntax_registry = syntax_registry
13
+
14
+ def set_next(self, handler: LineParser) -> LineParser:
15
+ self._next_handler = handler
16
+ return handler
17
+
18
+ async def handle(self, context: BlockParsingContext) -> None:
19
+ if self._can_handle(context):
20
+ await self._process(context)
21
+ elif self._next_handler:
22
+ await self._next_handler.handle(context)
23
+
24
+ @abstractmethod
25
+ def _can_handle(self, context: BlockParsingContext) -> bool:
26
+ pass
27
+
28
+ @abstractmethod
29
+ async def _process(self, context: BlockParsingContext) -> None:
30
+ pass
@@ -0,0 +1,33 @@
1
+ """Parser for bookmark blocks."""
2
+
3
+ from typing import override
4
+
5
+ from notionary.blocks.schemas import BookmarkData, CreateBookmarkBlock
6
+ from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
7
+ from notionary.page.content.syntax import SyntaxRegistry
8
+
9
+
10
+ class BookmarkParser(LineParser):
11
+ def __init__(self, syntax_registry: SyntaxRegistry) -> None:
12
+ super().__init__(syntax_registry)
13
+ self._syntax = syntax_registry.get_bookmark_syntax()
14
+
15
+ @override
16
+ def _can_handle(self, context: BlockParsingContext) -> bool:
17
+ if context.is_inside_parent_context():
18
+ return False
19
+ return self._syntax.regex_pattern.search(context.line) is not None
20
+
21
+ @override
22
+ async def _process(self, context: BlockParsingContext) -> None:
23
+ url = self._extract_url(context.line)
24
+ if not url:
25
+ return
26
+
27
+ bookmark_data = BookmarkData(url=url, caption=[])
28
+ block = CreateBookmarkBlock(bookmark=bookmark_data)
29
+ context.result_blocks.append(block)
30
+
31
+ def _extract_url(self, line: str) -> str | None:
32
+ match = self._syntax.regex_pattern.search(line)
33
+ return match.group(1) if match else None
@@ -0,0 +1,33 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.schemas import BreadcrumbData, CreateBreadcrumbBlock
4
+ from notionary.page.content.parser.parsers.base import (
5
+ BlockParsingContext,
6
+ LineParser,
7
+ )
8
+ from notionary.page.content.syntax import SyntaxRegistry
9
+
10
+
11
+ class BreadcrumbParser(LineParser):
12
+ def __init__(self, syntax_registry: SyntaxRegistry) -> None:
13
+ super().__init__(syntax_registry)
14
+ self._syntax = syntax_registry.get_breadcrumb_syntax()
15
+
16
+ @override
17
+ def _can_handle(self, context: BlockParsingContext) -> bool:
18
+ if context.is_inside_parent_context():
19
+ return False
20
+ return self._is_breadcrumb(context.line)
21
+
22
+ @override
23
+ async def _process(self, context: BlockParsingContext) -> None:
24
+ block = self._create_breadcrumb_block()
25
+ if block:
26
+ context.result_blocks.append(block)
27
+
28
+ def _is_breadcrumb(self, line: str) -> bool:
29
+ return self._syntax.regex_pattern.match(line) is not None
30
+
31
+ def _create_breadcrumb_block(self) -> CreateBreadcrumbBlock:
32
+ breadcrumb_data = BreadcrumbData()
33
+ return CreateBreadcrumbBlock(breadcrumb=breadcrumb_data)
@@ -0,0 +1,85 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.rich_text.markdown_rich_text_converter import (
4
+ MarkdownRichTextConverter,
5
+ )
6
+ from notionary.blocks.schemas import CreateBulletedListItemBlock, CreateBulletedListItemData
7
+ from notionary.page.content.parser.parsers.base import (
8
+ BlockParsingContext,
9
+ LineParser,
10
+ )
11
+ from notionary.page.content.syntax import SyntaxRegistry
12
+
13
+
14
+ class BulletedListParser(LineParser):
15
+ def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
16
+ super().__init__(syntax_registry)
17
+ self._syntax = syntax_registry.get_bulleted_list_syntax()
18
+ self._rich_text_converter = rich_text_converter
19
+
20
+ @override
21
+ def _can_handle(self, context: BlockParsingContext) -> bool:
22
+ if context.is_inside_parent_context():
23
+ return False
24
+ return self._is_bulleted_list_line(context.line)
25
+
26
+ def _is_bulleted_list_line(self, line: str) -> bool:
27
+ return self._syntax.regex_pattern.match(line) is not None
28
+
29
+ @override
30
+ async def _process(self, context: BlockParsingContext) -> None:
31
+ block = await self._create_bulleted_list_block(context.line)
32
+ if not block:
33
+ return
34
+
35
+ await self._process_nested_children(block, context)
36
+ context.result_blocks.append(block)
37
+
38
+ async def _process_nested_children(self, block: CreateBulletedListItemBlock, context: BlockParsingContext) -> None:
39
+ child_lines = self._collect_child_lines(context)
40
+ if not child_lines:
41
+ return
42
+
43
+ child_blocks = await self._parse_child_blocks(child_lines, context)
44
+ if child_blocks:
45
+ block.bulleted_list_item.children = child_blocks
46
+
47
+ context.lines_consumed = len(child_lines)
48
+
49
+ def _collect_child_lines(self, context: BlockParsingContext) -> list[str]:
50
+ parent_indent_level = context.get_line_indentation_level()
51
+ return context.collect_indented_child_lines(parent_indent_level)
52
+
53
+ async def _parse_child_blocks(
54
+ self, child_lines: list[str], context: BlockParsingContext
55
+ ) -> list[CreateBulletedListItemBlock]:
56
+ stripped_lines = self._remove_parent_indentation(child_lines, context)
57
+ children_text = self._convert_lines_to_text(stripped_lines)
58
+ return await context.parse_nested_markdown(children_text)
59
+
60
+ def _remove_parent_indentation(self, lines: list[str], context: BlockParsingContext) -> list[str]:
61
+ return context.strip_indentation_level(lines, levels=1)
62
+
63
+ def _convert_lines_to_text(self, lines: list[str]) -> str:
64
+ return "\n".join(lines)
65
+
66
+ async def _create_bulleted_list_block(self, text: str) -> CreateBulletedListItemBlock | None:
67
+ content = self._extract_list_content(text)
68
+ if content is None:
69
+ return None
70
+
71
+ rich_text = await self._convert_to_rich_text(content)
72
+ return self._build_block(rich_text)
73
+
74
+ def _extract_list_content(self, text: str) -> str | None:
75
+ match = self._syntax.regex_pattern.match(text)
76
+ if not match:
77
+ return None
78
+ return match.group(2)
79
+
80
+ async def _convert_to_rich_text(self, content: str):
81
+ return await self._rich_text_converter.to_rich_text(content)
82
+
83
+ def _build_block(self, rich_text) -> CreateBulletedListItemBlock:
84
+ bulleted_list_content = CreateBulletedListItemData(rich_text=rich_text)
85
+ return CreateBulletedListItemBlock(bulleted_list_item=bulleted_list_content)
@@ -0,0 +1,100 @@
1
+ import re
2
+ from typing import override
3
+
4
+ from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
5
+ from notionary.blocks.schemas import CreateCalloutBlock, CreateCalloutData
6
+ from notionary.page.content.parser.parsers.base import (
7
+ BlockParsingContext,
8
+ LineParser,
9
+ )
10
+ from notionary.page.content.syntax import SyntaxRegistry
11
+ from notionary.shared.models.icon import EmojiIcon
12
+
13
+
14
+ class CalloutParser(LineParser):
15
+ DEFAULT_EMOJI = "💡"
16
+
17
+ def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
18
+ super().__init__(syntax_registry)
19
+ self._syntax = syntax_registry.get_callout_syntax()
20
+ self._pattern = self._syntax.regex_pattern
21
+ self._rich_text_converter = rich_text_converter
22
+
23
+ @override
24
+ def _can_handle(self, context: BlockParsingContext) -> bool:
25
+ return self._pattern.search(context.line) is not None
26
+
27
+ @override
28
+ async def _process(self, context: BlockParsingContext) -> None:
29
+ block = await self._create_callout_block(context.line)
30
+ if not block:
31
+ return
32
+
33
+ await self._process_nested_children(block, context)
34
+
35
+ if self._is_nested_in_parent_context(context):
36
+ context.parent_stack[-1].add_child_block(block)
37
+ else:
38
+ context.result_blocks.append(block)
39
+
40
+ async def _process_nested_children(self, block: CreateCalloutBlock, context: BlockParsingContext) -> None:
41
+ child_lines = self._collect_child_lines(context)
42
+ if not child_lines:
43
+ return
44
+
45
+ child_blocks = await self._parse_child_blocks(child_lines, context)
46
+ if child_blocks:
47
+ block.callout.children = child_blocks
48
+
49
+ context.lines_consumed = len(child_lines)
50
+
51
+ def _collect_child_lines(self, context: BlockParsingContext) -> list[str]:
52
+ parent_indent_level = context.get_line_indentation_level()
53
+ return context.collect_indented_child_lines(parent_indent_level)
54
+
55
+ async def _parse_child_blocks(
56
+ self, child_lines: list[str], context: BlockParsingContext
57
+ ) -> list[CreateCalloutBlock]:
58
+ stripped_lines = self._remove_parent_indentation(child_lines, context)
59
+ children_text = self._convert_lines_to_text(stripped_lines)
60
+ return await context.parse_nested_markdown(children_text)
61
+
62
+ def _remove_parent_indentation(self, lines: list[str], context: BlockParsingContext) -> list[str]:
63
+ return context.strip_indentation_level(lines, levels=1)
64
+
65
+ def _convert_lines_to_text(self, lines: list[str]) -> str:
66
+ return "\n".join(lines)
67
+
68
+ async def _create_callout_block(self, line: str) -> CreateCalloutBlock | None:
69
+ match = self._pattern.search(line)
70
+ if not match:
71
+ return None
72
+
73
+ content, emoji = self._extract_content_and_emoji(match)
74
+ rich_text = await self._convert_to_rich_text(content)
75
+ return self._build_block(rich_text, emoji)
76
+
77
+ def _extract_content_and_emoji(self, match: re.Match[str]) -> tuple[str, str]:
78
+ inline_content = match.group(1)
79
+ if inline_content:
80
+ return inline_content.strip(), match.group(2) or self.DEFAULT_EMOJI
81
+
82
+ block_content = match.group(3)
83
+ if block_content:
84
+ return block_content.strip(), match.group(4) or self.DEFAULT_EMOJI
85
+
86
+ return "", self.DEFAULT_EMOJI
87
+
88
+ async def _convert_to_rich_text(self, content: str):
89
+ return await self._rich_text_converter.to_rich_text(content)
90
+
91
+ def _build_block(self, rich_text, emoji: str) -> CreateCalloutBlock:
92
+ callout_data = CreateCalloutData(
93
+ rich_text=rich_text,
94
+ icon=EmojiIcon(emoji=emoji),
95
+ children=[],
96
+ )
97
+ return CreateCalloutBlock(callout=callout_data)
98
+
99
+ def _is_nested_in_parent_context(self, context: BlockParsingContext) -> bool:
100
+ return bool(context.parent_stack)
@@ -0,0 +1,55 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.rich_text.markdown_rich_text_converter import (
4
+ MarkdownRichTextConverter,
5
+ )
6
+ from notionary.blocks.schemas import BlockCreatePayload
7
+ from notionary.page.content.parser.parsers.base import (
8
+ BlockParsingContext,
9
+ LineParser,
10
+ )
11
+ from notionary.page.content.syntax import SyntaxRegistry
12
+
13
+
14
+ class CaptionParser(LineParser):
15
+ def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
16
+ super().__init__(syntax_registry)
17
+ self._syntax = syntax_registry.get_caption_syntax()
18
+ self._rich_text_converter = rich_text_converter
19
+
20
+ @override
21
+ def _can_handle(self, context: BlockParsingContext) -> bool:
22
+ if context.is_inside_parent_context():
23
+ return False
24
+
25
+ if not self._syntax.regex_pattern.match(context.line):
26
+ return False
27
+
28
+ if not context.result_blocks:
29
+ return False
30
+
31
+ previous_block = context.result_blocks[-1]
32
+ return self._block_supports_caption(previous_block)
33
+
34
+ @override
35
+ async def _process(self, context: BlockParsingContext) -> None:
36
+ caption_match = self._syntax.regex_pattern.match(context.line)
37
+ if not caption_match:
38
+ return
39
+
40
+ caption_text = caption_match.group(1)
41
+ caption_rich_text = await self._rich_text_converter.to_rich_text(caption_text)
42
+
43
+ previous_block = context.result_blocks[-1]
44
+ self._attach_caption_to_block(previous_block, caption_rich_text)
45
+
46
+ def _block_supports_caption(self, block: BlockCreatePayload) -> bool:
47
+ block_data = getattr(block, block.type.value, None)
48
+ if block_data is None:
49
+ return False
50
+ return hasattr(block_data, "caption")
51
+
52
+ def _attach_caption_to_block(self, block: BlockCreatePayload, caption_rich_text: list) -> None:
53
+ block_data = getattr(block, block.type.value)
54
+ if hasattr(block_data, "caption"):
55
+ block_data.caption = caption_rich_text