notionary 0.2.26__py3-none-any.whl → 0.2.28__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (387) hide show
  1. notionary/__init__.py +5 -20
  2. notionary/blocks/client.py +87 -215
  3. notionary/blocks/enums.py +167 -0
  4. notionary/blocks/rich_text/markdown_rich_text_converter.py +266 -0
  5. notionary/blocks/rich_text/models.py +164 -0
  6. notionary/blocks/rich_text/name_id_resolver/__init__.py +11 -0
  7. notionary/blocks/rich_text/name_id_resolver/database.py +31 -0
  8. notionary/blocks/rich_text/name_id_resolver/page.py +34 -0
  9. notionary/blocks/rich_text/name_id_resolver/person.py +37 -0
  10. notionary/blocks/rich_text/name_id_resolver/port.py +11 -0
  11. notionary/blocks/rich_text/rich_text_markdown_converter.py +132 -0
  12. notionary/blocks/rich_text/rich_text_patterns.py +39 -0
  13. notionary/blocks/schemas.py +746 -0
  14. notionary/comments/client.py +52 -187
  15. notionary/comments/factory.py +40 -0
  16. notionary/comments/models.py +5 -127
  17. notionary/comments/schemas.py +240 -0
  18. notionary/comments/service.py +34 -0
  19. notionary/data_source/http/client.py +11 -0
  20. notionary/data_source/http/data_source_instance_client.py +94 -0
  21. notionary/data_source/properties/models.py +406 -0
  22. notionary/data_source/query/builder.py +429 -0
  23. notionary/data_source/query/resolver.py +114 -0
  24. notionary/data_source/query/schema.py +304 -0
  25. notionary/data_source/query/validator.py +73 -0
  26. notionary/data_source/schemas.py +27 -0
  27. notionary/data_source/service.py +353 -0
  28. notionary/database/client.py +30 -135
  29. notionary/database/database_metadata_update_client.py +19 -0
  30. notionary/database/schemas.py +29 -0
  31. notionary/database/service.py +169 -0
  32. notionary/exceptions/__init__.py +33 -0
  33. notionary/exceptions/api.py +41 -0
  34. notionary/exceptions/base.py +2 -0
  35. notionary/exceptions/block_parsing.py +16 -0
  36. notionary/exceptions/data_source/__init__.py +6 -0
  37. notionary/exceptions/data_source/builder.py +182 -0
  38. notionary/exceptions/data_source/properties.py +34 -0
  39. notionary/exceptions/properties.py +58 -0
  40. notionary/exceptions/search.py +33 -0
  41. notionary/file_upload/client.py +18 -30
  42. notionary/file_upload/models.py +7 -8
  43. notionary/file_upload/{notion_file_upload.py → service.py} +29 -64
  44. notionary/http/client.py +205 -0
  45. notionary/http/models.py +49 -0
  46. notionary/page/blocks/client.py +1 -0
  47. notionary/page/content/factory.py +68 -0
  48. notionary/page/content/markdown/__init__.py +5 -0
  49. notionary/page/content/markdown/builder.py +304 -0
  50. notionary/page/content/markdown/nodes/__init__.py +54 -0
  51. notionary/page/content/markdown/nodes/audio.py +23 -0
  52. notionary/page/content/markdown/nodes/base.py +12 -0
  53. notionary/page/content/markdown/nodes/bookmark.py +25 -0
  54. notionary/page/content/markdown/nodes/breadcrumb.py +14 -0
  55. notionary/page/content/markdown/nodes/bulleted_list.py +18 -0
  56. notionary/page/content/markdown/nodes/callout.py +32 -0
  57. notionary/page/content/markdown/nodes/code.py +30 -0
  58. notionary/page/content/markdown/nodes/columns.py +51 -0
  59. notionary/page/content/markdown/nodes/divider.py +14 -0
  60. notionary/page/content/markdown/nodes/embed.py +23 -0
  61. notionary/page/content/markdown/nodes/equation.py +19 -0
  62. notionary/page/content/markdown/nodes/file.py +23 -0
  63. notionary/page/content/markdown/nodes/heading.py +16 -0
  64. notionary/page/content/markdown/nodes/image.py +23 -0
  65. notionary/page/content/markdown/nodes/mixins/caption.py +12 -0
  66. notionary/page/content/markdown/nodes/numbered_list.py +15 -0
  67. notionary/page/content/markdown/nodes/paragraph.py +14 -0
  68. notionary/page/content/markdown/nodes/pdf.py +23 -0
  69. notionary/page/content/markdown/nodes/quote.py +15 -0
  70. notionary/page/content/markdown/nodes/space.py +14 -0
  71. notionary/page/content/markdown/nodes/table.py +45 -0
  72. notionary/page/content/markdown/nodes/table_of_contents.py +14 -0
  73. notionary/page/content/markdown/nodes/todo.py +22 -0
  74. notionary/page/content/markdown/nodes/toggle.py +28 -0
  75. notionary/page/content/markdown/nodes/toggleable_heading.py +35 -0
  76. notionary/page/content/markdown/nodes/video.py +23 -0
  77. notionary/page/content/parser/context.py +49 -0
  78. notionary/page/content/parser/factory.py +219 -0
  79. notionary/page/content/parser/parsers/__init__.py +60 -0
  80. notionary/page/content/parser/parsers/audio.py +40 -0
  81. notionary/page/content/parser/parsers/base.py +30 -0
  82. notionary/page/content/parser/parsers/bookmark.py +33 -0
  83. notionary/page/content/parser/parsers/breadcrumb.py +33 -0
  84. notionary/page/content/parser/parsers/bulleted_list.py +41 -0
  85. notionary/page/content/parser/parsers/callout.py +129 -0
  86. notionary/page/content/parser/parsers/caption.py +55 -0
  87. notionary/page/content/parser/parsers/code.py +81 -0
  88. notionary/page/content/parser/parsers/column.py +117 -0
  89. notionary/page/content/parser/parsers/column_list.py +81 -0
  90. notionary/page/content/parser/parsers/divider.py +33 -0
  91. notionary/page/content/parser/parsers/embed.py +33 -0
  92. notionary/page/content/parser/parsers/equation.py +65 -0
  93. notionary/page/content/parser/parsers/file.py +42 -0
  94. notionary/page/content/parser/parsers/heading.py +58 -0
  95. notionary/page/content/parser/parsers/image.py +42 -0
  96. notionary/page/content/parser/parsers/numbered_list.py +45 -0
  97. notionary/page/content/parser/parsers/paragraph.py +36 -0
  98. notionary/page/content/parser/parsers/pdf.py +42 -0
  99. notionary/page/content/parser/parsers/quote.py +65 -0
  100. notionary/page/content/parser/parsers/space.py +35 -0
  101. notionary/page/content/parser/parsers/table.py +144 -0
  102. notionary/page/content/parser/parsers/table_of_contents.py +32 -0
  103. notionary/page/content/parser/parsers/todo.py +58 -0
  104. notionary/page/content/parser/parsers/toggle.py +127 -0
  105. notionary/page/content/parser/parsers/toggleable_heading.py +150 -0
  106. notionary/page/content/parser/parsers/video.py +42 -0
  107. notionary/page/content/parser/post_processing/handlers/__init__.py +5 -0
  108. notionary/page/content/parser/post_processing/handlers/rich_text_length.py +93 -0
  109. notionary/page/content/parser/post_processing/handlers/rich_text_length_truncation.py +93 -0
  110. notionary/page/content/parser/post_processing/port.py +9 -0
  111. notionary/page/content/parser/post_processing/service.py +16 -0
  112. notionary/page/content/parser/pre_processsing/handlers/__init__.py +9 -0
  113. notionary/page/content/parser/pre_processsing/handlers/column_syntax.py +80 -0
  114. notionary/page/content/parser/pre_processsing/handlers/port.py +7 -0
  115. notionary/page/content/parser/pre_processsing/handlers/whitespace.py +68 -0
  116. notionary/page/content/parser/pre_processsing/service.py +15 -0
  117. notionary/page/content/parser/service.py +69 -0
  118. notionary/page/content/renderer/context.py +48 -0
  119. notionary/page/content/renderer/factory.py +240 -0
  120. notionary/page/content/renderer/post_processing/handlers/__init__.py +5 -0
  121. notionary/page/content/renderer/post_processing/handlers/numbered_list_placeholdere.py +62 -0
  122. notionary/page/content/renderer/post_processing/port.py +7 -0
  123. notionary/page/content/renderer/post_processing/service.py +15 -0
  124. notionary/page/content/renderer/renderers/__init__.py +57 -0
  125. notionary/page/content/renderer/renderers/audio.py +31 -0
  126. notionary/page/content/renderer/renderers/base.py +31 -0
  127. notionary/page/content/renderer/renderers/bookmark.py +25 -0
  128. notionary/page/content/renderer/renderers/breadcrumb.py +21 -0
  129. notionary/page/content/renderer/renderers/bulleted_list.py +48 -0
  130. notionary/page/content/renderer/renderers/callout.py +65 -0
  131. notionary/page/content/renderer/renderers/captioned_block.py +58 -0
  132. notionary/page/content/renderer/renderers/code.py +34 -0
  133. notionary/page/content/renderer/renderers/column.py +44 -0
  134. notionary/page/content/renderer/renderers/column_list.py +31 -0
  135. notionary/page/content/renderer/renderers/divider.py +22 -0
  136. notionary/page/content/renderer/renderers/embed.py +25 -0
  137. notionary/page/content/renderer/renderers/equation.py +37 -0
  138. notionary/page/content/renderer/renderers/fallback.py +24 -0
  139. notionary/page/content/renderer/renderers/file.py +40 -0
  140. notionary/page/content/renderer/renderers/heading.py +69 -0
  141. notionary/page/content/renderer/renderers/image.py +31 -0
  142. notionary/page/content/renderer/renderers/numbered_list.py +41 -0
  143. notionary/page/content/renderer/renderers/paragraph.py +40 -0
  144. notionary/page/content/renderer/renderers/pdf.py +31 -0
  145. notionary/page/content/renderer/renderers/quote.py +49 -0
  146. notionary/page/content/renderer/renderers/table.py +115 -0
  147. notionary/page/content/renderer/renderers/table_of_contents.py +26 -0
  148. notionary/page/content/renderer/renderers/table_row.py +17 -0
  149. notionary/page/content/renderer/renderers/todo.py +56 -0
  150. notionary/page/content/renderer/renderers/toggle.py +53 -0
  151. notionary/page/content/renderer/renderers/toggleable_heading.py +78 -0
  152. notionary/page/content/renderer/renderers/video.py +31 -0
  153. notionary/page/content/renderer/service.py +50 -0
  154. notionary/page/content/service.py +65 -0
  155. notionary/page/content/syntax/models.py +68 -0
  156. notionary/page/content/syntax/service.py +453 -0
  157. notionary/page/page_context.py +7 -16
  158. notionary/page/page_http_client.py +15 -0
  159. notionary/page/page_metadata_update_client.py +19 -0
  160. notionary/page/properties/client.py +144 -0
  161. notionary/page/properties/factory.py +26 -0
  162. notionary/page/properties/models.py +307 -0
  163. notionary/page/properties/service.py +257 -0
  164. notionary/page/schemas.py +13 -0
  165. notionary/page/service.py +222 -0
  166. notionary/shared/entity/client.py +29 -0
  167. notionary/shared/entity/dto_parsers.py +53 -0
  168. notionary/shared/entity/entity_metadata_update_client.py +41 -0
  169. notionary/shared/entity/schemas.py +45 -0
  170. notionary/shared/entity/service.py +171 -0
  171. notionary/shared/models/cover.py +20 -0
  172. notionary/shared/models/file.py +21 -0
  173. notionary/shared/models/icon.py +28 -0
  174. notionary/shared/models/parent.py +41 -0
  175. notionary/shared/properties/type.py +30 -0
  176. notionary/user/__init__.py +4 -8
  177. notionary/user/base.py +89 -0
  178. notionary/user/bot.py +70 -0
  179. notionary/user/client.py +22 -111
  180. notionary/user/person.py +41 -0
  181. notionary/user/schemas.py +67 -0
  182. notionary/user/service.py +65 -0
  183. notionary/utils/async_retry.py +39 -0
  184. notionary/utils/date.py +51 -0
  185. notionary/utils/fuzzy.py +56 -0
  186. notionary/{util/logging_mixin.py → utils/mixins/logging.py} +4 -16
  187. notionary/utils/pagination.py +50 -0
  188. notionary/utils/singleton.py +13 -0
  189. notionary/utils/uuid_utils.py +20 -0
  190. notionary/workspace/__init__.py +3 -0
  191. notionary/workspace/client.py +62 -0
  192. notionary/workspace/query/builder.py +60 -0
  193. notionary/workspace/query/models.py +60 -0
  194. notionary/workspace/query/service.py +93 -0
  195. notionary/workspace/schemas.py +21 -0
  196. notionary/workspace/service.py +116 -0
  197. {notionary-0.2.26.dist-info → notionary-0.2.28.dist-info}/METADATA +54 -49
  198. notionary-0.2.28.dist-info/RECORD +200 -0
  199. {notionary-0.2.26.dist-info → notionary-0.2.28.dist-info}/WHEEL +1 -1
  200. {notionary-0.2.26.dist-info → notionary-0.2.28.dist-info/licenses}/LICENSE +9 -9
  201. notionary/base_notion_client.py +0 -219
  202. notionary/blocks/__init__.py +0 -5
  203. notionary/blocks/_bootstrap.py +0 -271
  204. notionary/blocks/audio/__init__.py +0 -11
  205. notionary/blocks/audio/audio_element.py +0 -158
  206. notionary/blocks/audio/audio_markdown_node.py +0 -24
  207. notionary/blocks/audio/audio_models.py +0 -10
  208. notionary/blocks/base_block_element.py +0 -42
  209. notionary/blocks/bookmark/__init__.py +0 -12
  210. notionary/blocks/bookmark/bookmark_element.py +0 -83
  211. notionary/blocks/bookmark/bookmark_markdown_node.py +0 -28
  212. notionary/blocks/bookmark/bookmark_models.py +0 -15
  213. notionary/blocks/breadcrumbs/__init__.py +0 -15
  214. notionary/blocks/breadcrumbs/breadcrumb_element.py +0 -39
  215. notionary/blocks/breadcrumbs/breadcrumb_markdown_node.py +0 -13
  216. notionary/blocks/breadcrumbs/breadcrumb_models.py +0 -12
  217. notionary/blocks/bulleted_list/__init__.py +0 -15
  218. notionary/blocks/bulleted_list/bulleted_list_element.py +0 -74
  219. notionary/blocks/bulleted_list/bulleted_list_markdown_node.py +0 -20
  220. notionary/blocks/bulleted_list/bulleted_list_models.py +0 -17
  221. notionary/blocks/callout/__init__.py +0 -12
  222. notionary/blocks/callout/callout_element.py +0 -99
  223. notionary/blocks/callout/callout_markdown_node.py +0 -19
  224. notionary/blocks/callout/callout_models.py +0 -33
  225. notionary/blocks/child_database/__init__.py +0 -14
  226. notionary/blocks/child_database/child_database_element.py +0 -59
  227. notionary/blocks/child_database/child_database_models.py +0 -12
  228. notionary/blocks/child_page/__init__.py +0 -9
  229. notionary/blocks/child_page/child_page_element.py +0 -94
  230. notionary/blocks/child_page/child_page_models.py +0 -12
  231. notionary/blocks/code/__init__.py +0 -11
  232. notionary/blocks/code/code_element.py +0 -149
  233. notionary/blocks/code/code_markdown_node.py +0 -80
  234. notionary/blocks/code/code_models.py +0 -94
  235. notionary/blocks/column/__init__.py +0 -25
  236. notionary/blocks/column/column_element.py +0 -65
  237. notionary/blocks/column/column_list_element.py +0 -52
  238. notionary/blocks/column/column_list_markdown_node.py +0 -34
  239. notionary/blocks/column/column_markdown_node.py +0 -42
  240. notionary/blocks/column/column_models.py +0 -26
  241. notionary/blocks/divider/__init__.py +0 -12
  242. notionary/blocks/divider/divider_element.py +0 -41
  243. notionary/blocks/divider/divider_markdown_node.py +0 -11
  244. notionary/blocks/divider/divider_models.py +0 -12
  245. notionary/blocks/embed/__init__.py +0 -12
  246. notionary/blocks/embed/embed_element.py +0 -98
  247. notionary/blocks/embed/embed_markdown_node.py +0 -19
  248. notionary/blocks/embed/embed_models.py +0 -14
  249. notionary/blocks/equation/__init__.py +0 -13
  250. notionary/blocks/equation/equation_element.py +0 -133
  251. notionary/blocks/equation/equation_element_markdown_node.py +0 -23
  252. notionary/blocks/equation/equation_models.py +0 -11
  253. notionary/blocks/file/__init__.py +0 -23
  254. notionary/blocks/file/file_element.py +0 -133
  255. notionary/blocks/file/file_element_markdown_node.py +0 -24
  256. notionary/blocks/file/file_element_models.py +0 -39
  257. notionary/blocks/heading/__init__.py +0 -19
  258. notionary/blocks/heading/heading_element.py +0 -112
  259. notionary/blocks/heading/heading_markdown_node.py +0 -16
  260. notionary/blocks/heading/heading_models.py +0 -29
  261. notionary/blocks/image_block/__init__.py +0 -11
  262. notionary/blocks/image_block/image_element.py +0 -130
  263. notionary/blocks/image_block/image_markdown_node.py +0 -25
  264. notionary/blocks/image_block/image_models.py +0 -10
  265. notionary/blocks/markdown/markdown_builder.py +0 -525
  266. notionary/blocks/markdown/markdown_document_model.py +0 -0
  267. notionary/blocks/markdown/markdown_node.py +0 -25
  268. notionary/blocks/mixins/captions/__init__.py +0 -4
  269. notionary/blocks/mixins/captions/caption_markdown_node_mixin.py +0 -31
  270. notionary/blocks/mixins/captions/caption_mixin.py +0 -92
  271. notionary/blocks/mixins/file_upload/__init__.py +0 -3
  272. notionary/blocks/mixins/file_upload/file_upload_mixin.py +0 -320
  273. notionary/blocks/models.py +0 -174
  274. notionary/blocks/numbered_list/__init__.py +0 -16
  275. notionary/blocks/numbered_list/numbered_list_element.py +0 -65
  276. notionary/blocks/numbered_list/numbered_list_markdown_node.py +0 -17
  277. notionary/blocks/numbered_list/numbered_list_models.py +0 -17
  278. notionary/blocks/paragraph/__init__.py +0 -15
  279. notionary/blocks/paragraph/paragraph_element.py +0 -58
  280. notionary/blocks/paragraph/paragraph_markdown_node.py +0 -16
  281. notionary/blocks/paragraph/paragraph_models.py +0 -16
  282. notionary/blocks/pdf/__init__.py +0 -11
  283. notionary/blocks/pdf/pdf_element.py +0 -146
  284. notionary/blocks/pdf/pdf_markdown_node.py +0 -24
  285. notionary/blocks/pdf/pdf_models.py +0 -11
  286. notionary/blocks/quote/__init__.py +0 -14
  287. notionary/blocks/quote/quote_element.py +0 -75
  288. notionary/blocks/quote/quote_markdown_node.py +0 -16
  289. notionary/blocks/quote/quote_models.py +0 -18
  290. notionary/blocks/registry/__init__.py +0 -3
  291. notionary/blocks/registry/block_registry.py +0 -150
  292. notionary/blocks/rich_text/__init__.py +0 -33
  293. notionary/blocks/rich_text/rich_text_models.py +0 -221
  294. notionary/blocks/rich_text/text_inline_formatter.py +0 -456
  295. notionary/blocks/syntax_prompt_builder.py +0 -137
  296. notionary/blocks/table/__init__.py +0 -19
  297. notionary/blocks/table/table_element.py +0 -225
  298. notionary/blocks/table/table_markdown_node.py +0 -42
  299. notionary/blocks/table/table_models.py +0 -28
  300. notionary/blocks/table_of_contents/__init__.py +0 -17
  301. notionary/blocks/table_of_contents/table_of_contents_element.py +0 -80
  302. notionary/blocks/table_of_contents/table_of_contents_markdown_node.py +0 -21
  303. notionary/blocks/table_of_contents/table_of_contents_models.py +0 -18
  304. notionary/blocks/todo/__init__.py +0 -12
  305. notionary/blocks/todo/todo_element.py +0 -81
  306. notionary/blocks/todo/todo_markdown_node.py +0 -21
  307. notionary/blocks/todo/todo_models.py +0 -18
  308. notionary/blocks/toggle/__init__.py +0 -12
  309. notionary/blocks/toggle/toggle_element.py +0 -112
  310. notionary/blocks/toggle/toggle_markdown_node.py +0 -31
  311. notionary/blocks/toggle/toggle_models.py +0 -17
  312. notionary/blocks/toggleable_heading/__init__.py +0 -11
  313. notionary/blocks/toggleable_heading/toggleable_heading_element.py +0 -115
  314. notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +0 -34
  315. notionary/blocks/types.py +0 -130
  316. notionary/blocks/video/__init__.py +0 -11
  317. notionary/blocks/video/video_element.py +0 -187
  318. notionary/blocks/video/video_element_models.py +0 -10
  319. notionary/blocks/video/video_markdown_node.py +0 -26
  320. notionary/comments/__init__.py +0 -26
  321. notionary/database/__init__.py +0 -4
  322. notionary/database/database.py +0 -480
  323. notionary/database/database_filter_builder.py +0 -173
  324. notionary/database/database_provider.py +0 -227
  325. notionary/database/exceptions.py +0 -13
  326. notionary/database/factory.py +0 -0
  327. notionary/database/models.py +0 -337
  328. notionary/database/notion_database.py +0 -487
  329. notionary/file_upload/__init__.py +0 -7
  330. notionary/page/client.py +0 -124
  331. notionary/page/markdown_whitespace_processor.py +0 -129
  332. notionary/page/models.py +0 -322
  333. notionary/page/notion_page.py +0 -674
  334. notionary/page/page_content_deleting_service.py +0 -117
  335. notionary/page/page_content_writer.py +0 -80
  336. notionary/page/property_formatter.py +0 -99
  337. notionary/page/reader/handler/__init__.py +0 -19
  338. notionary/page/reader/handler/base_block_renderer.py +0 -44
  339. notionary/page/reader/handler/block_processing_context.py +0 -35
  340. notionary/page/reader/handler/block_rendering_context.py +0 -48
  341. notionary/page/reader/handler/column_list_renderer.py +0 -51
  342. notionary/page/reader/handler/column_renderer.py +0 -60
  343. notionary/page/reader/handler/equation_renderer.py +0 -0
  344. notionary/page/reader/handler/line_renderer.py +0 -73
  345. notionary/page/reader/handler/numbered_list_renderer.py +0 -85
  346. notionary/page/reader/handler/toggle_renderer.py +0 -69
  347. notionary/page/reader/handler/toggleable_heading_renderer.py +0 -89
  348. notionary/page/reader/page_content_retriever.py +0 -81
  349. notionary/page/search_filter_builder.py +0 -132
  350. notionary/page/utils.py +0 -60
  351. notionary/page/writer/handler/__init__.py +0 -24
  352. notionary/page/writer/handler/code_handler.py +0 -72
  353. notionary/page/writer/handler/column_handler.py +0 -141
  354. notionary/page/writer/handler/column_list_handler.py +0 -139
  355. notionary/page/writer/handler/equation_handler.py +0 -74
  356. notionary/page/writer/handler/line_handler.py +0 -35
  357. notionary/page/writer/handler/line_processing_context.py +0 -54
  358. notionary/page/writer/handler/regular_line_handler.py +0 -86
  359. notionary/page/writer/handler/table_handler.py +0 -66
  360. notionary/page/writer/handler/toggle_handler.py +0 -159
  361. notionary/page/writer/handler/toggleable_heading_handler.py +0 -174
  362. notionary/page/writer/markdown_to_notion_converter.py +0 -139
  363. notionary/page/writer/markdown_to_notion_converter_context.py +0 -30
  364. notionary/page/writer/markdown_to_notion_text_length_post_processor.py +0 -0
  365. notionary/page/writer/notion_text_length_processor.py +0 -150
  366. notionary/schemas/__init__.py +0 -3
  367. notionary/schemas/base.py +0 -73
  368. notionary/shared/__init__.py +0 -3
  369. notionary/shared/name_to_id_resolver.py +0 -203
  370. notionary/telemetry/__init__.py +0 -19
  371. notionary/telemetry/service.py +0 -136
  372. notionary/telemetry/views.py +0 -73
  373. notionary/user/base_notion_user.py +0 -53
  374. notionary/user/models.py +0 -84
  375. notionary/user/notion_bot_user.py +0 -226
  376. notionary/user/notion_user.py +0 -255
  377. notionary/user/notion_user_manager.py +0 -101
  378. notionary/util/__init__.py +0 -15
  379. notionary/util/concurrency_limiter.py +0 -0
  380. notionary/util/factory_decorator.py +0 -0
  381. notionary/util/factory_only.py +0 -37
  382. notionary/util/fuzzy.py +0 -75
  383. notionary/util/page_id_utils.py +0 -27
  384. notionary/util/singleton.py +0 -18
  385. notionary/util/singleton_metaclass.py +0 -22
  386. notionary/workspace.py +0 -105
  387. notionary-0.2.26.dist-info/RECORD +0 -202
@@ -1,159 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import re
4
-
5
- from notionary.blocks.toggle.toggle_element import ToggleElement
6
- from notionary.page.writer.handler import (
7
- LineHandler,
8
- LineProcessingContext,
9
- ParentBlockContext,
10
- )
11
-
12
-
13
- class ToggleHandler(LineHandler):
14
- """Handles regular toggle blocks with ultra-simplified +++ syntax."""
15
-
16
- def __init__(self):
17
- super().__init__()
18
- # Updated: Support both "+++title" and "+++ title"
19
- self._start_pattern = re.compile(r"^[+]{3}\s*(.+)$", re.IGNORECASE)
20
- self._end_pattern = re.compile(r"^[+]{3}\s*$")
21
-
22
- def _can_handle(self, context: LineProcessingContext) -> bool:
23
- return (
24
- self._is_toggle_start(context)
25
- or self._is_toggle_end(context)
26
- or self._is_toggle_content(context)
27
- )
28
-
29
- async def _process(self, context: LineProcessingContext) -> None:
30
- # Explicit, readable branches (small duplication is acceptable)
31
- if self._is_toggle_start(context):
32
- await self._start_toggle(context)
33
- context.was_processed = True
34
- context.should_continue = True
35
-
36
- if self._is_toggle_end(context):
37
- await self._finalize_toggle(context)
38
- context.was_processed = True
39
- context.should_continue = True
40
-
41
- if self._is_toggle_content(context):
42
- self._add_toggle_content(context)
43
- context.was_processed = True
44
- context.should_continue = True
45
-
46
- def _is_toggle_start(self, context: LineProcessingContext) -> bool:
47
- """Check if line starts a toggle (+++ Title or +++Title)."""
48
- line = context.line.strip()
49
-
50
- # Must match our pattern (now allows optional space)
51
- if not self._start_pattern.match(line):
52
- return False
53
-
54
- # But NOT match toggleable heading pattern (has # after +++)
55
- # Updated: Support both "+++#title" and "+++ # title"
56
- toggleable_heading_pattern = re.compile(
57
- r"^[+]{3}\s*#{1,3}\s+.+$", re.IGNORECASE
58
- )
59
- if toggleable_heading_pattern.match(line):
60
- return False
61
-
62
- return True
63
-
64
- def _is_toggle_end(self, context: LineProcessingContext) -> bool:
65
- """Check if we need to end a toggle (+++)."""
66
- if not self._end_pattern.match(context.line.strip()):
67
- return False
68
-
69
- if not context.parent_stack:
70
- return False
71
-
72
- # Check if top of stack is a Toggle
73
- current_parent = context.parent_stack[-1]
74
- return issubclass(current_parent.element_type, ToggleElement)
75
-
76
- async def _start_toggle(self, context: LineProcessingContext) -> None:
77
- """Start a new toggle block."""
78
- toggle_element = ToggleElement()
79
-
80
- # Create the block
81
- result = await toggle_element.markdown_to_notion(context.line)
82
- if not result:
83
- return
84
-
85
- block = result
86
-
87
- # Push to parent stack
88
- parent_context = ParentBlockContext(
89
- block=block,
90
- element_type=ToggleElement,
91
- child_lines=[],
92
- )
93
- context.parent_stack.append(parent_context)
94
-
95
- async def _finalize_toggle(self, context: LineProcessingContext) -> None:
96
- """Finalize a toggle block and add it to result_blocks."""
97
- toggle_context = context.parent_stack.pop()
98
-
99
- if toggle_context.has_children():
100
- all_children = await self._get_all_children(
101
- toggle_context, context.block_registry
102
- )
103
- toggle_context.block.toggle.children = all_children
104
-
105
- # Check if we have a parent context to add this toggle to
106
- if context.parent_stack:
107
- # Add this toggle as a child block to the parent
108
- parent_context = context.parent_stack[-1]
109
- parent_context.add_child_block(toggle_context.block)
110
- else:
111
- # No parent, add to top level
112
- context.result_blocks.append(toggle_context.block)
113
-
114
- def _is_toggle_content(self, context: LineProcessingContext) -> bool:
115
- """Check if we're inside a toggle context and should handle content."""
116
- if not context.parent_stack:
117
- return False
118
-
119
- current_parent = context.parent_stack[-1]
120
- if not issubclass(current_parent.element_type, ToggleElement):
121
- return False
122
-
123
- # Handle all content inside toggle (not start/end patterns)
124
- line = context.line.strip()
125
- return not (self._start_pattern.match(line) or self._end_pattern.match(line))
126
-
127
- def _add_toggle_content(self, context: LineProcessingContext) -> None:
128
- """Add content to the current toggle context."""
129
- context.parent_stack[-1].add_child_line(context.line)
130
-
131
- async def _convert_children_text(self, text: str, block_registry) -> list:
132
- """Convert children text to blocks."""
133
- from notionary.page.writer.markdown_to_notion_converter import (
134
- MarkdownToNotionConverter,
135
- )
136
-
137
- if not text.strip():
138
- return []
139
-
140
- child_converter = MarkdownToNotionConverter(block_registry)
141
- return await child_converter.process_lines(text)
142
-
143
- async def _get_all_children(self, parent_context, block_registry) -> list:
144
- """Helper method to combine text-based and direct block children."""
145
- children_blocks = []
146
-
147
- # Process text lines
148
- if parent_context.child_lines:
149
- children_text = "\n".join(parent_context.child_lines)
150
- text_blocks = await self._convert_children_text(
151
- children_text, block_registry
152
- )
153
- children_blocks.extend(text_blocks)
154
-
155
- # Add direct blocks (like processed columns)
156
- if hasattr(parent_context, "child_blocks") and parent_context.child_blocks:
157
- children_blocks.extend(parent_context.child_blocks)
158
-
159
- return children_blocks
@@ -1,174 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import re
4
-
5
- from notionary.blocks.models import BlockCreateRequest
6
- from notionary.blocks.toggleable_heading.toggleable_heading_element import (
7
- ToggleableHeadingElement,
8
- )
9
- from notionary.blocks.types import BlockType
10
- from notionary.page.writer.handler import (
11
- LineHandler,
12
- LineProcessingContext,
13
- ParentBlockContext,
14
- )
15
-
16
-
17
- class ToggleableHeadingHandler(LineHandler):
18
- """Handles toggleable heading blocks with +++# syntax."""
19
-
20
- def __init__(self):
21
- super().__init__()
22
- # Updated: Support both "+++# title" and "+++#title"
23
- self._start_pattern = re.compile(
24
- r"^[+]{3}\s*(?P<level>#{1,3})\s*(.+)$", re.IGNORECASE
25
- )
26
- # +++
27
- self._end_pattern = re.compile(r"^[+]{3}\s*$")
28
-
29
- def _can_handle(self, context: LineProcessingContext) -> bool:
30
- return (
31
- self._is_toggleable_heading_start(context)
32
- or self._is_toggleable_heading_end(context)
33
- or self._is_toggleable_heading_content(context)
34
- )
35
-
36
- async def _process(self, context: LineProcessingContext) -> None:
37
- """Process toggleable heading start, end, or content with unified handling."""
38
-
39
- async def _handle(action):
40
- await action(context)
41
- context.was_processed = True
42
- context.should_continue = True
43
- return True
44
-
45
- if self._is_toggleable_heading_start(context):
46
- return await _handle(self._start_toggleable_heading)
47
- if self._is_toggleable_heading_end(context):
48
- return await _handle(self._finalize_toggleable_heading)
49
- if self._is_toggleable_heading_content(context):
50
- return await _handle(self._add_toggleable_heading_content)
51
-
52
- def _is_toggleable_heading_start(self, context: LineProcessingContext) -> bool:
53
- """Check if line starts a toggleable heading (+++# "Title" or +++#"Title")."""
54
- return self._start_pattern.match(context.line.strip()) is not None
55
-
56
- def _is_toggleable_heading_end(self, context: LineProcessingContext) -> bool:
57
- """Check if we need to end a toggleable heading (+++)."""
58
- if not self._end_pattern.match(context.line.strip()):
59
- return False
60
-
61
- if not context.parent_stack:
62
- return False
63
-
64
- # Check if top of stack is a ToggleableHeading
65
- current_parent = context.parent_stack[-1]
66
- return issubclass(current_parent.element_type, ToggleableHeadingElement)
67
-
68
- async def _start_toggleable_heading(self, context: LineProcessingContext) -> None:
69
- """Start a new toggleable heading block."""
70
- toggleable_heading_element = ToggleableHeadingElement()
71
-
72
- # Create the block
73
- result = await toggleable_heading_element.markdown_to_notion(context.line)
74
- if not result:
75
- return
76
-
77
- block = result
78
-
79
- # Push to parent stack
80
- parent_context = ParentBlockContext(
81
- block=block,
82
- element_type=ToggleableHeadingElement,
83
- child_lines=[],
84
- )
85
- context.parent_stack.append(parent_context)
86
-
87
- def _is_toggleable_heading_content(self, context: LineProcessingContext) -> bool:
88
- """Check if we're inside a toggleable heading context and should handle content."""
89
- if not context.parent_stack:
90
- return False
91
-
92
- current_parent = context.parent_stack[-1]
93
- if not issubclass(current_parent.element_type, ToggleableHeadingElement):
94
- return False
95
-
96
- # Handle all content inside toggleable heading (not start/end patterns)
97
- line = context.line.strip()
98
- return not (self._start_pattern.match(line) or self._end_pattern.match(line))
99
-
100
- async def _add_toggleable_heading_content(
101
- self, context: LineProcessingContext
102
- ) -> None:
103
- """Add content to the current toggleable heading context."""
104
- context.parent_stack[-1].add_child_line(context.line)
105
-
106
- async def _finalize_toggleable_heading(
107
- self, context: LineProcessingContext
108
- ) -> None:
109
- """Finalize a toggleable heading block and add it to result_blocks."""
110
- heading_context = context.parent_stack.pop()
111
-
112
- if heading_context.has_children():
113
- all_children = await self._get_all_children(
114
- heading_context, context.block_registry
115
- )
116
- self._assign_heading_children(heading_context.block, all_children)
117
-
118
- # Check if we have a parent context to add this heading to
119
- if context.parent_stack:
120
- # Add this heading as a child block to the parent
121
- parent_context = context.parent_stack[-1]
122
- if hasattr(parent_context, "add_child_block"):
123
- parent_context.add_child_block(heading_context.block)
124
- else:
125
- # Fallback: add to result_blocks for backward compatibility
126
- context.result_blocks.append(heading_context.block)
127
- else:
128
- # No parent, add to top level
129
- context.result_blocks.append(heading_context.block)
130
-
131
- async def _get_all_children(
132
- self, parent_context: ParentBlockContext, block_registry
133
- ) -> list:
134
- """Helper method to combine text-based and direct block children."""
135
- children_blocks = []
136
-
137
- # Process text lines
138
- if parent_context.child_lines:
139
- children_text = "\n".join(parent_context.child_lines)
140
- text_blocks = await self._convert_children_text(
141
- children_text, block_registry
142
- )
143
- children_blocks.extend(text_blocks)
144
-
145
- # Add direct blocks
146
- if hasattr(parent_context, "child_blocks") and parent_context.child_blocks:
147
- children_blocks.extend(parent_context.child_blocks)
148
-
149
- return children_blocks
150
-
151
- def _assign_heading_children(
152
- self, parent_block: BlockCreateRequest, children: list[BlockCreateRequest]
153
- ) -> None:
154
- """Assign children to toggleable heading blocks."""
155
- block_type = parent_block.type
156
-
157
- if block_type == BlockType.HEADING_1:
158
- parent_block.heading_1.children = children
159
- elif block_type == BlockType.HEADING_2:
160
- parent_block.heading_2.children = children
161
- elif block_type == BlockType.HEADING_3:
162
- parent_block.heading_3.children = children
163
-
164
- async def _convert_children_text(self, text: str, block_registry) -> list:
165
- """Convert children text to blocks."""
166
- from notionary.page.writer.markdown_to_notion_converter import (
167
- MarkdownToNotionConverter,
168
- )
169
-
170
- if not text.strip():
171
- return []
172
-
173
- child_converter = MarkdownToNotionConverter(block_registry)
174
- return await child_converter.process_lines(text)
@@ -1,139 +0,0 @@
1
- from notionary.blocks.models import BlockCreateRequest
2
- from notionary.blocks.registry.block_registry import BlockRegistry
3
- from notionary.page.writer.handler import (
4
- CodeHandler,
5
- ColumnHandler,
6
- ColumnListHandler,
7
- EquationHandler,
8
- LineProcessingContext,
9
- ParentBlockContext,
10
- RegularLineHandler,
11
- TableHandler,
12
- ToggleableHeadingHandler,
13
- ToggleHandler,
14
- )
15
- from notionary.page.writer.notion_text_length_processor import (
16
- NotionTextLengthProcessor,
17
- )
18
- from notionary.util.logging_mixin import LoggingMixin
19
-
20
-
21
- class HandlerOrderValidationError(RuntimeError):
22
- """Raised when handler chain order is incorrect."""
23
-
24
- pass
25
-
26
-
27
- class MarkdownToNotionConverter(LoggingMixin):
28
- """Converts Markdown text to Notion API block format with unified stack-based processing."""
29
-
30
- def __init__(self, block_registry: BlockRegistry) -> None:
31
- self._block_registry = block_registry
32
- self._text_length_post_processor = NotionTextLengthProcessor()
33
- self._setup_handler_chain()
34
-
35
- async def convert(self, markdown_text: str) -> list[BlockCreateRequest]:
36
- if not markdown_text.strip():
37
- return []
38
-
39
- all_blocks = await self.process_lines(markdown_text)
40
-
41
- # Apply text length post-processing (truncation)
42
- all_blocks = self._text_length_post_processor.process(all_blocks)
43
-
44
- return all_blocks
45
-
46
- async def process_lines(self, text: str) -> list[BlockCreateRequest]:
47
- lines = text.split("\n")
48
- result_blocks: list[BlockCreateRequest] = []
49
- parent_stack: list[ParentBlockContext] = []
50
-
51
- i = 0
52
- while i < len(lines):
53
- line = lines[i]
54
-
55
- context = LineProcessingContext(
56
- line=line,
57
- result_blocks=result_blocks,
58
- parent_stack=parent_stack,
59
- block_registry=self._block_registry,
60
- all_lines=lines,
61
- current_line_index=i,
62
- lines_consumed=0,
63
- )
64
-
65
- await self._handler_chain.handle(context)
66
-
67
- # Skip consumed lines
68
- i += 1 + context.lines_consumed
69
-
70
- if context.should_continue:
71
- continue
72
-
73
- return result_blocks
74
-
75
- def _setup_handler_chain(self) -> None:
76
- code_handler = CodeHandler()
77
- equation_handler = EquationHandler()
78
- table_handler = TableHandler()
79
- column_list_handler = ColumnListHandler()
80
- column_handler = ColumnHandler()
81
- toggle_handler = ToggleHandler()
82
- toggleable_heading_handler = ToggleableHeadingHandler()
83
- regular_handler = RegularLineHandler()
84
-
85
- # Create handler chain
86
- code_handler.set_next(equation_handler).set_next(table_handler).set_next(
87
- column_handler
88
- ).set_next(column_list_handler).set_next(toggleable_heading_handler).set_next(
89
- toggle_handler
90
- ).set_next(
91
- regular_handler
92
- )
93
-
94
- self._handler_chain = code_handler
95
-
96
- # Validate critical order - only log/error if something is wrong
97
- self._validate_handler_order(
98
- [
99
- code_handler,
100
- equation_handler,
101
- table_handler,
102
- column_handler,
103
- column_list_handler,
104
- toggleable_heading_handler,
105
- toggle_handler,
106
- regular_handler,
107
- ]
108
- )
109
-
110
- def _validate_handler_order(self, handlers) -> None:
111
- """Validate critical handler positioning rules - only warns/errors when needed."""
112
- handler_classes = [handler.__class__ for handler in handlers]
113
-
114
- # Critical: ColumnHandler MUST come before ColumnListHandler
115
- try:
116
- column_handler_pos = handler_classes.index(ColumnHandler)
117
- column_list_handler_pos = handler_classes.index(ColumnListHandler)
118
-
119
- if column_handler_pos >= column_list_handler_pos:
120
- error_msg = (
121
- f"CRITICAL: ColumnHandler must come BEFORE ColumnListHandler. "
122
- f"Current order: ColumnHandler at {column_handler_pos}, ColumnListHandler at {column_list_handler_pos}. "
123
- f"Fix: Move ColumnHandler before ColumnListHandler in _setup_handler_chain()"
124
- )
125
- self.logger.error(error_msg)
126
- raise HandlerOrderValidationError(error_msg)
127
-
128
- except ValueError as e:
129
- error_msg = f"Missing required handlers in chain: {e}"
130
- self.logger.error(error_msg)
131
- raise HandlerOrderValidationError(error_msg)
132
-
133
- # Critical: RegularLineHandler should be last (fallback)
134
- if handler_classes[-1] != RegularLineHandler:
135
- error_msg = (
136
- f"WARNING: RegularLineHandler should be last handler (fallback), "
137
- f"but {handler_classes[-1].__name__} is at the end"
138
- )
139
- self.logger.warning(error_msg)
@@ -1,30 +0,0 @@
1
- # notionary/blocks/context/conversion_context.py
2
- from __future__ import annotations
3
-
4
- from typing import Optional, TYPE_CHECKING
5
- from dataclasses import dataclass
6
-
7
- if TYPE_CHECKING:
8
- from notionary.database.client import NotionDatabaseClient
9
-
10
-
11
- @dataclass
12
- class ConverterContext:
13
- """
14
- Context object that provides dependencies for block conversion operations.
15
- """
16
-
17
- page_id: Optional[str] = None
18
- database_client: Optional["NotionDatabaseClient"] = None
19
-
20
- def require_database_client(self) -> NotionDatabaseClient:
21
- """Get database client or raise if not available."""
22
- if self.database_client is None:
23
- raise ValueError("Database client required but not provided in context")
24
- return self.database_client
25
-
26
- def require_page_id(self) -> str:
27
- """Get parent page ID or raise if not available."""
28
- if self.page_id is None:
29
- raise ValueError("Parent page ID required but not provided in context")
30
- return self.page_id
@@ -1,150 +0,0 @@
1
- """
2
- Post-processor for handling Notion API text length limitations.
3
-
4
- Handles text length validation and truncation for blocks that exceed
5
- Notion's rich_text character limit of 2000 characters per element.
6
- """
7
-
8
- from typing import TypeGuard, Union
9
-
10
- from notionary.blocks.models import BlockCreateRequest
11
- from notionary.blocks.rich_text.rich_text_models import RichTextObject
12
- from notionary.blocks.types import HasRichText, HasChildren
13
- from notionary.util import LoggingMixin
14
-
15
-
16
- class NotionTextLengthProcessor(LoggingMixin):
17
- """
18
- Processes Notion blocks to ensure text content doesn't exceed API limits.
19
-
20
- The Notion API has a limit of 2000 characters per rich_text element.
21
- This processor truncates content that exceeds the specified limit.
22
- """
23
-
24
- DEFAULT_MAX_LENGTH = 1900 # Leave some buffer under the 2000 limit
25
-
26
- def __init__(self, max_text_length: int = DEFAULT_MAX_LENGTH) -> None:
27
- """
28
- Initialize the processor.
29
-
30
- Args:
31
- max_text_length: Maximum allowed text length (default: 1900)
32
- """
33
- if max_text_length <= 0:
34
- raise ValueError("max_text_length must be positive")
35
- if max_text_length > 2000:
36
- self.logger.warning(
37
- "max_text_length (%d) exceeds Notion's limit of 2000 characters",
38
- max_text_length,
39
- )
40
-
41
- self.max_text_length = max_text_length
42
-
43
- def process(self, blocks: list[BlockCreateRequest]) -> list[BlockCreateRequest]:
44
- """
45
- Process blocks to fix text length limits.
46
- """
47
- if not blocks:
48
- return blocks
49
-
50
- flattened_blocks = self._flatten_block_list(blocks)
51
- return [self._process_single_block(block) for block in flattened_blocks]
52
-
53
- def _process_single_block(self, block: BlockCreateRequest) -> BlockCreateRequest:
54
- """
55
- Process a single block to fix text length issues.
56
- """
57
- block_copy = block.model_copy(deep=True)
58
-
59
- block_content = self._extract_block_content(block_copy)
60
-
61
- if block_content is not None:
62
- self._fix_content_text_lengths(block_content)
63
-
64
- return block_copy
65
-
66
- def _extract_block_content(self, block: BlockCreateRequest) -> object | None:
67
- """
68
- Extract the content object from a block using type-safe attribute access.
69
- """
70
- # Get the block's content using the block type as attribute name
71
- # We assume block.type always exists as per the BlockCreateRequest structure
72
- content = getattr(block, block.type, None)
73
-
74
- # Verify it's a valid content object (has rich_text or children)
75
- if content and (
76
- self._is_rich_text_container(content)
77
- or self._is_children_container(content)
78
- ):
79
- return content
80
-
81
- return None
82
-
83
- def _fix_content_text_lengths(self, content: object) -> None:
84
- """
85
- Fix text lengths in a content object and its children recursively.
86
- """
87
- # Process rich_text if present
88
- if self._is_rich_text_container(content):
89
- self._truncate_rich_text_content(content.rich_text)
90
-
91
- # Process children recursively if present
92
- if self._is_children_container(content):
93
- for child in content.children:
94
- child_content = self._extract_block_content(child)
95
- if child_content:
96
- self._fix_content_text_lengths(child_content)
97
-
98
- def _truncate_rich_text_content(self, rich_text_list: list[RichTextObject]) -> None:
99
- """
100
- Truncate text content in rich text objects that exceed the limit.
101
- """
102
- for rich_text_obj in rich_text_list:
103
- if not self._is_text_rich_text_object(rich_text_obj):
104
- continue
105
-
106
- content = rich_text_obj.text.content
107
- if len(content) > self.max_text_length:
108
- self.logger.warning(
109
- "Truncating text content from %d to %d characters",
110
- len(content),
111
- self.max_text_length,
112
- )
113
- # Truncate the content
114
- rich_text_obj.text.content = content[: self.max_text_length]
115
-
116
- def _flatten_block_list(
117
- self, blocks: list[Union[BlockCreateRequest, list]]
118
- ) -> list[BlockCreateRequest]:
119
- """
120
- Flatten a potentially nested list of blocks.
121
- """
122
- flattened: list[BlockCreateRequest] = []
123
-
124
- for item in blocks:
125
- if isinstance(item, list):
126
- # Recursively flatten nested lists
127
- flattened.extend(self._flatten_block_list(item))
128
- else:
129
- # Add individual block
130
- flattened.append(item)
131
-
132
- return flattened
133
-
134
- def _is_rich_text_container(self, obj: object) -> TypeGuard[HasRichText]:
135
- """Type guard to check if an object has rich_text attribute."""
136
- return hasattr(obj, "rich_text") and isinstance(getattr(obj, "rich_text"), list)
137
-
138
- def _is_children_container(self, obj: object) -> TypeGuard[HasChildren]:
139
- """Type guard to check if an object has children attribute."""
140
- return hasattr(obj, "children") and isinstance(getattr(obj, "children"), list)
141
-
142
- def _is_text_rich_text_object(
143
- self, rich_text_obj: RichTextObject
144
- ) -> TypeGuard[RichTextObject]:
145
- """Type guard to check if a RichTextObject is of type 'text' with content."""
146
- return (
147
- rich_text_obj.type == "text"
148
- and rich_text_obj.text is not None
149
- and rich_text_obj.text.content is not None
150
- )
@@ -1,3 +0,0 @@
1
- from .base import NotionContentSchema
2
-
3
- __all__ = ["NotionContentSchema"]