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,225 @@
1
+ from collections.abc import Callable
2
+ from typing import Self
3
+
4
+ from notionary.blocks.client import NotionBlockHttpClient
5
+ from notionary.blocks.rich_text.rich_text_markdown_converter import convert_rich_text_to_markdown
6
+ from notionary.comments.models import Comment
7
+ from notionary.comments.service import CommentService
8
+ from notionary.page.content.factory import PageContentServiceFactory
9
+ from notionary.page.content.markdown.builder import MarkdownBuilder
10
+ from notionary.page.content.service import PageContentService
11
+ from notionary.page.page_http_client import NotionPageHttpClient
12
+ from notionary.page.page_metadata_update_client import PageMetadataUpdateClient
13
+ from notionary.page.properties.factory import PagePropertyHandlerFactory
14
+ from notionary.page.properties.models import PageTitleProperty
15
+ from notionary.page.properties.service import PagePropertyHandler
16
+ from notionary.page.schemas import NotionPageDto
17
+ from notionary.shared.entity.dto_parsers import (
18
+ extract_cover_image_url_from_dto,
19
+ extract_emoji_icon_from_dto,
20
+ extract_external_icon_url_from_dto,
21
+ )
22
+ from notionary.shared.entity.service import Entity
23
+ from notionary.user.schemas import PartialUserDto
24
+ from notionary.workspace.query.service import WorkspaceQueryService
25
+
26
+
27
+ class NotionPage(Entity):
28
+ def __init__(
29
+ self,
30
+ id: str,
31
+ title: str,
32
+ created_time: str,
33
+ created_by: PartialUserDto,
34
+ last_edited_time: str,
35
+ last_edited_by: PartialUserDto,
36
+ url: str,
37
+ archived: bool,
38
+ in_trash: bool,
39
+ page_property_handler: PagePropertyHandler,
40
+ block_client: NotionBlockHttpClient,
41
+ comment_service: CommentService,
42
+ page_content_service: PageContentService,
43
+ metadata_update_client: PageMetadataUpdateClient,
44
+ public_url: str | None = None,
45
+ emoji_icon: str | None = None,
46
+ external_icon_url: str | None = None,
47
+ cover_image_url: str | None = None,
48
+ ) -> None:
49
+ super().__init__(
50
+ id=id,
51
+ created_time=created_time,
52
+ created_by=created_by,
53
+ last_edited_time=last_edited_time,
54
+ last_edited_by=last_edited_by,
55
+ in_trash=in_trash,
56
+ emoji_icon=emoji_icon,
57
+ external_icon_url=external_icon_url,
58
+ cover_image_url=cover_image_url,
59
+ )
60
+ self._title = title
61
+ self._archived = archived
62
+ self._url = url
63
+ self._public_url = public_url
64
+
65
+ self._block_client = block_client
66
+ self._comment_service = comment_service
67
+ self._page_content_service = page_content_service
68
+ self.properties = page_property_handler
69
+ self._metadata_update_client = metadata_update_client
70
+
71
+ @classmethod
72
+ async def from_id(
73
+ cls,
74
+ page_id: str,
75
+ page_property_handler_factory: PagePropertyHandlerFactory | None = None,
76
+ ) -> Self:
77
+ factory = page_property_handler_factory or PagePropertyHandlerFactory()
78
+ response = await cls._fetch_page_dto(page_id)
79
+ return await cls._create_from_dto(response, factory)
80
+
81
+ @classmethod
82
+ async def from_title(
83
+ cls,
84
+ page_title: str,
85
+ search_service: WorkspaceQueryService | None = None,
86
+ ) -> Self:
87
+ service = search_service or WorkspaceQueryService()
88
+ return await service.find_page(page_title)
89
+
90
+ @classmethod
91
+ async def _fetch_page_dto(cls, page_id: str) -> NotionPageDto:
92
+ async with NotionPageHttpClient(page_id=page_id) as client:
93
+ return await client.get_page()
94
+
95
+ @classmethod
96
+ async def _create_from_dto(
97
+ cls,
98
+ response: NotionPageDto,
99
+ page_property_handler_factory: PagePropertyHandlerFactory,
100
+ ) -> Self:
101
+ title_task = cls._extract_title_from_dto(response)
102
+ page_property_handler = page_property_handler_factory.create_from_page_response(response)
103
+
104
+ title = await title_task
105
+
106
+ return cls._create_with_dependencies(
107
+ id=response.id,
108
+ title=title,
109
+ created_time=response.created_time,
110
+ created_by=response.created_by,
111
+ last_edited_time=response.last_edited_time,
112
+ last_edited_by=response.last_edited_by,
113
+ archived=response.archived,
114
+ in_trash=response.in_trash,
115
+ url=response.url,
116
+ page_property_handler=page_property_handler,
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
+ )
122
+
123
+ @classmethod
124
+ def _create_with_dependencies(
125
+ cls,
126
+ id: str,
127
+ title: str,
128
+ created_time: str,
129
+ created_by: PartialUserDto,
130
+ last_edited_time: str,
131
+ last_edited_by: PartialUserDto,
132
+ url: str,
133
+ archived: bool,
134
+ in_trash: bool,
135
+ page_property_handler: PagePropertyHandler,
136
+ public_url: str | None = None,
137
+ emoji_icon: str | None = None,
138
+ external_icon_url: str | None = None,
139
+ cover_image_url: str | None = None,
140
+ ) -> Self:
141
+ block_client = NotionBlockHttpClient()
142
+ comment_service = CommentService()
143
+
144
+ page_content_service_factory = PageContentServiceFactory()
145
+ page_content_service = page_content_service_factory.create(page_id=id, block_client=block_client)
146
+
147
+ metadata_update_client = PageMetadataUpdateClient(page_id=id)
148
+
149
+ return cls(
150
+ id=id,
151
+ title=title,
152
+ created_time=created_time,
153
+ created_by=created_by,
154
+ last_edited_time=last_edited_time,
155
+ last_edited_by=last_edited_by,
156
+ url=url,
157
+ archived=archived,
158
+ in_trash=in_trash,
159
+ page_property_handler=page_property_handler,
160
+ block_client=block_client,
161
+ comment_service=comment_service,
162
+ page_content_service=page_content_service,
163
+ metadata_update_client=metadata_update_client,
164
+ public_url=public_url,
165
+ emoji_icon=emoji_icon,
166
+ external_icon_url=external_icon_url,
167
+ cover_image_url=cover_image_url,
168
+ )
169
+
170
+ @staticmethod
171
+ async def _extract_title_from_dto(response: NotionPageDto) -> str:
172
+ title_property = next(
173
+ (prop for prop in response.properties.values() if isinstance(prop, PageTitleProperty)),
174
+ None,
175
+ )
176
+ rich_text_title = title_property.title if title_property else []
177
+ return await convert_rich_text_to_markdown(rich_text_title)
178
+
179
+ @property
180
+ def _entity_metadata_update_client(self) -> PageMetadataUpdateClient:
181
+ return self._metadata_update_client
182
+
183
+ @property
184
+ def title(self) -> str:
185
+ return self._title
186
+
187
+ @property
188
+ def url(self) -> str:
189
+ return self._url
190
+
191
+ @property
192
+ def markdown_builder() -> MarkdownBuilder:
193
+ return MarkdownBuilder()
194
+
195
+ async def get_comments(self) -> list[Comment]:
196
+ return await self._comment_service.list_all_comments_for_page(page_id=self._id)
197
+
198
+ async def post_top_level_comment(self, comment: str) -> None:
199
+ await self._comment_service.create_comment_on_page(page_id=self._id, text=comment)
200
+
201
+ async def post_reply_to_discussion(self, discussion_id: str, comment: str) -> None:
202
+ await self._comment_service.reply_to_discussion_by_id(discussion_id=discussion_id, text=comment)
203
+
204
+ async def set_title(self, title: str) -> None:
205
+ await self.properties.set_title_property(title)
206
+ self._title = title
207
+
208
+ async def append_markdown(
209
+ self,
210
+ content: (str | Callable[[MarkdownBuilder], MarkdownBuilder]),
211
+ ) -> None:
212
+ await self._page_content_service.append_markdown(content=content)
213
+
214
+ async def replace_content(
215
+ self,
216
+ content: (str | Callable[[MarkdownBuilder], MarkdownBuilder]),
217
+ ) -> None:
218
+ await self._page_content_service.clear()
219
+ await self._page_content_service.append_markdown(content=content)
220
+
221
+ async def clear_page_content(self) -> None:
222
+ await self._page_content_service.clear()
223
+
224
+ async def get_markdown_content(self) -> str:
225
+ return await self._page_content_service.get_as_markdown()
@@ -0,0 +1,29 @@
1
+ from typing import TypeVar, override
2
+
3
+ from notionary.http.client import NotionHttpClient
4
+ from notionary.shared.entity.entity_metadata_update_client import EntityMetadataUpdateClient
5
+ from notionary.shared.entity.schemas import EntityResponseDto, NotionEntityUpdateDto
6
+
7
+ ResponseType = TypeVar("ResponseType", bound=EntityResponseDto)
8
+
9
+
10
+ class GenericEntityMetadataUpdateClient(NotionHttpClient, EntityMetadataUpdateClient):
11
+ def __init__(
12
+ self,
13
+ entity_id: str,
14
+ path_segment: str,
15
+ response_dto_class: type[ResponseType],
16
+ timeout: int = 30,
17
+ ) -> None:
18
+ super().__init__(timeout)
19
+ self._entity_id = entity_id
20
+ self._path_segment = path_segment
21
+ self._response_dto_class = response_dto_class
22
+
23
+ @override
24
+ async def patch_metadata(self, updated_data: NotionEntityUpdateDto) -> ResponseType:
25
+ updated_data_dict = updated_data.model_dump(exclude_unset=True, exclude_none=True)
26
+ url = f"{self._path_segment}/{self._entity_id}"
27
+
28
+ response_dict = await self.patch(url, data=updated_data_dict)
29
+ return self._response_dto_class.model_validate(response_dict)
@@ -0,0 +1,53 @@
1
+ from typing import cast
2
+
3
+ from notionary.blocks.rich_text.rich_text_markdown_converter import RichTextToMarkdownConverter
4
+ from notionary.shared.entity.schemas import Describable, EntityResponseDto, Titled
5
+ from notionary.shared.models.cover import CoverType
6
+ from notionary.shared.models.icon import IconType
7
+ from notionary.shared.models.parent import DatabaseParent, DataSourceParent, ParentType
8
+
9
+
10
+ def extract_emoji_icon_from_dto(entity_dto: EntityResponseDto) -> str | None:
11
+ if not entity_dto.icon or entity_dto.icon.type != IconType.EMOJI:
12
+ return None
13
+ return entity_dto.icon.emoji
14
+
15
+
16
+ def extract_external_icon_url_from_dto(entity_dto: EntityResponseDto) -> str | None:
17
+ if not entity_dto.icon or entity_dto.icon.type != IconType.EXTERNAL:
18
+ return None
19
+ return entity_dto.icon.external.url if entity_dto.icon.external else None
20
+
21
+
22
+ def extract_cover_image_url_from_dto(entity_dto: EntityResponseDto) -> str | None:
23
+ if not entity_dto.cover or entity_dto.cover.type != CoverType.EXTERNAL:
24
+ return None
25
+ return entity_dto.cover.external.url if entity_dto.cover.external else None
26
+
27
+
28
+ def extract_database_id(entity_dto: EntityResponseDto) -> str | None:
29
+ if entity_dto.parent.type == ParentType.DATA_SOURCE_ID:
30
+ data_source_parent = cast(DataSourceParent, entity_dto.parent)
31
+ return data_source_parent.database_id if data_source_parent else None
32
+
33
+ if entity_dto.parent.type == ParentType.DATABASE_ID:
34
+ database_parent = cast(DatabaseParent, entity_dto.parent)
35
+ return database_parent.database_id if database_parent else None
36
+
37
+ return None
38
+
39
+
40
+ async def extract_title(
41
+ entity: Titled,
42
+ rich_text_converter: RichTextToMarkdownConverter,
43
+ ) -> str:
44
+ return await rich_text_converter.to_markdown(entity.title)
45
+
46
+
47
+ async def extract_description(
48
+ entity: Describable,
49
+ rich_text_converter: RichTextToMarkdownConverter,
50
+ ) -> str | None:
51
+ if not entity.description:
52
+ return None
53
+ return await rich_text_converter.to_markdown(entity.description)
@@ -0,0 +1,41 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from notionary.shared.entity.schemas import EntityResponseDto, NotionEntityUpdateDto
4
+ from notionary.shared.models.cover import NotionCover
5
+ from notionary.shared.models.icon import EmojiIcon, ExternalIcon
6
+
7
+
8
+ class EntityMetadataUpdateClient(ABC):
9
+ @abstractmethod
10
+ async def patch_metadata(self, updated_data: NotionEntityUpdateDto) -> EntityResponseDto: ...
11
+
12
+ async def patch_emoji_icon(self, emoji: str) -> EntityResponseDto:
13
+ icon = EmojiIcon(emoji=emoji)
14
+ update_dto = NotionEntityUpdateDto(icon=icon)
15
+ return await self.patch_metadata(update_dto)
16
+
17
+ async def patch_external_icon(self, icon_url: str) -> EntityResponseDto:
18
+ icon = ExternalIcon.from_url(icon_url)
19
+ update_dto = NotionEntityUpdateDto(icon=icon)
20
+ return await self.patch_metadata(update_dto)
21
+
22
+ async def remove_icon(self) -> None:
23
+ update_dto = NotionEntityUpdateDto(icon=None)
24
+ return await self.patch_metadata(update_dto)
25
+
26
+ async def patch_external_cover(self, cover_url: str) -> EntityResponseDto:
27
+ cover = NotionCover.from_url(cover_url)
28
+ update_dto = NotionEntityUpdateDto(cover=cover)
29
+ return await self.patch_metadata(update_dto)
30
+
31
+ async def remove_cover(self) -> None:
32
+ update_dto = NotionEntityUpdateDto(cover=None)
33
+ return await self.patch_metadata(update_dto)
34
+
35
+ async def move_to_trash(self) -> EntityResponseDto:
36
+ update_dto = NotionEntityUpdateDto(in_trash=True)
37
+ return await self.patch_metadata(update_dto)
38
+
39
+ async def restore_from_trash(self) -> EntityResponseDto:
40
+ update_dto = NotionEntityUpdateDto(in_trash=False)
41
+ return await self.patch_metadata(update_dto)
@@ -0,0 +1,45 @@
1
+ from enum import StrEnum
2
+ from typing import Protocol
3
+
4
+ from pydantic import BaseModel
5
+
6
+ from notionary.blocks.rich_text.models import RichText
7
+ from notionary.shared.models.cover import NotionCover
8
+ from notionary.shared.models.icon import Icon
9
+ from notionary.shared.models.parent import Parent
10
+ from notionary.user.schemas import PartialUserDto
11
+
12
+
13
+ class EntityWorkspaceQueryObjectType(StrEnum):
14
+ PAGE = "page"
15
+ DATA_SOURCE = "data_source"
16
+ DATABASE = "database"
17
+
18
+
19
+ class EntityResponseDto(BaseModel):
20
+ object: EntityWorkspaceQueryObjectType
21
+ id: str
22
+ created_time: str
23
+ created_by: PartialUserDto
24
+ last_edited_time: str
25
+ last_edited_by: PartialUserDto
26
+ cover: NotionCover | None = None
27
+ icon: Icon | None = None
28
+ parent: Parent
29
+ in_trash: bool
30
+ url: str
31
+ public_url: str | None = None
32
+
33
+
34
+ class NotionEntityUpdateDto(BaseModel):
35
+ icon: Icon | None = None
36
+ cover: NotionCover | None = None
37
+ in_trash: bool | None = None
38
+
39
+
40
+ class Titled(Protocol):
41
+ title: list[RichText]
42
+
43
+
44
+ class Describable(Protocol):
45
+ description: list[RichText] | None
@@ -0,0 +1,171 @@
1
+ from __future__ import annotations
2
+
3
+ import random
4
+ from abc import ABC, abstractmethod
5
+ from collections.abc import Sequence
6
+ from typing import TYPE_CHECKING, Self
7
+
8
+ from notionary.shared.entity.entity_metadata_update_client import EntityMetadataUpdateClient
9
+ from notionary.user.schemas import PartialUserDto
10
+ from notionary.user.service import UserService
11
+ from notionary.utils.mixins.logging import LoggingMixin
12
+ from notionary.utils.uuid_utils import extract_uuid
13
+
14
+ if TYPE_CHECKING:
15
+ from notionary.user.base import BaseUser
16
+
17
+
18
+ class Entity(LoggingMixin, ABC):
19
+ def __init__(
20
+ self,
21
+ id: str,
22
+ created_time: str,
23
+ created_by: PartialUserDto,
24
+ last_edited_time: str,
25
+ last_edited_by: PartialUserDto,
26
+ in_trash: bool,
27
+ emoji_icon: str | None = None,
28
+ external_icon_url: str | None = None,
29
+ cover_image_url: str | None = None,
30
+ user_service: UserService | None = None,
31
+ ) -> None:
32
+ self._id = id
33
+ self._created_time = created_time
34
+ self._created_by = created_by
35
+ self._last_edited_time = last_edited_time
36
+ self._last_edited_by = last_edited_by
37
+ self._emoji_icon = emoji_icon
38
+ self._external_icon_url = external_icon_url
39
+ self._cover_image_url = cover_image_url
40
+ self._in_trash = in_trash
41
+ self._user_service = user_service or UserService()
42
+
43
+ @classmethod
44
+ @abstractmethod
45
+ async def from_id(cls, id: str) -> Self:
46
+ pass
47
+
48
+ @classmethod
49
+ @abstractmethod
50
+ async def from_title(cls, title: str) -> Self:
51
+ pass
52
+
53
+ @classmethod
54
+ async def from_url(cls, url: str) -> Self:
55
+ entity_id = extract_uuid(url)
56
+ if not entity_id:
57
+ raise ValueError(f"Could not extract entity ID from URL: {url}")
58
+ return await cls.from_id(entity_id)
59
+
60
+ @property
61
+ @abstractmethod
62
+ def _entity_metadata_update_client(self) -> EntityMetadataUpdateClient:
63
+ # functionality for updating properties like title, icon, cover, archive status depends on interface for template like implementation
64
+ # has to be implementated by inheritants to correctly use the methods below
65
+ ...
66
+
67
+ @property
68
+ def id(self) -> str:
69
+ return self._id
70
+
71
+ @property
72
+ def created_time(self) -> str:
73
+ return self._created_time
74
+
75
+ @property
76
+ def last_edited_time(self) -> str:
77
+ return self._last_edited_time
78
+
79
+ @property
80
+ def in_trash(self) -> bool:
81
+ return self._in_trash
82
+
83
+ @property
84
+ def emoji_icon(self) -> str | None:
85
+ return self._emoji_icon
86
+
87
+ @property
88
+ def external_icon_url(self) -> str | None:
89
+ return self._external_icon_url
90
+
91
+ @property
92
+ def cover_image_url(self) -> str | None:
93
+ return self._cover_image_url
94
+
95
+ @property
96
+ def created_by(self) -> PartialUserDto:
97
+ return self._created_by
98
+
99
+ @property
100
+ def last_edited_by(self) -> PartialUserDto:
101
+ return self._last_edited_by
102
+
103
+ async def get_created_by_user(self) -> BaseUser | None:
104
+ return await self._user_service.get_user_by_id(self._created_by.id)
105
+
106
+ async def get_last_edited_by_user(self) -> BaseUser | None:
107
+ return await self._user_service.get_user_by_id(self._last_edited_by.id)
108
+
109
+ async def set_emoji_icon(self, emoji: str) -> None:
110
+ entity_response = await self._entity_metadata_update_client.patch_emoji_icon(emoji)
111
+ self._emoji_icon = entity_response.icon.emoji if entity_response.icon else None
112
+ self._external_icon_url = None
113
+
114
+ async def set_external_icon(self, icon_url: str) -> None:
115
+ entity_response = await self._entity_metadata_update_client.patch_external_icon(icon_url)
116
+ self._emoji_icon = None
117
+ self._external_icon_url = (
118
+ entity_response.icon.external.url if entity_response.icon and entity_response.icon.external else None
119
+ )
120
+
121
+ async def remove_icon(self) -> None:
122
+ await self._entity_metadata_update_client.remove_icon()
123
+ self._emoji_icon = None
124
+ self._external_icon_url = None
125
+
126
+ async def set_cover_image_by_url(self, image_url: str) -> None:
127
+ entity_response = await self._entity_metadata_update_client.patch_external_cover(image_url)
128
+ self._cover_image_url = (
129
+ entity_response.cover.external.url if entity_response.cover and entity_response.cover.external else None
130
+ )
131
+
132
+ async def set_random_gradient_cover(self) -> None:
133
+ random_cover_url = self._get_random_gradient_cover()
134
+ await self.set_cover_image_by_url(random_cover_url)
135
+
136
+ async def remove_cover_image(self) -> None:
137
+ await self._entity_metadata_update_client.remove_cover()
138
+ self._cover_image_url = None
139
+
140
+ async def move_to_trash(self) -> None:
141
+ if self._in_trash:
142
+ self.logger.warning("Entity is already in trash.")
143
+ return
144
+
145
+ entity_response = await self._entity_metadata_update_client.move_to_trash()
146
+ self._in_trash = entity_response.in_trash
147
+
148
+ async def restore_from_trash(self) -> None:
149
+ if not self._in_trash:
150
+ self.logger.warning("Entity is not in trash.")
151
+ return
152
+
153
+ entity_response = await self._entity_metadata_update_client.restore_from_trash()
154
+ self._in_trash = entity_response.in_trash
155
+
156
+ def __repr__(self) -> str:
157
+ attrs = []
158
+ for key, value in self.__dict__.items():
159
+ if key.startswith("_") and not key.startswith("__"):
160
+ attr_name = key[1:]
161
+ attrs.append(f"{attr_name}={value!r}")
162
+
163
+ attrs_str = ", ".join(attrs)
164
+ return f"{self.__class__.__name__}({attrs_str})"
165
+
166
+ def _get_random_gradient_cover(self) -> str:
167
+ DEFAULT_NOTION_COVERS: Sequence[str] = [
168
+ f"https://www.notion.so/images/page-cover/gradients_{i}.png" for i in range(1, 10)
169
+ ]
170
+
171
+ return random.choice(DEFAULT_NOTION_COVERS)
@@ -0,0 +1,20 @@
1
+ from enum import StrEnum
2
+ from typing import Literal, Self
3
+
4
+ from pydantic import BaseModel
5
+
6
+ from notionary.shared.models.file import ExternalFile
7
+
8
+
9
+ class CoverType(StrEnum):
10
+ EXTERNAL = "external"
11
+ FILE = "file"
12
+
13
+
14
+ class NotionCover(BaseModel):
15
+ type: Literal[CoverType.EXTERNAL, CoverType.FILE] = CoverType.EXTERNAL
16
+ external: ExternalFile | None = None
17
+
18
+ @classmethod
19
+ def from_url(cls, url: str) -> Self:
20
+ return cls(external=ExternalFile(url=url))
@@ -0,0 +1,21 @@
1
+ from enum import StrEnum
2
+ from typing import Literal, Self
3
+
4
+ from pydantic import BaseModel
5
+
6
+
7
+ class FileType(StrEnum):
8
+ EXTERNAL = "external"
9
+
10
+
11
+ class ExternalFile(BaseModel):
12
+ url: str
13
+
14
+
15
+ class ExternalRessource(BaseModel):
16
+ type: Literal[FileType.EXTERNAL] = FileType.EXTERNAL
17
+ external: ExternalFile
18
+
19
+ @classmethod
20
+ def from_url(cls, url: str) -> Self:
21
+ return cls(external=ExternalFile(url=url))
@@ -0,0 +1,28 @@
1
+ from enum import StrEnum
2
+ from typing import Literal, Self
3
+
4
+ from pydantic import BaseModel
5
+
6
+ from notionary.shared.models.file import ExternalFile
7
+
8
+
9
+ class IconType(StrEnum):
10
+ EMOJI = "emoji"
11
+ EXTERNAL = "external"
12
+
13
+
14
+ class EmojiIcon(BaseModel):
15
+ type: Literal[IconType.EMOJI] = IconType.EMOJI
16
+ emoji: str
17
+
18
+
19
+ class ExternalIcon(BaseModel):
20
+ type: Literal[IconType.EXTERNAL] = IconType.EXTERNAL
21
+ external: ExternalFile
22
+
23
+ @classmethod
24
+ def from_url(cls, url: str) -> Self:
25
+ return cls(external=ExternalFile(url=url))
26
+
27
+
28
+ Icon = EmojiIcon | ExternalIcon
@@ -0,0 +1,41 @@
1
+ from enum import StrEnum
2
+ from typing import Literal
3
+
4
+ from pydantic import BaseModel
5
+
6
+
7
+ class ParentType(StrEnum):
8
+ DATABASE_ID = "database_id"
9
+ DATA_SOURCE_ID = "data_source_id"
10
+ PAGE_ID = "page_id"
11
+ BLOCK_ID = "block_id"
12
+ WORKSPACE = "workspace"
13
+
14
+
15
+ class DataSourceParent(BaseModel):
16
+ type: Literal[ParentType.DATA_SOURCE_ID]
17
+ data_source_id: str
18
+ database_id: str
19
+
20
+
21
+ class PageParent(BaseModel):
22
+ type: Literal[ParentType.PAGE_ID]
23
+ page_id: str
24
+
25
+
26
+ class BlockParent(BaseModel):
27
+ type: Literal[ParentType.BLOCK_ID]
28
+ block_id: str
29
+
30
+
31
+ class WorkspaceParent(BaseModel):
32
+ type: Literal[ParentType.WORKSPACE]
33
+ workspace: bool
34
+
35
+
36
+ class DatabaseParent(BaseModel):
37
+ type: Literal[ParentType.DATABASE_ID]
38
+ database_id: str
39
+
40
+
41
+ Parent = DataSourceParent | PageParent | BlockParent | WorkspaceParent | DatabaseParent