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,37 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.enums import BlockColor
4
+ from notionary.blocks.rich_text.markdown_rich_text_converter import (
5
+ MarkdownRichTextConverter,
6
+ )
7
+ from notionary.blocks.schemas import CreateParagraphBlock, CreateParagraphData
8
+ from notionary.page.content.parser.parsers.base import (
9
+ BlockParsingContext,
10
+ LineParser,
11
+ )
12
+
13
+
14
+ class ParagraphParser(LineParser):
15
+ def __init__(self, rich_text_converter: MarkdownRichTextConverter) -> None:
16
+ super().__init__()
17
+ self._rich_text_converter = rich_text_converter
18
+
19
+ @override
20
+ def _can_handle(self, context: BlockParsingContext) -> bool:
21
+ if context.is_inside_parent_context():
22
+ return False
23
+ return bool(context.line)
24
+
25
+ @override
26
+ async def _process(self, context: BlockParsingContext) -> None:
27
+ block = await self._create_paragraph_block(context.line)
28
+ if block:
29
+ context.result_blocks.append(block)
30
+
31
+ async def _create_paragraph_block(self, text: str) -> CreateParagraphBlock | None:
32
+ if not text:
33
+ return None
34
+
35
+ rich_text = await self._rich_text_converter.to_rich_text(text)
36
+ paragraph_content = CreateParagraphData(rich_text=rich_text, color=BlockColor.DEFAULT)
37
+ return CreateParagraphBlock(paragraph=paragraph_content)
@@ -0,0 +1,42 @@
1
+ """Parser for PDF blocks."""
2
+
3
+ from typing import override
4
+
5
+ from notionary.blocks.schemas import (
6
+ CreatePdfBlock,
7
+ ExternalFile,
8
+ FileData,
9
+ FileType,
10
+ )
11
+ from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
12
+ from notionary.page.content.syntax import SyntaxRegistry
13
+
14
+
15
+ class PdfParser(LineParser):
16
+ def __init__(self, syntax_registry: SyntaxRegistry) -> None:
17
+ super().__init__(syntax_registry)
18
+ self._syntax = syntax_registry.get_pdf_syntax()
19
+
20
+ @override
21
+ def _can_handle(self, context: BlockParsingContext) -> bool:
22
+ if context.is_inside_parent_context():
23
+ return False
24
+ return self._syntax.regex_pattern.search(context.line) is not None
25
+
26
+ @override
27
+ async def _process(self, context: BlockParsingContext) -> None:
28
+ url = self._extract_url(context.line)
29
+ if not url:
30
+ return
31
+
32
+ pdf_data = FileData(
33
+ type=FileType.EXTERNAL,
34
+ external=ExternalFile(url=url),
35
+ caption=[],
36
+ )
37
+ block = CreatePdfBlock(pdf=pdf_data)
38
+ context.result_blocks.append(block)
39
+
40
+ def _extract_url(self, line: str) -> str | None:
41
+ match = self._syntax.regex_pattern.search(line)
42
+ return match.group(1).strip() if match else None
@@ -0,0 +1,125 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
4
+ from notionary.blocks.schemas import BlockColor, CreateQuoteBlock, CreateQuoteData
5
+ from notionary.page.content.parser.parsers.base import (
6
+ BlockParsingContext,
7
+ LineParser,
8
+ )
9
+ from notionary.page.content.syntax import SyntaxRegistry
10
+
11
+
12
+ class QuoteParser(LineParser):
13
+ def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
14
+ super().__init__(syntax_registry)
15
+ self._syntax = syntax_registry.get_quote_syntax()
16
+ self._rich_text_converter = rich_text_converter
17
+
18
+ @override
19
+ def _can_handle(self, context: BlockParsingContext) -> bool:
20
+ if context.is_inside_parent_context():
21
+ return False
22
+ return self._is_quote(context.line)
23
+
24
+ def _is_quote(self, line: str) -> bool:
25
+ return self._syntax.regex_pattern.match(line) is not None
26
+
27
+ @override
28
+ async def _process(self, context: BlockParsingContext) -> None:
29
+ quote_lines = self._collect_quote_lines(context)
30
+
31
+ block = await self._create_quote_block(quote_lines)
32
+ if not block:
33
+ return
34
+
35
+ # Lines consumed: all quote lines minus the current line (which is already being processed)
36
+ context.lines_consumed = len(quote_lines) - 1
37
+
38
+ await self._process_nested_children(block, context, quote_lines)
39
+ context.result_blocks.append(block)
40
+
41
+ def _collect_quote_lines(self, context: BlockParsingContext) -> list[str]:
42
+ quote_lines = [context.line]
43
+ for line in context.get_remaining_lines():
44
+ if not self._is_quote(line):
45
+ break
46
+ quote_lines.append(line)
47
+ return quote_lines
48
+
49
+ async def _process_nested_children(
50
+ self, block: CreateQuoteBlock, context: BlockParsingContext, quote_lines: list[str]
51
+ ) -> None:
52
+ # Calculate indent level after all quote lines
53
+ last_quote_line_index = len(quote_lines) - 1
54
+ child_lines = self._collect_child_lines_after_quote(context, last_quote_line_index)
55
+
56
+ if not child_lines:
57
+ return
58
+
59
+ child_blocks = await self._parse_child_blocks(child_lines, context)
60
+ if child_blocks:
61
+ block.quote.children = child_blocks
62
+
63
+ context.lines_consumed += len(child_lines)
64
+
65
+ def _collect_child_lines_after_quote(self, context: BlockParsingContext, last_quote_index: int) -> list[str]:
66
+ """Collect indented children after the quote block."""
67
+ parent_indent_level = context.get_line_indentation_level()
68
+ remaining_lines = context.get_remaining_lines()
69
+
70
+ # Skip the quote lines we already processed
71
+ lines_after_quote = remaining_lines[last_quote_index:]
72
+
73
+ child_lines = []
74
+ expected_child_indent = parent_indent_level + 1
75
+
76
+ for line in lines_after_quote:
77
+ if not line.strip():
78
+ child_lines.append(line)
79
+ continue
80
+
81
+ line_indent = context.get_line_indentation_level(line)
82
+ if line_indent >= expected_child_indent:
83
+ child_lines.append(line)
84
+ else:
85
+ break
86
+
87
+ return child_lines
88
+
89
+ async def _parse_child_blocks(self, child_lines: list[str], context: BlockParsingContext) -> list[CreateQuoteBlock]:
90
+ stripped_lines = self._remove_parent_indentation(child_lines, context)
91
+ children_text = self._convert_lines_to_text(stripped_lines)
92
+ return await context.parse_nested_markdown(children_text)
93
+
94
+ def _remove_parent_indentation(self, lines: list[str], context: BlockParsingContext) -> list[str]:
95
+ return context.strip_indentation_level(lines, levels=1)
96
+
97
+ def _convert_lines_to_text(self, lines: list[str]) -> str:
98
+ return "\n".join(lines)
99
+
100
+ async def _create_quote_block(self, quote_lines: list[str]) -> CreateQuoteBlock | None:
101
+ contents = self._extract_quote_contents(quote_lines)
102
+ if not contents:
103
+ return None
104
+
105
+ content = self._join_contents_for_multiline_quote(contents)
106
+ rich_text = await self._convert_to_rich_text(content)
107
+ return self._build_block(rich_text)
108
+
109
+ def _extract_quote_contents(self, quote_lines: list[str]) -> list[str]:
110
+ contents = []
111
+ for line in quote_lines:
112
+ match = self._syntax.regex_pattern.match(line)
113
+ if match:
114
+ contents.append(match.group(1).strip())
115
+ return contents
116
+
117
+ def _join_contents_for_multiline_quote(self, contents: list[str]) -> str:
118
+ return "\n".join(contents)
119
+
120
+ async def _convert_to_rich_text(self, content: str):
121
+ return await self._rich_text_converter.to_rich_text(content)
122
+
123
+ def _build_block(self, rich_text) -> CreateQuoteBlock:
124
+ quote_data = CreateQuoteData(rich_text=rich_text, color=BlockColor.DEFAULT)
125
+ return CreateQuoteBlock(quote=quote_data)
@@ -0,0 +1,41 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.enums import BlockColor
4
+ from notionary.blocks.schemas import CreateParagraphBlock, CreateParagraphData
5
+ from notionary.page.content.parser.parsers.base import (
6
+ BlockParsingContext,
7
+ LineParser,
8
+ )
9
+ from notionary.page.content.syntax import SyntaxRegistry
10
+
11
+
12
+ class SpaceParser(LineParser):
13
+ def __init__(self, syntax_registry: SyntaxRegistry) -> None:
14
+ super().__init__(syntax_registry)
15
+ self._syntax = syntax_registry.get_space_syntax()
16
+
17
+ @override
18
+ def _can_handle(self, context: BlockParsingContext) -> bool:
19
+ if context.is_inside_parent_context():
20
+ return False
21
+
22
+ if self._is_explicit_space_marker(context):
23
+ return True
24
+
25
+ return self._is_second_consecutive_empty_line(context)
26
+
27
+ def _is_explicit_space_marker(self, context: BlockParsingContext) -> bool:
28
+ return self._syntax.regex_pattern.match(context.line.strip()) is not None
29
+
30
+ def _is_second_consecutive_empty_line(self, context: BlockParsingContext) -> bool:
31
+ return context.line.strip() == "" and context.is_previous_line_empty
32
+
33
+ @override
34
+ async def _process(self, context: BlockParsingContext) -> None:
35
+ block = self._create_space_block()
36
+ if block:
37
+ context.result_blocks.append(block)
38
+
39
+ def _create_space_block(self) -> CreateParagraphBlock:
40
+ paragraph_data = CreateParagraphData(rich_text=[], color=BlockColor.DEFAULT)
41
+ return CreateParagraphBlock(paragraph=paragraph_data)
@@ -0,0 +1,144 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
4
+ from notionary.blocks.rich_text.models import RichText
5
+ from notionary.blocks.schemas import CreateTableBlock, CreateTableData, CreateTableRowBlock, TableRowData
6
+ from notionary.page.content.parser.parsers import BlockParsingContext, LineParser
7
+ from notionary.page.content.syntax import SyntaxRegistry
8
+
9
+
10
+ class TableParser(LineParser):
11
+ def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
12
+ super().__init__(syntax_registry)
13
+ self._syntax = syntax_registry.get_table_syntax()
14
+ self._separator_syntax = syntax_registry.get_table_row_syntax()
15
+ self.rich_text_converter = rich_text_converter
16
+
17
+ @override
18
+ def _can_handle(self, context: BlockParsingContext) -> bool:
19
+ if context.is_inside_parent_context():
20
+ return False
21
+ return self._is_table_start(context)
22
+
23
+ @override
24
+ async def _process(self, context: BlockParsingContext) -> None:
25
+ if not self._is_table_start(context):
26
+ return
27
+
28
+ await self._process_complete_table(context)
29
+
30
+ def _is_table_start(self, context: BlockParsingContext) -> bool:
31
+ return self._syntax.regex_pattern.match(context.line) is not None
32
+
33
+ async def _process_complete_table(self, context: BlockParsingContext) -> None:
34
+ table_lines = [context.line]
35
+ remaining_lines = context.get_remaining_lines()
36
+ lines_consumed = self._collect_table_lines(table_lines, remaining_lines)
37
+
38
+ block = await self._create_table_block(table_lines)
39
+
40
+ if block:
41
+ context.lines_consumed = lines_consumed
42
+ context.result_blocks.append(block)
43
+
44
+ def _collect_table_lines(self, table_lines: list[str], remaining_lines: list[str]) -> int:
45
+ lines_consumed = 0
46
+
47
+ for index, line in enumerate(remaining_lines):
48
+ line_stripped = line.strip()
49
+
50
+ if not line_stripped:
51
+ table_lines.append(line)
52
+ continue
53
+
54
+ if self._is_table_line(line_stripped):
55
+ table_lines.append(line)
56
+ else:
57
+ lines_consumed = index
58
+ break
59
+ else:
60
+ lines_consumed = len(remaining_lines)
61
+
62
+ return lines_consumed
63
+
64
+ def _is_table_line(self, line: str) -> bool:
65
+ return self._syntax.regex_pattern.match(line) or self._separator_syntax.regex_pattern.match(line)
66
+
67
+ async def _create_table_block(self, table_lines: list[str]) -> CreateTableBlock | None:
68
+ if not table_lines:
69
+ return None
70
+
71
+ first_row = self._find_first_table_row(table_lines)
72
+ if not first_row:
73
+ return None
74
+
75
+ header_cells = self._parse_table_row(first_row)
76
+ column_count = len(header_cells)
77
+
78
+ table_rows, has_separator = await self._process_table_rows(table_lines)
79
+
80
+ table_data = CreateTableData(
81
+ table_width=column_count,
82
+ has_column_header=has_separator,
83
+ has_row_header=False,
84
+ children=table_rows,
85
+ )
86
+
87
+ return CreateTableBlock(table=table_data)
88
+
89
+ def _find_first_table_row(self, table_lines: list[str]) -> str | None:
90
+ for line in table_lines:
91
+ line_stripped = line.strip()
92
+ if line_stripped and self._syntax.regex_pattern.match(line_stripped):
93
+ return line_stripped
94
+ return None
95
+
96
+ async def _process_table_rows(self, table_lines: list[str]) -> tuple[list[CreateTableRowBlock], bool]:
97
+ table_rows = []
98
+ has_separator = False
99
+
100
+ for line in table_lines:
101
+ line_stripped = line.strip()
102
+
103
+ if not line_stripped:
104
+ continue
105
+
106
+ if self._is_separator_line(line_stripped):
107
+ has_separator = True
108
+ continue
109
+
110
+ if self._syntax.regex_pattern.match(line_stripped):
111
+ table_row = await self._create_table_row(line_stripped)
112
+ table_rows.append(table_row)
113
+
114
+ return table_rows, has_separator
115
+
116
+ def _is_separator_line(self, line: str) -> bool:
117
+ return self._separator_syntax.regex_pattern.match(line) is not None
118
+
119
+ async def _create_table_row(self, line: str) -> CreateTableRowBlock:
120
+ cells = self._parse_table_row(line)
121
+ rich_text_cells = await self._convert_cells_to_rich_text(cells)
122
+ table_row_data = TableRowData(cells=rich_text_cells)
123
+ return CreateTableRowBlock(table_row=table_row_data)
124
+
125
+ async def _convert_cells_to_rich_text(self, cells: list[str]) -> list[list[RichText]]:
126
+ rich_text_cells = []
127
+
128
+ for cell in cells:
129
+ rich_text = await self.rich_text_converter.to_rich_text(cell)
130
+ rich_text_cells.append(rich_text)
131
+
132
+ return rich_text_cells
133
+
134
+ def _parse_table_row(self, row_text: str) -> list[str]:
135
+ """Parse a table row by splitting on the table delimiter from SyntaxRegistry."""
136
+ row_content = row_text.strip()
137
+ delimiter = self._syntax.start_delimiter
138
+
139
+ if row_content.startswith(delimiter):
140
+ row_content = row_content[1:]
141
+ if row_content.endswith(delimiter):
142
+ row_content = row_content[:-1]
143
+
144
+ return row_content.split(delimiter)
@@ -0,0 +1,32 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.schemas import BlockColor, CreateTableOfContentsBlock, TableOfContentsData
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 TableOfContentsParser(LineParser):
12
+ def __init__(self, syntax_registry: SyntaxRegistry) -> None:
13
+ super().__init__(syntax_registry)
14
+ self._syntax = syntax_registry.get_table_of_contents_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_toc(context.line)
21
+
22
+ @override
23
+ async def _process(self, context: BlockParsingContext) -> None:
24
+ block = self._create_toc_block()
25
+ context.result_blocks.append(block)
26
+
27
+ def _is_toc(self, line: str) -> bool:
28
+ return self._syntax.regex_pattern.match(line) is not None
29
+
30
+ def _create_toc_block(self) -> CreateTableOfContentsBlock:
31
+ toc_data = TableOfContentsData(color=BlockColor.DEFAULT)
32
+ return CreateTableOfContentsBlock(table_of_contents=toc_data)
@@ -0,0 +1,96 @@
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 BlockColor, CreateToDoBlock, CreateToDoData
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 TodoParser(LineParser):
15
+ def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
16
+ super().__init__(syntax_registry)
17
+ self._syntax = syntax_registry.get_todo_syntax()
18
+ self._syntax_done = syntax_registry.get_todo_done_syntax()
19
+ self._rich_text_converter = rich_text_converter
20
+
21
+ @override
22
+ def _can_handle(self, context: BlockParsingContext) -> bool:
23
+ if context.is_inside_parent_context():
24
+ return False
25
+ return self._is_todo_line(context.line)
26
+
27
+ def _is_todo_line(self, line: str) -> bool:
28
+ return (
29
+ self._syntax.regex_pattern.match(line) is not None
30
+ or self._syntax_done.regex_pattern.match(line) is not None
31
+ )
32
+
33
+ @override
34
+ async def _process(self, context: BlockParsingContext) -> None:
35
+ block = await self._create_todo_block(context.line)
36
+ if not block:
37
+ return
38
+
39
+ await self._process_nested_children(block, context)
40
+ context.result_blocks.append(block)
41
+
42
+ async def _process_nested_children(self, block: CreateToDoBlock, context: BlockParsingContext) -> None:
43
+ child_lines = self._collect_child_lines(context)
44
+ if not child_lines:
45
+ return
46
+
47
+ child_blocks = await self._parse_child_blocks(child_lines, context)
48
+ if child_blocks:
49
+ block.to_do.children = child_blocks
50
+
51
+ context.lines_consumed = len(child_lines)
52
+
53
+ def _collect_child_lines(self, context: BlockParsingContext) -> list[str]:
54
+ parent_indent_level = context.get_line_indentation_level()
55
+ return context.collect_indented_child_lines(parent_indent_level)
56
+
57
+ async def _parse_child_blocks(self, child_lines: list[str], context: BlockParsingContext) -> list[CreateToDoBlock]:
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_todo_block(self, text: str) -> CreateToDoBlock | None:
69
+ content, checked = self._extract_todo_content(text)
70
+ if content is None:
71
+ return None
72
+
73
+ rich_text = await self._convert_to_rich_text(content)
74
+ return self._build_block(rich_text, checked)
75
+
76
+ def _extract_todo_content(self, text: str) -> tuple[str | None, bool]:
77
+ done_match = self._syntax_done.regex_pattern.match(text)
78
+ if done_match:
79
+ return done_match.group(1), True
80
+
81
+ todo_match = self._syntax.regex_pattern.match(text)
82
+ if todo_match:
83
+ return todo_match.group(1), False
84
+
85
+ return None, False
86
+
87
+ async def _convert_to_rich_text(self, content: str):
88
+ return await self._rich_text_converter.to_rich_text(content)
89
+
90
+ def _build_block(self, rich_text, checked: bool) -> CreateToDoBlock:
91
+ todo_content = CreateToDoData(
92
+ rich_text=rich_text,
93
+ checked=checked,
94
+ color=BlockColor.DEFAULT,
95
+ )
96
+ return CreateToDoBlock(to_do=todo_content)
@@ -0,0 +1,70 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
4
+ from notionary.blocks.schemas import BlockColor, CreateToggleBlock, CreateToggleData
5
+ from notionary.page.content.parser.parsers import (
6
+ BlockParsingContext,
7
+ LineParser,
8
+ )
9
+ from notionary.page.content.syntax import SyntaxRegistry
10
+
11
+
12
+ class ToggleParser(LineParser):
13
+ def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
14
+ super().__init__(syntax_registry)
15
+ self._syntax = syntax_registry.get_toggle_syntax()
16
+ self._heading_syntax = syntax_registry.get_toggleable_heading_syntax()
17
+ self._rich_text_converter = rich_text_converter
18
+
19
+ @override
20
+ def _can_handle(self, context: BlockParsingContext) -> bool:
21
+ return self._is_toggle_start(context)
22
+
23
+ @override
24
+ async def _process(self, context: BlockParsingContext) -> None:
25
+ if self._is_toggle_start(context):
26
+ await self._process_toggle(context)
27
+
28
+ def _is_toggle_start(self, context: BlockParsingContext) -> bool:
29
+ if not self._syntax.regex_pattern.match(context.line):
30
+ return False
31
+
32
+ # Exclude toggleable heading patterns to be more resilient to wrong order of chain
33
+ return not self.is_heading_start(context.line)
34
+
35
+ def is_heading_start(self, line: str) -> bool:
36
+ return self._heading_syntax.regex_pattern.match(line) is not None
37
+
38
+ async def _process_toggle(self, context: BlockParsingContext) -> None:
39
+ block = await self._create_toggle_block(context.line)
40
+ if not block:
41
+ return
42
+
43
+ await self._process_nested_children(block, context)
44
+
45
+ context.result_blocks.append(block)
46
+
47
+ async def _create_toggle_block(self, line: str) -> CreateToggleBlock | None:
48
+ if not (match := self._syntax.regex_pattern.match(line)):
49
+ return None
50
+
51
+ title = match.group(1).strip()
52
+ rich_text = await self._rich_text_converter.to_rich_text(title)
53
+
54
+ toggle_content = CreateToggleData(rich_text=rich_text, color=BlockColor.DEFAULT, children=[])
55
+ return CreateToggleBlock(toggle=toggle_content)
56
+
57
+ async def _process_nested_children(self, block: CreateToggleBlock, context: BlockParsingContext) -> None:
58
+ parent_indent_level = context.get_line_indentation_level()
59
+ child_lines = context.collect_indented_child_lines(parent_indent_level)
60
+
61
+ if not child_lines:
62
+ return
63
+
64
+ stripped_lines = context.strip_indentation_level(child_lines, levels=1)
65
+ child_markdown = "\n".join(stripped_lines)
66
+
67
+ child_blocks = await context.parse_nested_markdown(child_markdown)
68
+ block.toggle.children = child_blocks
69
+
70
+ context.lines_consumed = len(child_lines)
@@ -0,0 +1,42 @@
1
+ """Parser for video blocks."""
2
+
3
+ from typing import override
4
+
5
+ from notionary.blocks.schemas import (
6
+ CreateVideoBlock,
7
+ ExternalFile,
8
+ FileData,
9
+ FileType,
10
+ )
11
+ from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
12
+ from notionary.page.content.syntax import SyntaxRegistry
13
+
14
+
15
+ class VideoParser(LineParser):
16
+ def __init__(self, syntax_registry: SyntaxRegistry) -> None:
17
+ super().__init__(syntax_registry)
18
+ self._syntax = syntax_registry.get_video_syntax()
19
+
20
+ @override
21
+ def _can_handle(self, context: BlockParsingContext) -> bool:
22
+ if context.is_inside_parent_context():
23
+ return False
24
+ return self._syntax.regex_pattern.search(context.line) is not None
25
+
26
+ @override
27
+ async def _process(self, context: BlockParsingContext) -> None:
28
+ url = self._extract_url(context.line)
29
+ if not url:
30
+ return
31
+
32
+ video_data = FileData(
33
+ type=FileType.EXTERNAL,
34
+ external=ExternalFile(url=url),
35
+ caption=[],
36
+ )
37
+ block = CreateVideoBlock(video=video_data)
38
+ context.result_blocks.append(block)
39
+
40
+ def _extract_url(self, line: str) -> str | None:
41
+ match = self._syntax.regex_pattern.search(line)
42
+ return match.group(1).strip() if match else None
@@ -0,0 +1,5 @@
1
+ from .rich_text_length_truncation import RichTextLengthTruncationPostProcessor
2
+
3
+ __all__ = [
4
+ "RichTextLengthTruncationPostProcessor",
5
+ ]