notionary 0.2.27__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.27.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.27.dist-info → notionary-0.2.28.dist-info}/WHEEL +1 -1
  200. {notionary-0.2.27.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 -712
  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.27.dist-info/RECORD +0 -202
@@ -0,0 +1,169 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from collections.abc import Awaitable, Callable
5
+ from typing import Self
6
+
7
+ from notionary.blocks.rich_text.rich_text_markdown_converter import RichTextToMarkdownConverter
8
+ from notionary.data_source.service import NotionDataSource
9
+ from notionary.database.client import NotionDatabaseHttpClient
10
+ from notionary.database.database_metadata_update_client import DatabaseMetadataUpdateClient
11
+ from notionary.database.schemas import NotionDatabaseDto
12
+ from notionary.shared.entity.dto_parsers import (
13
+ extract_cover_image_url_from_dto,
14
+ extract_description,
15
+ extract_emoji_icon_from_dto,
16
+ extract_external_icon_url_from_dto,
17
+ extract_title,
18
+ )
19
+ from notionary.shared.entity.service import Entity
20
+ from notionary.user.schemas import PartialUserDto
21
+ from notionary.workspace.query.service import WorkspaceQueryService
22
+
23
+ type DataSourceFactory = Callable[[str], Awaitable[NotionDataSource]]
24
+
25
+
26
+ class NotionDatabase(Entity):
27
+ def __init__(
28
+ self,
29
+ id: str,
30
+ title: str,
31
+ created_time: str,
32
+ created_by: PartialUserDto,
33
+ last_edited_time: str,
34
+ last_edited_by: PartialUserDto,
35
+ url: str,
36
+ in_trash: bool,
37
+ is_inline: bool,
38
+ data_source_ids: list[str],
39
+ public_url: str | None = None,
40
+ emoji_icon: str | None = None,
41
+ external_icon_url: str | None = None,
42
+ cover_image_url: str | None = None,
43
+ description: str | None = None,
44
+ client: NotionDatabaseHttpClient | None = None,
45
+ metadata_update_client: DatabaseMetadataUpdateClient | None = None,
46
+ ) -> None:
47
+ super().__init__(
48
+ id=id,
49
+ created_time=created_time,
50
+ created_by=created_by,
51
+ last_edited_time=last_edited_time,
52
+ last_edited_by=last_edited_by,
53
+ in_trash=in_trash,
54
+ emoji_icon=emoji_icon,
55
+ external_icon_url=external_icon_url,
56
+ cover_image_url=cover_image_url,
57
+ )
58
+ self._title = title
59
+ self._url = url
60
+ self._public_url = public_url
61
+ self._description = description
62
+ self._is_inline = is_inline
63
+
64
+ self._data_sources: list[NotionDataSource] | None = None
65
+ self._data_source_ids = data_source_ids
66
+
67
+ self.client = client or NotionDatabaseHttpClient(database_id=id)
68
+ self._metadata_update_client = metadata_update_client or DatabaseMetadataUpdateClient(database_id=id)
69
+
70
+ @classmethod
71
+ async def from_id(
72
+ cls,
73
+ database_id: str,
74
+ rich_text_converter: RichTextToMarkdownConverter | None = None,
75
+ database_client: NotionDatabaseHttpClient | None = None,
76
+ ) -> Self:
77
+ converter = rich_text_converter or RichTextToMarkdownConverter()
78
+ client = database_client or NotionDatabaseHttpClient(database_id=database_id)
79
+
80
+ async with client:
81
+ response_dto = await client.get_database()
82
+
83
+ return await cls._create_from_dto(response_dto, converter, client)
84
+
85
+ @classmethod
86
+ async def from_title(
87
+ cls,
88
+ database_title: str,
89
+ min_similarity: float = 0.6,
90
+ search_service: WorkspaceQueryService | None = None,
91
+ ) -> Self:
92
+ service = search_service or WorkspaceQueryService()
93
+ return await service.find_database(database_title, min_similarity=min_similarity)
94
+
95
+ @classmethod
96
+ async def _create_from_dto(
97
+ cls,
98
+ response: NotionDatabaseDto,
99
+ rich_text_converter: RichTextToMarkdownConverter,
100
+ client: NotionDatabaseHttpClient,
101
+ ) -> Self:
102
+ title, description = await asyncio.gather(
103
+ extract_title(response, rich_text_converter), extract_description(response, rich_text_converter)
104
+ )
105
+
106
+ return cls(
107
+ id=response.id,
108
+ title=title,
109
+ description=description,
110
+ created_time=response.created_time,
111
+ created_by=response.created_by,
112
+ last_edited_time=response.last_edited_time,
113
+ last_edited_by=response.last_edited_by,
114
+ in_trash=response.in_trash,
115
+ is_inline=response.is_inline,
116
+ url=response.url,
117
+ public_url=response.public_url,
118
+ emoji_icon=extract_emoji_icon_from_dto(response),
119
+ external_icon_url=extract_external_icon_url_from_dto(response),
120
+ cover_image_url=extract_cover_image_url_from_dto(response),
121
+ data_source_ids=[ds.id for ds in response.data_sources],
122
+ client=client,
123
+ )
124
+
125
+ @property
126
+ def _entity_metadata_update_client(self) -> DatabaseMetadataUpdateClient:
127
+ return self._metadata_update_client
128
+
129
+ @property
130
+ def title(self) -> str:
131
+ return self._title
132
+
133
+ @property
134
+ def url(self) -> str:
135
+ return self._url
136
+
137
+ @property
138
+ def public_url(self) -> str | None:
139
+ return self._public_url
140
+
141
+ @property
142
+ def is_inline(self) -> bool:
143
+ return self._is_inline
144
+
145
+ def get_description(self) -> str | None:
146
+ return self._description
147
+
148
+ async def get_data_sources(
149
+ self,
150
+ data_source_factory: DataSourceFactory = NotionDataSource.from_id,
151
+ ) -> list[NotionDataSource]:
152
+ if self._data_sources is None:
153
+ self._data_sources = await self._load_data_sources(data_source_factory)
154
+ return self._data_sources
155
+
156
+ async def _load_data_sources(
157
+ self,
158
+ data_source_factory: DataSourceFactory,
159
+ ) -> list[NotionDataSource]:
160
+ tasks = [data_source_factory(ds_id) for ds_id in self._data_source_ids]
161
+ return list(await asyncio.gather(*tasks))
162
+
163
+ async def set_title(self, title: str) -> None:
164
+ result = await self.client.update_database_title(title=title)
165
+ self._title = result.title[0].plain_text if result.title else ""
166
+
167
+ async def set_description(self, description: str) -> None:
168
+ updated_description = await self.client.update_database_description(description=description)
169
+ self._description = updated_description
@@ -0,0 +1,33 @@
1
+ from .api import (
2
+ NotionApiError,
3
+ NotionAuthenticationError,
4
+ NotionConnectionError,
5
+ NotionRateLimitError,
6
+ NotionResourceNotFoundError,
7
+ NotionServerError,
8
+ NotionValidationError,
9
+ )
10
+ from .base import NotionaryError
11
+ from .data_source.properties import DataSourcePropertyNotFound, DataSourcePropertyTypeError
12
+ from .properties import AccessPagePropertyWithoutDataSourceError, PagePropertyNotFoundError, PagePropertyTypeError
13
+ from .search import DatabaseNotFound, DataSourceNotFound, EntityNotFound, PageNotFound
14
+
15
+ __all__ = [
16
+ "AccessPagePropertyWithoutDataSourceError",
17
+ "DataSourceNotFound",
18
+ "DataSourcePropertyNotFound",
19
+ "DataSourcePropertyTypeError",
20
+ "DatabaseNotFound",
21
+ "EntityNotFound",
22
+ "NotionApiError",
23
+ "NotionAuthenticationError",
24
+ "NotionConnectionError",
25
+ "NotionRateLimitError",
26
+ "NotionResourceNotFoundError",
27
+ "NotionServerError",
28
+ "NotionValidationError",
29
+ "NotionaryError",
30
+ "PageNotFound",
31
+ "PagePropertyNotFoundError",
32
+ "PagePropertyTypeError",
33
+ ]
@@ -0,0 +1,41 @@
1
+ from notionary.exceptions.base import NotionaryError
2
+
3
+
4
+ class NotionApiError(NotionaryError):
5
+ def __init__(
6
+ self,
7
+ message: str,
8
+ status_code: int | None = None,
9
+ response_text: int | None = None,
10
+ ):
11
+ super().__init__(message)
12
+ self.status_code = status_code
13
+ self.response_text = response_text
14
+
15
+
16
+ class NotionAuthenticationError(NotionApiError):
17
+ pass
18
+
19
+
20
+ class NotionPermissionError(NotionApiError):
21
+ pass
22
+
23
+
24
+ class NotionRateLimitError(NotionApiError):
25
+ pass
26
+
27
+
28
+ class NotionResourceNotFoundError(NotionApiError):
29
+ pass
30
+
31
+
32
+ class NotionValidationError(NotionApiError):
33
+ pass
34
+
35
+
36
+ class NotionServerError(NotionApiError):
37
+ pass
38
+
39
+
40
+ class NotionConnectionError(NotionApiError):
41
+ pass
@@ -0,0 +1,2 @@
1
+ class NotionaryError(Exception):
2
+ pass
@@ -0,0 +1,16 @@
1
+ from notionary.exceptions.base import NotionaryError
2
+
3
+ RATIO_TOLERANCE = 0.0001
4
+
5
+
6
+ class InsufficientColumnsError(NotionaryError):
7
+ def __init__(self, column_count: int) -> None:
8
+ self.column_count = column_count
9
+ super().__init__(f"Columns container must contain at least 2 column blocks, but only {column_count} found")
10
+
11
+
12
+ class InvalidColumnRatioSumError(NotionaryError):
13
+ def __init__(self, total: float, tolerance: float = RATIO_TOLERANCE) -> None:
14
+ self.total = total
15
+ self.tolerance = tolerance
16
+ super().__init__(f"Width ratios must sum to 1.0 (±{tolerance}), but sum is {total}")
@@ -0,0 +1,6 @@
1
+ from .properties import DataSourcePropertyNotFound, DataSourcePropertyTypeError
2
+
3
+ __all__ = [
4
+ "DataSourcePropertyNotFound",
5
+ "DataSourcePropertyTypeError",
6
+ ]
@@ -0,0 +1,182 @@
1
+ from typing import Any
2
+
3
+ from notionary.data_source.query.schema import (
4
+ ArrayOperator,
5
+ BooleanOperator,
6
+ DateOperator,
7
+ NumberOperator,
8
+ Operator,
9
+ StringOperator,
10
+ )
11
+ from notionary.exceptions.base import NotionaryError
12
+ from notionary.shared.properties.type import PropertyType
13
+
14
+
15
+ class QueryBuilderError(NotionaryError):
16
+ def __init__(self, message: str, property_name: str | None = None) -> None:
17
+ self.property_name = property_name
18
+ super().__init__(message)
19
+
20
+
21
+ class InvalidOperatorForPropertyType(QueryBuilderError):
22
+ def __init__(
23
+ self,
24
+ property_name: str,
25
+ property_type: PropertyType,
26
+ operator: Operator,
27
+ valid_operators: list[Operator],
28
+ ) -> None:
29
+ self.property_type = property_type
30
+ self.operator = operator
31
+ self.valid_operators = valid_operators
32
+
33
+ valid_operators_str = ", ".join([f"'{op.value}'" for op in valid_operators])
34
+ message = (
35
+ f"Cannot use operator '{operator.value}' on property '{property_name}' of type '{property_type}'. "
36
+ f"Valid operators for this property type are: {valid_operators_str}"
37
+ )
38
+ super().__init__(message, property_name)
39
+
40
+
41
+ class InvalidValueForOperator(QueryBuilderError):
42
+ def __init__(
43
+ self,
44
+ property_name: str,
45
+ operator: Operator,
46
+ provided_value: Any,
47
+ expected_value_type: str,
48
+ example_value: Any | None = None,
49
+ ) -> None:
50
+ self.operator = operator
51
+ self.provided_value = provided_value
52
+ self.expected_value_type = expected_value_type
53
+ self.example_value = example_value
54
+
55
+ message = (
56
+ f"Invalid value for operator '{operator.value}' on property '{property_name}'. "
57
+ f"Expected {expected_value_type}, but got {type(provided_value).__name__}"
58
+ )
59
+
60
+ if example_value is not None:
61
+ message += f". Example: {example_value}"
62
+
63
+ super().__init__(message, property_name)
64
+
65
+
66
+ class MissingRequiredValue(QueryBuilderError):
67
+ def __init__(
68
+ self,
69
+ property_name: str,
70
+ operator: StringOperator | NumberOperator | BooleanOperator | DateOperator | ArrayOperator,
71
+ ) -> None:
72
+ self.operator = operator
73
+
74
+ message = f"Operator '{operator.value}' on property '{property_name}' requires a value, but none was provided"
75
+ super().__init__(message, property_name)
76
+
77
+
78
+ class ValueNotAllowedForOperator(QueryBuilderError):
79
+ def __init__(
80
+ self,
81
+ property_name: str,
82
+ operator: StringOperator | NumberOperator | BooleanOperator | DateOperator | ArrayOperator,
83
+ ) -> None:
84
+ self.operator = operator
85
+
86
+ message = (
87
+ f"Operator '{operator.value}' on property '{property_name}' does not accept a value. "
88
+ f"Operators like 'is_empty', 'is_not_empty', 'is_true', 'is_false' don't need values"
89
+ )
90
+ super().__init__(message, property_name)
91
+
92
+
93
+ class InvalidDateFormat(QueryBuilderError):
94
+ def __init__(
95
+ self,
96
+ property_name: str,
97
+ provided_date: str,
98
+ expected_format: str = "ISO 8601 (YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS)",
99
+ ) -> None:
100
+ self.provided_date = provided_date
101
+ self.expected_format = expected_format
102
+
103
+ message = (
104
+ f"Invalid date format for property '{property_name}'. "
105
+ f"Provided: '{provided_date}', expected format: {expected_format}"
106
+ )
107
+ super().__init__(message, property_name)
108
+
109
+
110
+ class InvalidNumberValue(QueryBuilderError):
111
+ def __init__(
112
+ self,
113
+ property_name: str,
114
+ provided_value: Any,
115
+ reason: str,
116
+ ) -> None:
117
+ self.provided_value = provided_value
118
+ self.reason = reason
119
+
120
+ message = f"Invalid number value for property '{property_name}': {reason}. Provided value: {provided_value}"
121
+ super().__init__(message, property_name)
122
+
123
+
124
+ class PropertyNotConfigured(QueryBuilderError):
125
+ def __init__(
126
+ self,
127
+ property_name: str,
128
+ ) -> None:
129
+ message = (
130
+ f"Property '{property_name}' exists but has no type configuration. "
131
+ f"Cannot determine valid operators for this property"
132
+ )
133
+ super().__init__(message, property_name)
134
+
135
+
136
+ class NoPropertySelected(QueryBuilderError):
137
+ def __init__(self) -> None:
138
+ message = (
139
+ "No property selected. Use .where('property_name') or .where_not('property_name') "
140
+ "before calling an operator method like .equals(), .contains(), etc."
141
+ )
142
+ super().__init__(message)
143
+
144
+
145
+ class EmptyOrGroupError(QueryBuilderError):
146
+ def __init__(self) -> None:
147
+ message = (
148
+ "Cannot create an OR group with no conditions. Add at least one filter condition before using .or_where()"
149
+ )
150
+ super().__init__(message)
151
+
152
+
153
+ class ConflictingFiltersError(QueryBuilderError):
154
+ def __init__(
155
+ self,
156
+ property_name: str,
157
+ description: str,
158
+ ) -> None:
159
+ message = (
160
+ f"Conflicting filters detected on property '{property_name}': {description}. "
161
+ f"This query will never return any results"
162
+ )
163
+ super().__init__(message, property_name)
164
+
165
+
166
+ class InvalidSortProperty(QueryBuilderError):
167
+ def __init__(
168
+ self,
169
+ property_name: str,
170
+ reason: str,
171
+ available_properties: list[str] | None = None,
172
+ ) -> None:
173
+ self.available_properties = available_properties
174
+ self.reason = reason
175
+
176
+ message = f"Cannot sort by property '{property_name}': {reason}"
177
+
178
+ if available_properties:
179
+ props_str = ", ".join([f"'{p}'" for p in sorted(available_properties)])
180
+ message += f". Available properties: {props_str}"
181
+
182
+ super().__init__(message, property_name)
@@ -0,0 +1,34 @@
1
+ import difflib
2
+
3
+ from notionary.exceptions.base import NotionaryError
4
+
5
+
6
+ class DataSourcePropertyNotFound(NotionaryError):
7
+ def __init__(
8
+ self,
9
+ property_name: str,
10
+ available_properties: list[str] | None = None,
11
+ max_suggestions: int = 5,
12
+ cutoff: float = 0.6,
13
+ ) -> None:
14
+ self.property_name = property_name
15
+
16
+ # Calculate suggestions from available properties
17
+ if available_properties:
18
+ self.suggestions = difflib.get_close_matches(
19
+ property_name, available_properties, n=max_suggestions, cutoff=cutoff
20
+ )
21
+ else:
22
+ self.suggestions = []
23
+
24
+ message = f"Property '{self.property_name}' not found."
25
+ if self.suggestions:
26
+ suggestions_str = "', '".join(self.suggestions)
27
+ message += f" Did you mean '{suggestions_str}'?"
28
+ super().__init__(message)
29
+
30
+
31
+ class DataSourcePropertyTypeError(NotionaryError):
32
+ def __init__(self, property_name: str, expected_type: str, actual_type: str) -> None:
33
+ message = f"Property '{property_name}' has the wrong type. Expected: '{expected_type}', found: '{actual_type}'."
34
+ super().__init__(message)
@@ -0,0 +1,58 @@
1
+ import difflib
2
+ from typing import ClassVar
3
+
4
+ from notionary.exceptions.base import NotionaryError
5
+ from notionary.shared.models.parent import ParentType
6
+
7
+
8
+ class PagePropertyNotFoundError(NotionaryError):
9
+ def __init__(
10
+ self,
11
+ page_url: str,
12
+ property_name: str,
13
+ available_properties: list[str] | None = None,
14
+ max_suggestions: int = 3,
15
+ cutoff: float = 0.6,
16
+ ) -> None:
17
+ self.property_name = property_name
18
+
19
+ if available_properties:
20
+ self.suggestions = difflib.get_close_matches(
21
+ property_name, available_properties, n=max_suggestions, cutoff=cutoff
22
+ )
23
+ else:
24
+ self.suggestions = []
25
+
26
+ message = f"Property '{property_name}' not found."
27
+ if self.suggestions:
28
+ suggestions_str = "', '".join(self.suggestions)
29
+ message += f" Did you mean '{suggestions_str}'?"
30
+ message += f" Please check the page at {page_url} to verify if the property exists and is correctly named."
31
+ super().__init__(message)
32
+
33
+
34
+ class PagePropertyTypeError(NotionaryError):
35
+ def __init__(
36
+ self,
37
+ property_name: str,
38
+ actual_type: str,
39
+ ) -> None:
40
+ message = f"Property '{property_name}' is of type '{actual_type}'. Use the appropriate getter method for this property type."
41
+ super().__init__(message)
42
+
43
+
44
+ class AccessPagePropertyWithoutDataSourceError(NotionaryError):
45
+ _PARENT_DESCRIPTIONS: ClassVar[dict[ParentType, str]] = {
46
+ ParentType.WORKSPACE: "the workspace itself",
47
+ ParentType.PAGE_ID: "another page",
48
+ ParentType.BLOCK_ID: "a block",
49
+ ParentType.DATABASE_ID: "a database",
50
+ }
51
+
52
+ def __init__(self, parent_type: ParentType) -> None:
53
+ parent_desc = self._PARENT_DESCRIPTIONS.get(parent_type, f"its parent type is '{parent_type}'")
54
+ message = (
55
+ f"Cannot access properties other than title because this page's parent is {parent_desc}. "
56
+ "To use operations like property reading/writing, you need to use a page whose parent is a data source."
57
+ )
58
+ super().__init__(message)
@@ -0,0 +1,33 @@
1
+ from notionary.exceptions.base import NotionaryError
2
+
3
+
4
+ class EntityNotFound(NotionaryError):
5
+ def __init__(self, entity_type: str, query: str, available_titles: list[str] | None = None) -> None:
6
+ self.entity_type = entity_type
7
+ self.query = query
8
+ self.available_titles = available_titles or []
9
+
10
+ if self.available_titles:
11
+ message = (
12
+ f"No sufficiently similar {entity_type} found for query '{query}'. "
13
+ f"Did you mean one of these? Top results: {self.available_titles}"
14
+ )
15
+ else:
16
+ message = f"No {entity_type} found for query '{query}'. The search returned no results."
17
+
18
+ super().__init__(message)
19
+
20
+
21
+ class PageNotFound(EntityNotFound):
22
+ def __init__(self, query: str, available_titles: list[str] | None = None) -> None:
23
+ super().__init__("page", query, available_titles)
24
+
25
+
26
+ class DataSourceNotFound(EntityNotFound):
27
+ def __init__(self, query: str, available_titles: list[str] | None = None) -> None:
28
+ super().__init__("data source", query, available_titles)
29
+
30
+
31
+ class DatabaseNotFound(EntityNotFound):
32
+ def __init__(self, query: str, available_titles: list[str] | None = None) -> None:
33
+ super().__init__("database", query, available_titles)