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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (387) hide show
  1. notionary/__init__.py +5 -20
  2. notionary/blocks/client.py +87 -215
  3. notionary/blocks/enums.py +167 -0
  4. notionary/blocks/rich_text/markdown_rich_text_converter.py +266 -0
  5. notionary/blocks/rich_text/models.py +164 -0
  6. notionary/blocks/rich_text/name_id_resolver/__init__.py +11 -0
  7. notionary/blocks/rich_text/name_id_resolver/database.py +31 -0
  8. notionary/blocks/rich_text/name_id_resolver/page.py +34 -0
  9. notionary/blocks/rich_text/name_id_resolver/person.py +37 -0
  10. notionary/blocks/rich_text/name_id_resolver/port.py +11 -0
  11. notionary/blocks/rich_text/rich_text_markdown_converter.py +132 -0
  12. notionary/blocks/rich_text/rich_text_patterns.py +39 -0
  13. notionary/blocks/schemas.py +746 -0
  14. notionary/comments/client.py +52 -187
  15. notionary/comments/factory.py +40 -0
  16. notionary/comments/models.py +5 -127
  17. notionary/comments/schemas.py +240 -0
  18. notionary/comments/service.py +34 -0
  19. notionary/data_source/http/client.py +11 -0
  20. notionary/data_source/http/data_source_instance_client.py +94 -0
  21. notionary/data_source/properties/models.py +406 -0
  22. notionary/data_source/query/builder.py +429 -0
  23. notionary/data_source/query/resolver.py +114 -0
  24. notionary/data_source/query/schema.py +304 -0
  25. notionary/data_source/query/validator.py +73 -0
  26. notionary/data_source/schemas.py +27 -0
  27. notionary/data_source/service.py +353 -0
  28. notionary/database/client.py +30 -135
  29. notionary/database/database_metadata_update_client.py +19 -0
  30. notionary/database/schemas.py +29 -0
  31. notionary/database/service.py +169 -0
  32. notionary/exceptions/__init__.py +33 -0
  33. notionary/exceptions/api.py +41 -0
  34. notionary/exceptions/base.py +2 -0
  35. notionary/exceptions/block_parsing.py +16 -0
  36. notionary/exceptions/data_source/__init__.py +6 -0
  37. notionary/exceptions/data_source/builder.py +182 -0
  38. notionary/exceptions/data_source/properties.py +34 -0
  39. notionary/exceptions/properties.py +58 -0
  40. notionary/exceptions/search.py +33 -0
  41. notionary/file_upload/client.py +18 -30
  42. notionary/file_upload/models.py +7 -8
  43. notionary/file_upload/{notion_file_upload.py → service.py} +29 -64
  44. notionary/http/client.py +205 -0
  45. notionary/http/models.py +49 -0
  46. notionary/page/blocks/client.py +1 -0
  47. notionary/page/content/factory.py +68 -0
  48. notionary/page/content/markdown/__init__.py +5 -0
  49. notionary/page/content/markdown/builder.py +304 -0
  50. notionary/page/content/markdown/nodes/__init__.py +54 -0
  51. notionary/page/content/markdown/nodes/audio.py +23 -0
  52. notionary/page/content/markdown/nodes/base.py +12 -0
  53. notionary/page/content/markdown/nodes/bookmark.py +25 -0
  54. notionary/page/content/markdown/nodes/breadcrumb.py +14 -0
  55. notionary/page/content/markdown/nodes/bulleted_list.py +18 -0
  56. notionary/page/content/markdown/nodes/callout.py +32 -0
  57. notionary/page/content/markdown/nodes/code.py +30 -0
  58. notionary/page/content/markdown/nodes/columns.py +51 -0
  59. notionary/page/content/markdown/nodes/divider.py +14 -0
  60. notionary/page/content/markdown/nodes/embed.py +23 -0
  61. notionary/page/content/markdown/nodes/equation.py +19 -0
  62. notionary/page/content/markdown/nodes/file.py +23 -0
  63. notionary/page/content/markdown/nodes/heading.py +16 -0
  64. notionary/page/content/markdown/nodes/image.py +23 -0
  65. notionary/page/content/markdown/nodes/mixins/caption.py +12 -0
  66. notionary/page/content/markdown/nodes/numbered_list.py +15 -0
  67. notionary/page/content/markdown/nodes/paragraph.py +14 -0
  68. notionary/page/content/markdown/nodes/pdf.py +23 -0
  69. notionary/page/content/markdown/nodes/quote.py +15 -0
  70. notionary/page/content/markdown/nodes/space.py +14 -0
  71. notionary/page/content/markdown/nodes/table.py +45 -0
  72. notionary/page/content/markdown/nodes/table_of_contents.py +14 -0
  73. notionary/page/content/markdown/nodes/todo.py +22 -0
  74. notionary/page/content/markdown/nodes/toggle.py +28 -0
  75. notionary/page/content/markdown/nodes/toggleable_heading.py +35 -0
  76. notionary/page/content/markdown/nodes/video.py +23 -0
  77. notionary/page/content/parser/context.py +49 -0
  78. notionary/page/content/parser/factory.py +219 -0
  79. notionary/page/content/parser/parsers/__init__.py +60 -0
  80. notionary/page/content/parser/parsers/audio.py +40 -0
  81. notionary/page/content/parser/parsers/base.py +30 -0
  82. notionary/page/content/parser/parsers/bookmark.py +33 -0
  83. notionary/page/content/parser/parsers/breadcrumb.py +33 -0
  84. notionary/page/content/parser/parsers/bulleted_list.py +41 -0
  85. notionary/page/content/parser/parsers/callout.py +129 -0
  86. notionary/page/content/parser/parsers/caption.py +55 -0
  87. notionary/page/content/parser/parsers/code.py +81 -0
  88. notionary/page/content/parser/parsers/column.py +117 -0
  89. notionary/page/content/parser/parsers/column_list.py +81 -0
  90. notionary/page/content/parser/parsers/divider.py +33 -0
  91. notionary/page/content/parser/parsers/embed.py +33 -0
  92. notionary/page/content/parser/parsers/equation.py +65 -0
  93. notionary/page/content/parser/parsers/file.py +42 -0
  94. notionary/page/content/parser/parsers/heading.py +58 -0
  95. notionary/page/content/parser/parsers/image.py +42 -0
  96. notionary/page/content/parser/parsers/numbered_list.py +45 -0
  97. notionary/page/content/parser/parsers/paragraph.py +36 -0
  98. notionary/page/content/parser/parsers/pdf.py +42 -0
  99. notionary/page/content/parser/parsers/quote.py +65 -0
  100. notionary/page/content/parser/parsers/space.py +35 -0
  101. notionary/page/content/parser/parsers/table.py +144 -0
  102. notionary/page/content/parser/parsers/table_of_contents.py +32 -0
  103. notionary/page/content/parser/parsers/todo.py +58 -0
  104. notionary/page/content/parser/parsers/toggle.py +127 -0
  105. notionary/page/content/parser/parsers/toggleable_heading.py +150 -0
  106. notionary/page/content/parser/parsers/video.py +42 -0
  107. notionary/page/content/parser/post_processing/handlers/__init__.py +5 -0
  108. notionary/page/content/parser/post_processing/handlers/rich_text_length.py +93 -0
  109. notionary/page/content/parser/post_processing/handlers/rich_text_length_truncation.py +93 -0
  110. notionary/page/content/parser/post_processing/port.py +9 -0
  111. notionary/page/content/parser/post_processing/service.py +16 -0
  112. notionary/page/content/parser/pre_processsing/handlers/__init__.py +9 -0
  113. notionary/page/content/parser/pre_processsing/handlers/column_syntax.py +80 -0
  114. notionary/page/content/parser/pre_processsing/handlers/port.py +7 -0
  115. notionary/page/content/parser/pre_processsing/handlers/whitespace.py +68 -0
  116. notionary/page/content/parser/pre_processsing/service.py +15 -0
  117. notionary/page/content/parser/service.py +69 -0
  118. notionary/page/content/renderer/context.py +48 -0
  119. notionary/page/content/renderer/factory.py +240 -0
  120. notionary/page/content/renderer/post_processing/handlers/__init__.py +5 -0
  121. notionary/page/content/renderer/post_processing/handlers/numbered_list_placeholdere.py +62 -0
  122. notionary/page/content/renderer/post_processing/port.py +7 -0
  123. notionary/page/content/renderer/post_processing/service.py +15 -0
  124. notionary/page/content/renderer/renderers/__init__.py +57 -0
  125. notionary/page/content/renderer/renderers/audio.py +31 -0
  126. notionary/page/content/renderer/renderers/base.py +31 -0
  127. notionary/page/content/renderer/renderers/bookmark.py +25 -0
  128. notionary/page/content/renderer/renderers/breadcrumb.py +21 -0
  129. notionary/page/content/renderer/renderers/bulleted_list.py +48 -0
  130. notionary/page/content/renderer/renderers/callout.py +65 -0
  131. notionary/page/content/renderer/renderers/captioned_block.py +58 -0
  132. notionary/page/content/renderer/renderers/code.py +34 -0
  133. notionary/page/content/renderer/renderers/column.py +44 -0
  134. notionary/page/content/renderer/renderers/column_list.py +31 -0
  135. notionary/page/content/renderer/renderers/divider.py +22 -0
  136. notionary/page/content/renderer/renderers/embed.py +25 -0
  137. notionary/page/content/renderer/renderers/equation.py +37 -0
  138. notionary/page/content/renderer/renderers/fallback.py +24 -0
  139. notionary/page/content/renderer/renderers/file.py +40 -0
  140. notionary/page/content/renderer/renderers/heading.py +69 -0
  141. notionary/page/content/renderer/renderers/image.py +31 -0
  142. notionary/page/content/renderer/renderers/numbered_list.py +41 -0
  143. notionary/page/content/renderer/renderers/paragraph.py +40 -0
  144. notionary/page/content/renderer/renderers/pdf.py +31 -0
  145. notionary/page/content/renderer/renderers/quote.py +49 -0
  146. notionary/page/content/renderer/renderers/table.py +115 -0
  147. notionary/page/content/renderer/renderers/table_of_contents.py +26 -0
  148. notionary/page/content/renderer/renderers/table_row.py +17 -0
  149. notionary/page/content/renderer/renderers/todo.py +56 -0
  150. notionary/page/content/renderer/renderers/toggle.py +53 -0
  151. notionary/page/content/renderer/renderers/toggleable_heading.py +78 -0
  152. notionary/page/content/renderer/renderers/video.py +31 -0
  153. notionary/page/content/renderer/service.py +50 -0
  154. notionary/page/content/service.py +65 -0
  155. notionary/page/content/syntax/models.py +68 -0
  156. notionary/page/content/syntax/service.py +453 -0
  157. notionary/page/page_context.py +7 -16
  158. notionary/page/page_http_client.py +15 -0
  159. notionary/page/page_metadata_update_client.py +19 -0
  160. notionary/page/properties/client.py +144 -0
  161. notionary/page/properties/factory.py +26 -0
  162. notionary/page/properties/models.py +307 -0
  163. notionary/page/properties/service.py +257 -0
  164. notionary/page/schemas.py +13 -0
  165. notionary/page/service.py +222 -0
  166. notionary/shared/entity/client.py +29 -0
  167. notionary/shared/entity/dto_parsers.py +53 -0
  168. notionary/shared/entity/entity_metadata_update_client.py +41 -0
  169. notionary/shared/entity/schemas.py +45 -0
  170. notionary/shared/entity/service.py +171 -0
  171. notionary/shared/models/cover.py +20 -0
  172. notionary/shared/models/file.py +21 -0
  173. notionary/shared/models/icon.py +28 -0
  174. notionary/shared/models/parent.py +41 -0
  175. notionary/shared/properties/type.py +30 -0
  176. notionary/user/__init__.py +4 -8
  177. notionary/user/base.py +89 -0
  178. notionary/user/bot.py +70 -0
  179. notionary/user/client.py +22 -111
  180. notionary/user/person.py +41 -0
  181. notionary/user/schemas.py +67 -0
  182. notionary/user/service.py +65 -0
  183. notionary/utils/async_retry.py +39 -0
  184. notionary/utils/date.py +51 -0
  185. notionary/utils/fuzzy.py +56 -0
  186. notionary/{util/logging_mixin.py → utils/mixins/logging.py} +4 -16
  187. notionary/utils/pagination.py +50 -0
  188. notionary/utils/singleton.py +13 -0
  189. notionary/utils/uuid_utils.py +20 -0
  190. notionary/workspace/__init__.py +3 -0
  191. notionary/workspace/client.py +62 -0
  192. notionary/workspace/query/builder.py +60 -0
  193. notionary/workspace/query/models.py +60 -0
  194. notionary/workspace/query/service.py +93 -0
  195. notionary/workspace/schemas.py +21 -0
  196. notionary/workspace/service.py +116 -0
  197. {notionary-0.2.26.dist-info → notionary-0.2.28.dist-info}/METADATA +54 -49
  198. notionary-0.2.28.dist-info/RECORD +200 -0
  199. {notionary-0.2.26.dist-info → notionary-0.2.28.dist-info}/WHEEL +1 -1
  200. {notionary-0.2.26.dist-info → notionary-0.2.28.dist-info/licenses}/LICENSE +9 -9
  201. notionary/base_notion_client.py +0 -219
  202. notionary/blocks/__init__.py +0 -5
  203. notionary/blocks/_bootstrap.py +0 -271
  204. notionary/blocks/audio/__init__.py +0 -11
  205. notionary/blocks/audio/audio_element.py +0 -158
  206. notionary/blocks/audio/audio_markdown_node.py +0 -24
  207. notionary/blocks/audio/audio_models.py +0 -10
  208. notionary/blocks/base_block_element.py +0 -42
  209. notionary/blocks/bookmark/__init__.py +0 -12
  210. notionary/blocks/bookmark/bookmark_element.py +0 -83
  211. notionary/blocks/bookmark/bookmark_markdown_node.py +0 -28
  212. notionary/blocks/bookmark/bookmark_models.py +0 -15
  213. notionary/blocks/breadcrumbs/__init__.py +0 -15
  214. notionary/blocks/breadcrumbs/breadcrumb_element.py +0 -39
  215. notionary/blocks/breadcrumbs/breadcrumb_markdown_node.py +0 -13
  216. notionary/blocks/breadcrumbs/breadcrumb_models.py +0 -12
  217. notionary/blocks/bulleted_list/__init__.py +0 -15
  218. notionary/blocks/bulleted_list/bulleted_list_element.py +0 -74
  219. notionary/blocks/bulleted_list/bulleted_list_markdown_node.py +0 -20
  220. notionary/blocks/bulleted_list/bulleted_list_models.py +0 -17
  221. notionary/blocks/callout/__init__.py +0 -12
  222. notionary/blocks/callout/callout_element.py +0 -99
  223. notionary/blocks/callout/callout_markdown_node.py +0 -19
  224. notionary/blocks/callout/callout_models.py +0 -33
  225. notionary/blocks/child_database/__init__.py +0 -14
  226. notionary/blocks/child_database/child_database_element.py +0 -59
  227. notionary/blocks/child_database/child_database_models.py +0 -12
  228. notionary/blocks/child_page/__init__.py +0 -9
  229. notionary/blocks/child_page/child_page_element.py +0 -94
  230. notionary/blocks/child_page/child_page_models.py +0 -12
  231. notionary/blocks/code/__init__.py +0 -11
  232. notionary/blocks/code/code_element.py +0 -149
  233. notionary/blocks/code/code_markdown_node.py +0 -80
  234. notionary/blocks/code/code_models.py +0 -94
  235. notionary/blocks/column/__init__.py +0 -25
  236. notionary/blocks/column/column_element.py +0 -65
  237. notionary/blocks/column/column_list_element.py +0 -52
  238. notionary/blocks/column/column_list_markdown_node.py +0 -34
  239. notionary/blocks/column/column_markdown_node.py +0 -42
  240. notionary/blocks/column/column_models.py +0 -26
  241. notionary/blocks/divider/__init__.py +0 -12
  242. notionary/blocks/divider/divider_element.py +0 -41
  243. notionary/blocks/divider/divider_markdown_node.py +0 -11
  244. notionary/blocks/divider/divider_models.py +0 -12
  245. notionary/blocks/embed/__init__.py +0 -12
  246. notionary/blocks/embed/embed_element.py +0 -98
  247. notionary/blocks/embed/embed_markdown_node.py +0 -19
  248. notionary/blocks/embed/embed_models.py +0 -14
  249. notionary/blocks/equation/__init__.py +0 -13
  250. notionary/blocks/equation/equation_element.py +0 -133
  251. notionary/blocks/equation/equation_element_markdown_node.py +0 -23
  252. notionary/blocks/equation/equation_models.py +0 -11
  253. notionary/blocks/file/__init__.py +0 -23
  254. notionary/blocks/file/file_element.py +0 -133
  255. notionary/blocks/file/file_element_markdown_node.py +0 -24
  256. notionary/blocks/file/file_element_models.py +0 -39
  257. notionary/blocks/heading/__init__.py +0 -19
  258. notionary/blocks/heading/heading_element.py +0 -112
  259. notionary/blocks/heading/heading_markdown_node.py +0 -16
  260. notionary/blocks/heading/heading_models.py +0 -29
  261. notionary/blocks/image_block/__init__.py +0 -11
  262. notionary/blocks/image_block/image_element.py +0 -130
  263. notionary/blocks/image_block/image_markdown_node.py +0 -25
  264. notionary/blocks/image_block/image_models.py +0 -10
  265. notionary/blocks/markdown/markdown_builder.py +0 -525
  266. notionary/blocks/markdown/markdown_document_model.py +0 -0
  267. notionary/blocks/markdown/markdown_node.py +0 -25
  268. notionary/blocks/mixins/captions/__init__.py +0 -4
  269. notionary/blocks/mixins/captions/caption_markdown_node_mixin.py +0 -31
  270. notionary/blocks/mixins/captions/caption_mixin.py +0 -92
  271. notionary/blocks/mixins/file_upload/__init__.py +0 -3
  272. notionary/blocks/mixins/file_upload/file_upload_mixin.py +0 -320
  273. notionary/blocks/models.py +0 -174
  274. notionary/blocks/numbered_list/__init__.py +0 -16
  275. notionary/blocks/numbered_list/numbered_list_element.py +0 -65
  276. notionary/blocks/numbered_list/numbered_list_markdown_node.py +0 -17
  277. notionary/blocks/numbered_list/numbered_list_models.py +0 -17
  278. notionary/blocks/paragraph/__init__.py +0 -15
  279. notionary/blocks/paragraph/paragraph_element.py +0 -58
  280. notionary/blocks/paragraph/paragraph_markdown_node.py +0 -16
  281. notionary/blocks/paragraph/paragraph_models.py +0 -16
  282. notionary/blocks/pdf/__init__.py +0 -11
  283. notionary/blocks/pdf/pdf_element.py +0 -146
  284. notionary/blocks/pdf/pdf_markdown_node.py +0 -24
  285. notionary/blocks/pdf/pdf_models.py +0 -11
  286. notionary/blocks/quote/__init__.py +0 -14
  287. notionary/blocks/quote/quote_element.py +0 -75
  288. notionary/blocks/quote/quote_markdown_node.py +0 -16
  289. notionary/blocks/quote/quote_models.py +0 -18
  290. notionary/blocks/registry/__init__.py +0 -3
  291. notionary/blocks/registry/block_registry.py +0 -150
  292. notionary/blocks/rich_text/__init__.py +0 -33
  293. notionary/blocks/rich_text/rich_text_models.py +0 -221
  294. notionary/blocks/rich_text/text_inline_formatter.py +0 -456
  295. notionary/blocks/syntax_prompt_builder.py +0 -137
  296. notionary/blocks/table/__init__.py +0 -19
  297. notionary/blocks/table/table_element.py +0 -225
  298. notionary/blocks/table/table_markdown_node.py +0 -42
  299. notionary/blocks/table/table_models.py +0 -28
  300. notionary/blocks/table_of_contents/__init__.py +0 -17
  301. notionary/blocks/table_of_contents/table_of_contents_element.py +0 -80
  302. notionary/blocks/table_of_contents/table_of_contents_markdown_node.py +0 -21
  303. notionary/blocks/table_of_contents/table_of_contents_models.py +0 -18
  304. notionary/blocks/todo/__init__.py +0 -12
  305. notionary/blocks/todo/todo_element.py +0 -81
  306. notionary/blocks/todo/todo_markdown_node.py +0 -21
  307. notionary/blocks/todo/todo_models.py +0 -18
  308. notionary/blocks/toggle/__init__.py +0 -12
  309. notionary/blocks/toggle/toggle_element.py +0 -112
  310. notionary/blocks/toggle/toggle_markdown_node.py +0 -31
  311. notionary/blocks/toggle/toggle_models.py +0 -17
  312. notionary/blocks/toggleable_heading/__init__.py +0 -11
  313. notionary/blocks/toggleable_heading/toggleable_heading_element.py +0 -115
  314. notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +0 -34
  315. notionary/blocks/types.py +0 -130
  316. notionary/blocks/video/__init__.py +0 -11
  317. notionary/blocks/video/video_element.py +0 -187
  318. notionary/blocks/video/video_element_models.py +0 -10
  319. notionary/blocks/video/video_markdown_node.py +0 -26
  320. notionary/comments/__init__.py +0 -26
  321. notionary/database/__init__.py +0 -4
  322. notionary/database/database.py +0 -480
  323. notionary/database/database_filter_builder.py +0 -173
  324. notionary/database/database_provider.py +0 -227
  325. notionary/database/exceptions.py +0 -13
  326. notionary/database/factory.py +0 -0
  327. notionary/database/models.py +0 -337
  328. notionary/database/notion_database.py +0 -487
  329. notionary/file_upload/__init__.py +0 -7
  330. notionary/page/client.py +0 -124
  331. notionary/page/markdown_whitespace_processor.py +0 -129
  332. notionary/page/models.py +0 -322
  333. notionary/page/notion_page.py +0 -674
  334. notionary/page/page_content_deleting_service.py +0 -117
  335. notionary/page/page_content_writer.py +0 -80
  336. notionary/page/property_formatter.py +0 -99
  337. notionary/page/reader/handler/__init__.py +0 -19
  338. notionary/page/reader/handler/base_block_renderer.py +0 -44
  339. notionary/page/reader/handler/block_processing_context.py +0 -35
  340. notionary/page/reader/handler/block_rendering_context.py +0 -48
  341. notionary/page/reader/handler/column_list_renderer.py +0 -51
  342. notionary/page/reader/handler/column_renderer.py +0 -60
  343. notionary/page/reader/handler/equation_renderer.py +0 -0
  344. notionary/page/reader/handler/line_renderer.py +0 -73
  345. notionary/page/reader/handler/numbered_list_renderer.py +0 -85
  346. notionary/page/reader/handler/toggle_renderer.py +0 -69
  347. notionary/page/reader/handler/toggleable_heading_renderer.py +0 -89
  348. notionary/page/reader/page_content_retriever.py +0 -81
  349. notionary/page/search_filter_builder.py +0 -132
  350. notionary/page/utils.py +0 -60
  351. notionary/page/writer/handler/__init__.py +0 -24
  352. notionary/page/writer/handler/code_handler.py +0 -72
  353. notionary/page/writer/handler/column_handler.py +0 -141
  354. notionary/page/writer/handler/column_list_handler.py +0 -139
  355. notionary/page/writer/handler/equation_handler.py +0 -74
  356. notionary/page/writer/handler/line_handler.py +0 -35
  357. notionary/page/writer/handler/line_processing_context.py +0 -54
  358. notionary/page/writer/handler/regular_line_handler.py +0 -86
  359. notionary/page/writer/handler/table_handler.py +0 -66
  360. notionary/page/writer/handler/toggle_handler.py +0 -159
  361. notionary/page/writer/handler/toggleable_heading_handler.py +0 -174
  362. notionary/page/writer/markdown_to_notion_converter.py +0 -139
  363. notionary/page/writer/markdown_to_notion_converter_context.py +0 -30
  364. notionary/page/writer/markdown_to_notion_text_length_post_processor.py +0 -0
  365. notionary/page/writer/notion_text_length_processor.py +0 -150
  366. notionary/schemas/__init__.py +0 -3
  367. notionary/schemas/base.py +0 -73
  368. notionary/shared/__init__.py +0 -3
  369. notionary/shared/name_to_id_resolver.py +0 -203
  370. notionary/telemetry/__init__.py +0 -19
  371. notionary/telemetry/service.py +0 -136
  372. notionary/telemetry/views.py +0 -73
  373. notionary/user/base_notion_user.py +0 -53
  374. notionary/user/models.py +0 -84
  375. notionary/user/notion_bot_user.py +0 -226
  376. notionary/user/notion_user.py +0 -255
  377. notionary/user/notion_user_manager.py +0 -101
  378. notionary/util/__init__.py +0 -15
  379. notionary/util/concurrency_limiter.py +0 -0
  380. notionary/util/factory_decorator.py +0 -0
  381. notionary/util/factory_only.py +0 -37
  382. notionary/util/fuzzy.py +0 -75
  383. notionary/util/page_id_utils.py +0 -27
  384. notionary/util/singleton.py +0 -18
  385. notionary/util/singleton_metaclass.py +0 -22
  386. notionary/workspace.py +0 -105
  387. notionary-0.2.26.dist-info/RECORD +0 -202
@@ -0,0 +1,353 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from collections.abc import AsyncIterator, Callable
5
+ from typing import TYPE_CHECKING, Self
6
+
7
+ from notionary.blocks.rich_text.rich_text_markdown_converter import RichTextToMarkdownConverter
8
+ from notionary.data_source.http.client import DataSourceClient
9
+ from notionary.data_source.http.data_source_instance_client import DataSourceInstanceClient
10
+ from notionary.data_source.properties.models import (
11
+ DataSourceMultiSelectProperty,
12
+ DataSourceProperty,
13
+ DataSourcePropertyOption,
14
+ DataSourcePropertyT,
15
+ DataSourceRelationProperty,
16
+ DataSourceSelectProperty,
17
+ DataSourceStatusProperty,
18
+ )
19
+ from notionary.data_source.query.builder import DataSourceQueryBuilder
20
+ from notionary.data_source.query.resolver import QueryResolver
21
+ from notionary.data_source.query.schema import (
22
+ DataSourceQueryParams,
23
+ )
24
+ from notionary.data_source.schemas import DataSourceDto
25
+ from notionary.exceptions.data_source.properties import DataSourcePropertyNotFound, DataSourcePropertyTypeError
26
+ from notionary.page.properties.models import PageTitleProperty
27
+ from notionary.page.schemas import NotionPageDto
28
+ from notionary.shared.entity.dto_parsers import (
29
+ extract_cover_image_url_from_dto,
30
+ extract_database_id,
31
+ extract_description,
32
+ extract_emoji_icon_from_dto,
33
+ extract_external_icon_url_from_dto,
34
+ extract_title,
35
+ )
36
+ from notionary.shared.entity.entity_metadata_update_client import EntityMetadataUpdateClient
37
+ from notionary.shared.entity.service import Entity
38
+ from notionary.user.schemas import PartialUserDto
39
+ from notionary.workspace.query.service import WorkspaceQueryService
40
+
41
+ if TYPE_CHECKING:
42
+ from notionary import NotionDatabase, NotionPage
43
+
44
+
45
+ class NotionDataSource(Entity):
46
+ def __init__(
47
+ self,
48
+ id: str,
49
+ title: str,
50
+ created_time: str,
51
+ created_by: PartialUserDto,
52
+ last_edited_time: str,
53
+ last_edited_by: PartialUserDto,
54
+ archived: bool,
55
+ in_trash: bool,
56
+ properties: dict[str, DataSourceProperty],
57
+ parent_database_id: str | None,
58
+ emoji_icon: str | None = None,
59
+ external_icon_url: str | None = None,
60
+ cover_image_url: str | None = None,
61
+ description: str | None = None,
62
+ data_source_instance_client: DataSourceInstanceClient | None = None,
63
+ query_resolver: QueryResolver | None = None,
64
+ ) -> None:
65
+ super().__init__(
66
+ id=id,
67
+ created_time=created_time,
68
+ created_by=created_by,
69
+ last_edited_time=last_edited_time,
70
+ last_edited_by=last_edited_by,
71
+ in_trash=in_trash,
72
+ emoji_icon=emoji_icon,
73
+ external_icon_url=external_icon_url,
74
+ cover_image_url=cover_image_url,
75
+ )
76
+ self._parent_database_id = parent_database_id
77
+ self._parent_database: NotionDatabase | None = None
78
+ self._title = title
79
+ self._archived = archived
80
+ self._description = description
81
+ self._properties = properties or {}
82
+ self._data_source_client = data_source_instance_client or DataSourceInstanceClient(data_source_id=id)
83
+ self.query_resolver = query_resolver or QueryResolver()
84
+
85
+ @classmethod
86
+ async def from_id(
87
+ cls,
88
+ data_source_id: str,
89
+ data_source_client: DataSourceClient | None = None,
90
+ rich_text_converter: RichTextToMarkdownConverter | None = None,
91
+ ) -> Self:
92
+ client = data_source_client or DataSourceClient()
93
+ converter = rich_text_converter or RichTextToMarkdownConverter()
94
+ data_source_dto = await client.get_data_source(data_source_id)
95
+ return await cls._create_from_dto(data_source_dto, converter)
96
+
97
+ @classmethod
98
+ async def from_title(
99
+ cls,
100
+ data_source_title: str,
101
+ min_similarity: float = 0.6,
102
+ search_service: WorkspaceQueryService | None = None,
103
+ ) -> Self:
104
+ service = search_service or WorkspaceQueryService()
105
+ return await service.find_data_source(data_source_title, min_similarity=min_similarity)
106
+
107
+ @classmethod
108
+ async def _create_from_dto(
109
+ cls,
110
+ response: DataSourceDto,
111
+ rich_text_converter: RichTextToMarkdownConverter,
112
+ ) -> Self:
113
+ title, description = await asyncio.gather(
114
+ extract_title(response, rich_text_converter),
115
+ extract_description(response, rich_text_converter),
116
+ )
117
+
118
+ parent_database_id = extract_database_id(response)
119
+
120
+ return cls._create(
121
+ id=response.id,
122
+ title=title,
123
+ description=description,
124
+ created_time=response.created_time,
125
+ created_by=response.created_by,
126
+ last_edited_time=response.last_edited_time,
127
+ last_edited_by=response.last_edited_by,
128
+ archived=response.archived,
129
+ in_trash=response.in_trash,
130
+ properties=response.properties,
131
+ parent_database_id=parent_database_id,
132
+ emoji_icon=extract_emoji_icon_from_dto(response),
133
+ external_icon_url=extract_external_icon_url_from_dto(response),
134
+ cover_image_url=extract_cover_image_url_from_dto(response),
135
+ )
136
+
137
+ @classmethod
138
+ def _create(
139
+ cls,
140
+ id: str,
141
+ title: str,
142
+ created_time: str,
143
+ created_by: PartialUserDto,
144
+ last_edited_time: str,
145
+ last_edited_by: PartialUserDto,
146
+ archived: bool,
147
+ in_trash: bool,
148
+ properties: dict[str, DataSourceProperty],
149
+ parent_database_id: str | None,
150
+ emoji_icon: str | None = None,
151
+ external_icon_url: str | None = None,
152
+ cover_image_url: str | None = None,
153
+ description: str | None = None,
154
+ ) -> Self:
155
+ data_source_instance_client = DataSourceInstanceClient(data_source_id=id)
156
+ return cls(
157
+ id=id,
158
+ title=title,
159
+ created_time=created_time,
160
+ created_by=created_by,
161
+ last_edited_time=last_edited_time,
162
+ last_edited_by=last_edited_by,
163
+ archived=archived,
164
+ in_trash=in_trash,
165
+ parent_database_id=parent_database_id,
166
+ emoji_icon=emoji_icon,
167
+ external_icon_url=external_icon_url,
168
+ cover_image_url=cover_image_url,
169
+ description=description,
170
+ properties=properties,
171
+ data_source_instance_client=data_source_instance_client,
172
+ )
173
+
174
+ @property
175
+ def _entity_metadata_update_client(self) -> EntityMetadataUpdateClient:
176
+ return self._data_source_client
177
+
178
+ @property
179
+ def title(self) -> str:
180
+ return self._title
181
+
182
+ @property
183
+ def archived(self) -> bool:
184
+ return self._archived
185
+
186
+ @property
187
+ def description(self) -> str | None:
188
+ return self._description
189
+
190
+ @property
191
+ def properties(self) -> dict[str, DataSourceProperty]:
192
+ return self._properties
193
+
194
+ async def get_parent_database(self) -> NotionDatabase | None:
195
+ if self._parent_database is None and self._parent_database_id:
196
+ self._parent_database = await NotionDatabase.from_id(self._parent_database_id)
197
+ return self._parent_database
198
+
199
+ async def create_blank_page(self, title: str | None = None) -> NotionPage:
200
+ return await self._data_source_client.create_blank_page(title=title)
201
+
202
+ async def set_title(self, title: str) -> None:
203
+ data_source_dto = await self._data_source_client.update_title(title)
204
+ self._title = data_source_dto.title
205
+
206
+ async def archive(self) -> None:
207
+ if self._archived:
208
+ self.logger.info("Data source is already archived.")
209
+ return
210
+ await self._data_source_client.archive()
211
+ self._archived = True
212
+
213
+ async def unarchive(self) -> None:
214
+ if not self._archived:
215
+ self.logger.info("Data source is not archived.")
216
+ return
217
+ await self._data_source_client.unarchive()
218
+ self._archived = False
219
+
220
+ async def update_description(self, description: str) -> None:
221
+ self._description = await self._data_source_client.update_description(description)
222
+
223
+ async def get_options_for_property_by_name(self, property_name: str) -> list[str]:
224
+ prop = self._properties.get(property_name)
225
+
226
+ if prop is None:
227
+ return []
228
+
229
+ if isinstance(prop, DataSourceSelectProperty):
230
+ return prop.option_names
231
+
232
+ if isinstance(prop, DataSourceMultiSelectProperty):
233
+ return prop.option_names
234
+
235
+ if isinstance(prop, DataSourceStatusProperty):
236
+ return prop.option_names
237
+
238
+ if isinstance(prop, DataSourceRelationProperty):
239
+ return await self._get_relation_options(prop)
240
+
241
+ return []
242
+
243
+ def get_select_options_by_property_name(self, property_name: str) -> list[str]:
244
+ select_prop = self._get_typed_property_or_raise(property_name, DataSourceSelectProperty)
245
+ return select_prop.option_names
246
+
247
+ def get_multi_select_options_by_property_name(self, property_name: str) -> list[DataSourcePropertyOption]:
248
+ multi_select_prop = self._get_typed_property_or_raise(property_name, DataSourceMultiSelectProperty)
249
+ return multi_select_prop.option_names
250
+
251
+ def get_status_options_by_property_name(self, property_name: str) -> list[str]:
252
+ status_prop = self._get_typed_property_or_raise(property_name, DataSourceStatusProperty)
253
+ return status_prop.option_names
254
+
255
+ async def get_relation_options_by_property_name(self, property_name: str) -> list[str]:
256
+ relation_prop = self._get_typed_property_or_raise(property_name, DataSourceRelationProperty)
257
+ return await self._get_relation_options(relation_prop)
258
+
259
+ async def _get_relation_options(self, relation_prop: DataSourceRelationProperty) -> list[str]:
260
+ related_data_source_id = relation_prop.related_data_source_id
261
+ if not related_data_source_id:
262
+ return []
263
+
264
+ async with DataSourceInstanceClient(related_data_source_id) as related_client:
265
+ search_results = await related_client.query()
266
+
267
+ page_titles = []
268
+ for page_response in search_results.results:
269
+ title = self._extract_title_from_notion_page_dto(page_response)
270
+ if title:
271
+ page_titles.append(title)
272
+
273
+ return page_titles
274
+
275
+ def _extract_title_from_notion_page_dto(self, page: NotionPageDto) -> str | None:
276
+ if not page.properties:
277
+ return None
278
+
279
+ title_property = next(
280
+ (prop for prop in page.properties.values() if isinstance(prop, PageTitleProperty)),
281
+ None,
282
+ )
283
+
284
+ if not title_property:
285
+ return None
286
+
287
+ return "".join(item.plain_text for item in title_property.title)
288
+
289
+ def _get_typed_property_or_raise(self, name: str, property_type: type[DataSourcePropertyT]) -> DataSourcePropertyT:
290
+ prop = self._properties.get(name)
291
+
292
+ if prop is None:
293
+ raise DataSourcePropertyNotFound(
294
+ property_name=name,
295
+ available_properties=list(self._properties.keys()),
296
+ )
297
+
298
+ if not isinstance(prop, property_type):
299
+ raise DataSourcePropertyTypeError(
300
+ property_name=name, expected_type=property_type.__name__, actual_type=type(prop).__name__
301
+ )
302
+
303
+ return prop
304
+
305
+ def filter(self) -> DataSourceQueryBuilder:
306
+ return DataSourceQueryBuilder(properties=self._properties)
307
+
308
+ async def query(self, filter_fn: Callable[[DataSourceQueryBuilder], DataSourceQueryBuilder]) -> list[NotionPage]:
309
+ builder = DataSourceQueryBuilder(properties=self._properties)
310
+ filter_fn(builder)
311
+ query_params = builder.build()
312
+
313
+ return await self.get_pages(query_params)
314
+
315
+ async def query_stream(
316
+ self, filter_fn: Callable[[DataSourceQueryBuilder], DataSourceQueryBuilder]
317
+ ) -> AsyncIterator[NotionPage]:
318
+ builder = DataSourceQueryBuilder(properties=self._properties)
319
+ filter_fn(builder)
320
+ query_params = builder.build()
321
+
322
+ async for page in self.get_pages_stream(query_params):
323
+ yield page
324
+
325
+ async def get_pages(
326
+ self,
327
+ query_params: DataSourceQueryParams | None = None,
328
+ ) -> list[NotionPage]:
329
+ from notionary import NotionPage
330
+
331
+ resolved_params = await self._resolve_query_params_if_needed(query_params)
332
+ query_response = await self._data_source_client.query(query_params=resolved_params)
333
+ return [await NotionPage.from_id(page.id) for page in query_response.results]
334
+
335
+ async def get_pages_stream(
336
+ self,
337
+ query_params: DataSourceQueryParams | None = None,
338
+ ) -> AsyncIterator[NotionPage]:
339
+ from notionary import NotionPage
340
+
341
+ resolved_params = await self._resolve_query_params_if_needed(query_params)
342
+
343
+ async for page in self._data_source_client.query_stream(query_params=resolved_params):
344
+ yield await NotionPage.from_id(page.id)
345
+
346
+ async def _resolve_query_params_if_needed(
347
+ self,
348
+ query_params: DataSourceQueryParams | None,
349
+ ) -> DataSourceQueryParams | None:
350
+ if query_params is None:
351
+ return None
352
+
353
+ return await self.query_resolver.resolve_params(query_params)
@@ -1,148 +1,43 @@
1
- from typing import Any, Dict, Optional
2
-
3
- from notionary.base_notion_client import BaseNotionClient
4
- from notionary.database.models import (
5
- NotionDatabaseResponse,
6
- NotionDatabaseSearchResponse,
7
- NotionPageResponse,
8
- NotionQueryDatabaseResponse,
1
+ from notionary.blocks.rich_text.rich_text_markdown_converter import RichTextToMarkdownConverter
2
+ from notionary.database.schemas import (
3
+ NotionDatabaseDto,
4
+ NotionDatabaseUpdateDto,
9
5
  )
6
+ from notionary.http.client import NotionHttpClient
10
7
 
11
8
 
12
- class NotionDatabaseClient(BaseNotionClient):
13
- """
14
- Specialized Notion client for database operations.
15
- Inherits connection management and HTTP methods from BaseNotionClient.
16
- """
17
-
18
- def __init__(self, token: Optional[str] = None, timeout: int = 30):
19
- super().__init__(token, timeout)
20
-
21
- async def create_database(
22
- self,
23
- title: str,
24
- parent_page_id: Optional[str],
25
- properties: Optional[Dict[str, Any]] = None,
26
- ) -> NotionDatabaseResponse:
27
- """
28
- Creates a new database as child of the specified page.
29
- """
30
- if properties is None:
31
- properties = {"Name": {"title": {}}}
32
-
33
- database_data = {
34
- "parent": {"page_id": parent_page_id},
35
- "title": [{"type": "text", "text": {"content": title}}],
36
- "properties": properties,
37
- }
38
-
39
- response = await self.post("databases", database_data)
40
- return NotionDatabaseResponse.model_validate(response)
41
-
42
- async def get_database(self, database_id: str) -> NotionDatabaseResponse:
43
- """
44
- Gets metadata for a Notion database by its ID.
45
- """
46
- response = await self.get(f"databases/{database_id}")
47
- return NotionDatabaseResponse.model_validate(response)
48
-
49
- async def patch_database(
50
- self, database_id: str, data: Dict[str, Any]
51
- ) -> NotionDatabaseResponse:
52
- """
53
- Updates a Notion database with the provided data.
54
- """
55
- response = await self.patch(f"databases/{database_id}", data=data)
56
- return NotionDatabaseResponse.model_validate(response)
57
-
58
- async def query_database(
59
- self, database_id: str, query_data: Dict[str, Any] = None
60
- ) -> NotionQueryDatabaseResponse:
61
- """
62
- Queries a Notion database with the provided filter and sorts.
63
- """
64
- response = await self.post(f"databases/{database_id}/query", data=query_data)
65
- return NotionQueryDatabaseResponse.model_validate(response)
9
+ class NotionDatabaseHttpClient(NotionHttpClient):
10
+ def __init__(self, database_id: str, timeout: int = 30) -> None:
11
+ super().__init__(timeout)
12
+ self._database_id = database_id
66
13
 
67
- async def query_database_by_title(
68
- self, database_id: str, page_title: str
69
- ) -> NotionQueryDatabaseResponse:
70
- """
71
- Queries a Notion database by title.
72
- """
73
- query_data = {
74
- "filter": {"property": "title", "title": {"contains": page_title}}
75
- }
14
+ async def get_database(self) -> NotionDatabaseDto:
15
+ response = await self.get(f"databases/{self._database_id}")
16
+ return NotionDatabaseDto.model_validate(response)
76
17
 
77
- return await self.query_database(database_id=database_id, query_data=query_data)
18
+ async def patch_database(self, update_database_dto: NotionDatabaseUpdateDto) -> NotionDatabaseDto:
19
+ update_database_dto_dict = update_database_dto.model_dump(exclude_none=True)
78
20
 
79
- async def search_databases(
80
- self, query: str = "", sort_ascending: bool = True, limit: int = 100
81
- ) -> NotionDatabaseSearchResponse:
82
- """
83
- Searches for databases in Notion using the search endpoint.
21
+ response = await self.patch(f"databases/{self._database_id}", data=update_database_dto_dict)
22
+ return NotionDatabaseDto.model_validate(response)
84
23
 
85
- Args:
86
- query: Search query string
87
- sort_ascending: Whether to sort in ascending order
88
- limit: Maximum number of results to return
89
- """
90
- search_data = {
91
- "query": query,
92
- "filter": {"value": "database", "property": "object"},
93
- "sort": {
94
- "direction": "ascending" if sort_ascending else "descending",
95
- "timestamp": "last_edited_time",
96
- },
97
- "page_size": limit,
98
- }
24
+ async def update_database_title(self, title: str) -> NotionDatabaseDto:
25
+ from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
99
26
 
100
- response = await self.post("search", search_data)
101
- return NotionDatabaseSearchResponse.model_validate(response)
27
+ markdown_rich_text_formatter = MarkdownRichTextConverter()
28
+ database_rich_text = await markdown_rich_text_formatter.to_rich_text(title)
102
29
 
103
- async def create_page(self, parent_database_id: str) -> NotionPageResponse:
104
- """
105
- Creates a new blank page in the given database with minimal properties.
106
- """
107
- page_data = {
108
- "parent": {"database_id": parent_database_id},
109
- "properties": {},
110
- }
111
- response = await self.post("pages", page_data)
112
- return NotionPageResponse.model_validate(response)
30
+ database_title_update_dto = NotionDatabaseUpdateDto(title=database_rich_text)
31
+ return await self.patch_database(database_title_update_dto)
113
32
 
114
- async def update_database_title(
115
- self, database_id: str, title: str
116
- ) -> NotionDatabaseResponse:
117
- """
118
- Updates the title of a database.
119
- """
120
- data = {"title": [{"text": {"content": title}}]}
121
- return await self.patch_database(database_id, data)
33
+ async def update_database_description(self, description: str) -> str:
34
+ from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
122
35
 
123
- async def update_database_emoji(
124
- self, database_id: str, emoji: str
125
- ) -> NotionDatabaseResponse:
126
- """
127
- Updates the emoji/icon of a database.
128
- """
129
- data = {"icon": {"type": "emoji", "emoji": emoji}}
130
- return await self.patch_database(database_id, data)
36
+ markdown_to_rich_text_converter = MarkdownRichTextConverter()
37
+ rich_text_description = await markdown_to_rich_text_converter.to_rich_text(description)
131
38
 
132
- async def update_database_cover_image(
133
- self, database_id: str, image_url: str
134
- ) -> NotionDatabaseResponse:
135
- """
136
- Updates the cover image of a database.
137
- """
138
- data = {"cover": {"type": "external", "external": {"url": image_url}}}
139
- return await self.patch_database(database_id, data)
39
+ database_description_update_dto = NotionDatabaseUpdateDto(description=rich_text_description)
40
+ update_database_response = await self.patch_database(database_description_update_dto)
140
41
 
141
- async def update_database_external_icon(
142
- self, database_id: str, icon_url: str
143
- ) -> NotionDatabaseResponse:
144
- """
145
- Updates the database icon with an external image URL.
146
- """
147
- data = {"icon": {"type": "external", "external": {"url": icon_url}}}
148
- return await self.patch_database(database_id, data)
42
+ rich_text_to_markdown_converter = RichTextToMarkdownConverter()
43
+ return await rich_text_to_markdown_converter.to_markdown(update_database_response.description)
@@ -0,0 +1,19 @@
1
+ from typing import override
2
+
3
+ from notionary.database.schemas import NotionDatabaseDto
4
+ from notionary.http.client import NotionHttpClient
5
+ from notionary.shared.entity.entity_metadata_update_client import EntityMetadataUpdateClient
6
+ from notionary.shared.entity.schemas import NotionEntityUpdateDto
7
+
8
+
9
+ class DatabaseMetadataUpdateClient(NotionHttpClient, EntityMetadataUpdateClient):
10
+ def __init__(self, database_id: str, timeout: int = 30) -> None:
11
+ super().__init__(timeout)
12
+ self._database_id = database_id
13
+
14
+ @override
15
+ async def patch_metadata(self, updated_data: NotionEntityUpdateDto) -> NotionDatabaseDto:
16
+ updated_data_dict = updated_data.model_dump(exclude_unset=True, exclude_none=True)
17
+
18
+ response_dict = await self.patch(f"databases/{self._database_id}", data=updated_data_dict)
19
+ return NotionDatabaseDto.model_validate(response_dict)
@@ -0,0 +1,29 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+ from notionary.blocks.rich_text.models import RichText
4
+ from notionary.shared.entity.schemas import EntityResponseDto
5
+ from notionary.shared.models.cover import NotionCover
6
+ from notionary.shared.models.icon import Icon
7
+
8
+
9
+ class _DataSourceDiscoveryDto(BaseModel):
10
+ id: str
11
+ name: str
12
+
13
+
14
+ class NotionDatabaseDto(EntityResponseDto):
15
+ title: list[RichText]
16
+ description: list[RichText]
17
+ is_inline: bool
18
+ is_locked: bool
19
+ data_sources: list[_DataSourceDiscoveryDto] = Field(default_factory=list)
20
+ url: str
21
+ public_url: str | None = None
22
+
23
+
24
+ class NotionDatabaseUpdateDto(BaseModel):
25
+ title: list[RichText] | None = None
26
+ icon: Icon | None = None
27
+ cover: NotionCover | None = None
28
+ archived: bool | None = None
29
+ description: list[RichText] | None = None