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,49 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.rich_text.rich_text_markdown_converter import RichTextToMarkdownConverter
4
+ from notionary.blocks.schemas import Block, BlockType
5
+ from notionary.page.content.renderer.context import MarkdownRenderingContext
6
+ from notionary.page.content.renderer.renderers.base import BlockRenderer
7
+ from notionary.page.content.syntax import SyntaxRegistry
8
+
9
+
10
+ class QuoteRenderer(BlockRenderer):
11
+ def __init__(
12
+ self,
13
+ syntax_registry: SyntaxRegistry | None = None,
14
+ rich_text_markdown_converter: RichTextToMarkdownConverter | None = None,
15
+ ) -> None:
16
+ super().__init__(syntax_registry=syntax_registry)
17
+ self._rich_text_markdown_converter = rich_text_markdown_converter or RichTextToMarkdownConverter()
18
+
19
+ @override
20
+ def _can_handle(self, block: Block) -> bool:
21
+ return block.type == BlockType.QUOTE
22
+
23
+ @override
24
+ async def _process(self, context: MarkdownRenderingContext) -> None:
25
+ markdown = await self._convert_quote_to_markdown(context.block)
26
+
27
+ if not markdown:
28
+ context.markdown_result = ""
29
+ return
30
+
31
+ syntax = self._syntax_registry.get_quote_syntax()
32
+ quote_lines = markdown.split("\n")
33
+ quote_markdown = "\n".join(f"{syntax.start_delimiter}{line}" for line in quote_lines)
34
+
35
+ if context.indent_level > 0:
36
+ quote_markdown = context.indent_text(quote_markdown)
37
+
38
+ children_markdown = await context.render_children_with_additional_indent(1)
39
+
40
+ if children_markdown:
41
+ context.markdown_result = f"{quote_markdown}\n{children_markdown}"
42
+ else:
43
+ context.markdown_result = quote_markdown
44
+
45
+ async def _convert_quote_to_markdown(self, block: Block) -> str | None:
46
+ if not block.quote or not block.quote.rich_text:
47
+ return None
48
+
49
+ return await self._rich_text_markdown_converter.to_markdown(block.quote.rich_text)
@@ -0,0 +1,115 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.rich_text.rich_text_markdown_converter import RichTextToMarkdownConverter
4
+ from notionary.blocks.schemas import Block, BlockType
5
+ from notionary.page.content.renderer.context import MarkdownRenderingContext
6
+ from notionary.page.content.renderer.renderers.base import BlockRenderer
7
+
8
+
9
+ class TableRenderer(BlockRenderer):
10
+ MINIMUM_COLUMN_WIDTH = 3
11
+
12
+ def __init__(self, rich_text_markdown_converter: RichTextToMarkdownConverter | None = None) -> None:
13
+ super().__init__()
14
+ self._rich_text_markdown_converter = rich_text_markdown_converter or RichTextToMarkdownConverter()
15
+ self._table_syntax = self._syntax_registry.get_table_syntax()
16
+
17
+ @override
18
+ def _can_handle(self, block: Block) -> bool:
19
+ return block.type == BlockType.TABLE
20
+
21
+ @override
22
+ async def _process(self, context: MarkdownRenderingContext) -> None:
23
+ table_markdown = await self._build_table_markdown(context.block)
24
+
25
+ if not table_markdown:
26
+ context.markdown_result = ""
27
+ return
28
+
29
+ if context.indent_level > 0:
30
+ table_markdown = context.indent_text(table_markdown)
31
+
32
+ children_markdown = await context.render_children_with_additional_indent(1)
33
+
34
+ if children_markdown:
35
+ context.markdown_result = f"{table_markdown}\n{children_markdown}"
36
+ else:
37
+ context.markdown_result = table_markdown
38
+
39
+ async def _build_table_markdown(self, block: Block) -> str:
40
+ if not block.table or not block.has_children or not block.children:
41
+ return ""
42
+
43
+ rows = []
44
+ for row_block in block.children:
45
+ if row_block.type != BlockType.TABLE_ROW or not row_block.table_row:
46
+ continue
47
+
48
+ row_cells = await self._extract_row_cells(row_block)
49
+ rows.append(row_cells)
50
+
51
+ if not rows:
52
+ return ""
53
+
54
+ max_columns = max(len(row) for row in rows)
55
+ normalized_rows = self._normalize_row_lengths(rows, max_columns)
56
+ column_widths = self._calculate_column_widths(normalized_rows, max_columns)
57
+
58
+ markdown_lines = []
59
+
60
+ first_row = normalized_rows[0]
61
+ formatted_first_row = self._format_row(first_row, column_widths)
62
+ markdown_lines.append(formatted_first_row)
63
+
64
+ separator_line = self._create_separator_line(column_widths)
65
+ markdown_lines.append(separator_line)
66
+
67
+ remaining_rows = normalized_rows[1:]
68
+ for row in remaining_rows:
69
+ formatted_row = self._format_row(row, column_widths)
70
+ markdown_lines.append(formatted_row)
71
+
72
+ return "\n".join(markdown_lines)
73
+
74
+ def _normalize_row_lengths(self, rows: list[list[str]], target_length: int) -> list[list[str]]:
75
+ return [row + [""] * (target_length - len(row)) for row in rows]
76
+
77
+ def _calculate_column_widths(self, rows: list[list[str]], num_columns: int) -> list[int]:
78
+ widths = [max(len(row[i]) for row in rows) for i in range(num_columns)]
79
+ return [max(width, self.MINIMUM_COLUMN_WIDTH) for width in widths]
80
+
81
+ def _format_row(self, cells: list[str], column_widths: list[int]) -> str:
82
+ centered_cells = [cell.center(column_widths[i]) for i, cell in enumerate(cells)]
83
+ delimiter = self._table_syntax.start_delimiter
84
+ return f"{delimiter} {f' {delimiter} '.join(centered_cells)} {delimiter}"
85
+
86
+ def _create_separator_line(self, column_widths: list[int]) -> str:
87
+ separators = ["-" * width for width in column_widths]
88
+ delimiter = self._table_syntax.start_delimiter
89
+ return f"{delimiter} {f' {delimiter} '.join(separators)} {delimiter}"
90
+
91
+ def _has_column_header(self, block: Block) -> bool:
92
+ if not block.table:
93
+ return False
94
+ return block.table.has_column_header or False
95
+
96
+ def _has_row_header(self, block: Block) -> bool:
97
+ if not block.table:
98
+ return False
99
+ return block.table.has_row_header or False
100
+
101
+ def _get_table_width(self, block: Block) -> int:
102
+ if not block.table:
103
+ return 0
104
+ return block.table.table_width or 0
105
+
106
+ async def _extract_row_cells(self, row_block: Block) -> list[str]:
107
+ if not row_block.table_row or not row_block.table_row.cells:
108
+ return []
109
+
110
+ cells = []
111
+ for cell in row_block.table_row.cells:
112
+ cell_text = await self._rich_text_markdown_converter.to_markdown(cell)
113
+ cells.append(cell_text or "")
114
+
115
+ return cells
@@ -0,0 +1,26 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.schemas import Block, BlockType
4
+ from notionary.page.content.renderer.context import MarkdownRenderingContext
5
+ from notionary.page.content.renderer.renderers.base import BlockRenderer
6
+
7
+
8
+ class TableOfContentsRenderer(BlockRenderer):
9
+ @override
10
+ def _can_handle(self, block: Block) -> bool:
11
+ return block.type == BlockType.TABLE_OF_CONTENTS
12
+
13
+ @override
14
+ async def _process(self, context: MarkdownRenderingContext) -> None:
15
+ syntax = self._syntax_registry.get_table_of_contents_syntax()
16
+ toc_markdown = syntax.start_delimiter
17
+
18
+ if context.indent_level > 0:
19
+ toc_markdown = context.indent_text(toc_markdown)
20
+
21
+ children_markdown = await context.render_children_with_additional_indent(1)
22
+
23
+ if children_markdown:
24
+ context.markdown_result = f"{toc_markdown}\n{children_markdown}"
25
+ else:
26
+ context.markdown_result = toc_markdown
@@ -0,0 +1,17 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.enums import BlockType
4
+ from notionary.blocks.schemas import Block
5
+ from notionary.page.content.renderer.context import MarkdownRenderingContext
6
+ from notionary.page.content.renderer.renderers.base import BlockRenderer
7
+
8
+
9
+ class TableRowHandler(BlockRenderer):
10
+ @override
11
+ def _can_handle(self, block: Block) -> bool:
12
+ return block.type == BlockType.TABLE_ROW
13
+
14
+ @override
15
+ async def _process(self, context: MarkdownRenderingContext) -> None:
16
+ """Table rows are internally handled by table as the structure supports it"""
17
+ pass
@@ -0,0 +1,56 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.enums import BlockType
4
+ from notionary.blocks.rich_text.rich_text_markdown_converter import RichTextToMarkdownConverter
5
+ from notionary.blocks.schemas import Block
6
+ from notionary.page.content.renderer.context import MarkdownRenderingContext
7
+ from notionary.page.content.renderer.renderers.base import BlockRenderer
8
+ from notionary.page.content.syntax import SyntaxRegistry
9
+
10
+
11
+ class TodoRenderer(BlockRenderer):
12
+ def __init__(
13
+ self,
14
+ syntax_registry: SyntaxRegistry | None = None,
15
+ rich_text_markdown_converter: RichTextToMarkdownConverter | None = None,
16
+ ) -> None:
17
+ super().__init__(syntax_registry=syntax_registry)
18
+ self._rich_text_markdown_converter = rich_text_markdown_converter or RichTextToMarkdownConverter()
19
+
20
+ @override
21
+ def _can_handle(self, block: Block) -> bool:
22
+ return block.type == BlockType.TO_DO
23
+
24
+ @override
25
+ async def _process(self, context: MarkdownRenderingContext) -> None:
26
+ is_checked, content = await self._extract_todo_info(context.block)
27
+
28
+ if not content:
29
+ context.markdown_result = ""
30
+ return
31
+
32
+ syntax = self._syntax_registry.get_todo_done_syntax() if is_checked else self._syntax_registry.get_todo_syntax()
33
+
34
+ todo_markdown = f"{syntax.start_delimiter} {content}"
35
+
36
+ if context.indent_level > 0:
37
+ todo_markdown = context.indent_text(todo_markdown)
38
+
39
+ children_markdown = await context.render_children_with_additional_indent(1)
40
+
41
+ if children_markdown:
42
+ context.markdown_result = f"{todo_markdown}\n{children_markdown}"
43
+ else:
44
+ context.markdown_result = todo_markdown
45
+
46
+ async def _extract_todo_info(self, block: Block) -> tuple[bool, str]:
47
+ if not block.to_do:
48
+ return False, ""
49
+
50
+ is_checked = block.to_do.checked or False
51
+
52
+ content = ""
53
+ if block.to_do.rich_text:
54
+ content = await self._rich_text_markdown_converter.to_markdown(block.to_do.rich_text)
55
+
56
+ return is_checked, content
@@ -0,0 +1,52 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.enums import BlockType
4
+ from notionary.blocks.rich_text.rich_text_markdown_converter import RichTextToMarkdownConverter
5
+ from notionary.blocks.schemas import Block
6
+ from notionary.page.content.renderer.context import MarkdownRenderingContext
7
+ from notionary.page.content.renderer.renderers.base import BlockRenderer
8
+ from notionary.page.content.syntax import SyntaxRegistry
9
+
10
+
11
+ class ToggleRenderer(BlockRenderer):
12
+ def __init__(
13
+ self,
14
+ syntax_registry: SyntaxRegistry | None = None,
15
+ rich_text_markdown_converter: RichTextToMarkdownConverter | None = None,
16
+ ) -> None:
17
+ super().__init__(syntax_registry=syntax_registry)
18
+ self._rich_text_markdown_converter = rich_text_markdown_converter or RichTextToMarkdownConverter()
19
+
20
+ @override
21
+ def _can_handle(self, block: Block) -> bool:
22
+ return block.type == BlockType.TOGGLE
23
+
24
+ @override
25
+ async def _process(self, context: MarkdownRenderingContext) -> None:
26
+ toggle_title = await self._extract_toggle_title(context.block)
27
+
28
+ if not toggle_title:
29
+ return
30
+
31
+ syntax = self._syntax_registry.get_toggle_syntax()
32
+ toggle_start = f"{syntax.start_delimiter} {toggle_title}"
33
+
34
+ if context.indent_level > 0:
35
+ toggle_start = context.indent_text(toggle_start)
36
+
37
+ original_indent = context.indent_level
38
+ context.indent_level += 1
39
+ children_markdown = await context.render_children()
40
+ context.indent_level = original_indent
41
+
42
+ if children_markdown:
43
+ context.markdown_result = f"{toggle_start}\n{children_markdown}"
44
+ else:
45
+ context.markdown_result = toggle_start
46
+
47
+ async def _extract_toggle_title(self, block: Block) -> str:
48
+ if not block.toggle or not block.toggle.rich_text:
49
+ return ""
50
+
51
+ rich_text_title = block.toggle.rich_text
52
+ return await self._rich_text_markdown_converter.to_markdown(rich_text_title)
@@ -0,0 +1,31 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.schemas import Block, BlockType
4
+ from notionary.page.content.renderer.renderers.captioned_block import CaptionedBlockRenderer
5
+
6
+
7
+ class VideoRenderer(CaptionedBlockRenderer):
8
+ @override
9
+ def _can_handle(self, block: Block) -> bool:
10
+ return block.type == BlockType.VIDEO
11
+
12
+ @override
13
+ async def _render_main_content(self, block: Block) -> str:
14
+ url = self._extract_video_url(block)
15
+
16
+ if not url:
17
+ return ""
18
+
19
+ syntax = self._syntax_registry.get_video_syntax()
20
+ return f"{syntax.start_delimiter}{url}{syntax.end_delimiter}"
21
+
22
+ def _extract_video_url(self, block: Block) -> str:
23
+ if not block.video:
24
+ return ""
25
+
26
+ if block.video.external:
27
+ return block.video.external.url or ""
28
+ elif block.video.file:
29
+ return block.video.file.url or ""
30
+
31
+ return ""
@@ -0,0 +1,50 @@
1
+ from notionary.blocks.schemas import Block
2
+ from notionary.page.content.renderer.context import MarkdownRenderingContext
3
+ from notionary.page.content.renderer.post_processing.service import MarkdownRenderingPostProcessor
4
+ from notionary.page.content.renderer.renderers import BlockRenderer
5
+ from notionary.utils.mixins.logging import LoggingMixin
6
+
7
+
8
+ class NotionToMarkdownConverter(LoggingMixin):
9
+ def __init__(
10
+ self,
11
+ renderer_chain: BlockRenderer,
12
+ post_processor: MarkdownRenderingPostProcessor,
13
+ ) -> None:
14
+ self._renderer_chain = renderer_chain
15
+ self._post_processor = post_processor
16
+
17
+ async def convert(self, blocks: list[Block], indent_level: int = 0) -> str:
18
+ if not blocks:
19
+ return ""
20
+
21
+ rendered_block_parts = []
22
+ current_block_index = 0
23
+
24
+ while current_block_index < len(blocks):
25
+ context = self._create_rendering_context(blocks, current_block_index, indent_level)
26
+ await self._renderer_chain.handle(context)
27
+
28
+ if context.markdown_result:
29
+ rendered_block_parts.append(context.markdown_result)
30
+
31
+ current_block_index += 1
32
+
33
+ result = self._join_rendered_blocks(rendered_block_parts, indent_level)
34
+ result = self._post_processor.process(result)
35
+
36
+ return result
37
+
38
+ def _create_rendering_context(
39
+ self, blocks: list[Block], block_index: int, indent_level: int
40
+ ) -> MarkdownRenderingContext:
41
+ block = blocks[block_index]
42
+ return MarkdownRenderingContext(
43
+ block=block,
44
+ indent_level=indent_level,
45
+ convert_children_callback=self.convert,
46
+ )
47
+
48
+ def _join_rendered_blocks(self, rendered_parts: list[str], indent_level: int) -> str:
49
+ separator = "\n\n" if indent_level == 0 else "\n"
50
+ return separator.join(rendered_parts)
@@ -0,0 +1,68 @@
1
+ import asyncio
2
+ from collections.abc import Callable
3
+
4
+ from notionary.blocks.client import NotionBlockHttpClient
5
+ from notionary.blocks.schemas import Block
6
+ from notionary.page.content.markdown.builder import MarkdownBuilder
7
+ from notionary.page.content.parser.service import MarkdownToNotionConverter
8
+ from notionary.page.content.renderer.service import NotionToMarkdownConverter
9
+ from notionary.utils.decorators import async_retry, time_execution_async
10
+ from notionary.utils.mixins.logging import LoggingMixin
11
+
12
+
13
+ class PageContentService(LoggingMixin):
14
+ def __init__(
15
+ self,
16
+ page_id: str,
17
+ block_client: NotionBlockHttpClient,
18
+ markdown_converter: MarkdownToNotionConverter,
19
+ notion_to_markdown_converter: NotionToMarkdownConverter,
20
+ ) -> None:
21
+ self._page_id = page_id
22
+ self._block_client = block_client
23
+ self._markdown_converter = markdown_converter
24
+ self._notion_to_markdown_converter = notion_to_markdown_converter
25
+
26
+ @time_execution_async()
27
+ async def get_as_markdown(self) -> str:
28
+ blocks = await self._block_client.get_block_tree(parent_block_id=self._page_id)
29
+ return await self._notion_to_markdown_converter.convert(blocks=blocks)
30
+
31
+ @time_execution_async()
32
+ async def clear(self) -> None:
33
+ children_response = await self._block_client.get_block_children(block_id=self._page_id)
34
+
35
+ if not children_response or not children_response.results:
36
+ self.logger.debug("No blocks to delete for page: %s", self._page_id)
37
+ return
38
+
39
+ await asyncio.gather(*[self._delete_single_block(block) for block in children_response.results])
40
+
41
+ @async_retry(max_retries=10, initial_delay=0.2, backoff_factor=1.5)
42
+ async def _delete_single_block(self, block: Block) -> None:
43
+ self.logger.debug("Deleting block: %s", block.id)
44
+ await self._block_client.delete_block(block.id)
45
+
46
+ @time_execution_async()
47
+ async def append_markdown(self, content: str | Callable[[MarkdownBuilder], MarkdownBuilder]) -> None:
48
+ markdown = self._extract_markdown(content)
49
+ if not markdown:
50
+ self.logger.debug("No markdown content to append for page: %s", self._page_id)
51
+ return
52
+
53
+ blocks = await self._markdown_converter.convert(markdown)
54
+ await self._append_blocks(blocks)
55
+
56
+ def _extract_markdown(self, content: str | Callable[[MarkdownBuilder], MarkdownBuilder]) -> str:
57
+ if isinstance(content, str):
58
+ return content
59
+
60
+ if callable(content):
61
+ builder = MarkdownBuilder()
62
+ content(builder)
63
+ return builder.build()
64
+
65
+ raise ValueError("content must be either a string or a callable that takes a MarkdownBuilder")
66
+
67
+ async def _append_blocks(self, blocks: list[Block]) -> None:
68
+ await self._block_client.append_block_children(block_id=self._page_id, children=blocks)
@@ -0,0 +1,4 @@
1
+ from .grammar import MarkdownGrammar
2
+ from .registry import SyntaxRegistry
3
+
4
+ __all__ = ["MarkdownGrammar", "SyntaxRegistry"]
@@ -0,0 +1,10 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass(frozen=True)
5
+ class MarkdownGrammar:
6
+ spaces_per_nesting_level = 4
7
+ numbered_list_placeholder = "__NUM__"
8
+ column_delimiter = ":::"
9
+ toggle_delimiter = "+++"
10
+ table_delimiter = "|"
@@ -0,0 +1,66 @@
1
+ import re
2
+ from dataclasses import dataclass
3
+ from enum import StrEnum
4
+
5
+
6
+ class SyntaxRegistryKey(StrEnum):
7
+ AUDIO = "audio"
8
+ BOOKMARK = "bookmark"
9
+ IMAGE = "image"
10
+ VIDEO = "video"
11
+ FILE = "file"
12
+ PDF = "pdf"
13
+
14
+ # List blocks
15
+ BULLETED_LIST = "bulleted_list"
16
+ NUMBERED_LIST = "numbered_list"
17
+ TO_DO = "todo"
18
+ TO_DO_DONE = "todo_done"
19
+
20
+ TOGGLE = "toggle"
21
+ TOGGLEABLE_HEADING = "toggleable_heading"
22
+ CALLOUT = "callout"
23
+ QUOTE = "quote"
24
+ CODE = "code"
25
+
26
+ COLUMN_LIST = "column_list"
27
+ COLUMN = "column"
28
+
29
+ # Heading blocks
30
+ HEADING_1 = "heading_1"
31
+ HEADING_2 = "heading_2"
32
+ HEADING_3 = "heading_3"
33
+ HEADING = "heading" # Shared pattern for regular headings
34
+
35
+ DIVIDER = "divider"
36
+ BREADCRUMB = "breadcrumb"
37
+ TABLE_OF_CONTENTS = "table_of_contents"
38
+ EQUATION = "equation"
39
+ EMBED = "embed"
40
+ TABLE = "table"
41
+ TABLE_ROW = "table_row"
42
+
43
+ CAPTION = "caption"
44
+ SPACE = "space"
45
+
46
+
47
+ # some elemente need closing delimiters, others not
48
+ # either use union type or validate config in service
49
+ @dataclass(frozen=True)
50
+ class SyntaxDefinition:
51
+ """
52
+ Defines the syntax pattern for a block type.
53
+
54
+ Attributes:
55
+ start_delimiter: The opening delimiter (e.g., "```", "+++", ">")
56
+ end_delimiter: The optional closing delimiter (empty string if none)
57
+ regex_pattern: The compiled regex pattern to match this syntax
58
+ end_regex_pattern: Optional compiled regex pattern for end delimiter
59
+ is_multiline_block: Whether this block can contain child blocks
60
+ is_inline: Whether this is an inline syntax (like [audio](url))
61
+ """
62
+
63
+ start_delimiter: str
64
+ end_delimiter: str
65
+ regex_pattern: re.Pattern
66
+ end_regex_pattern: re.Pattern | None = None