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,393 @@
1
+ import re
2
+
3
+ from notionary.page.content.syntax.grammar import MarkdownGrammar
4
+ from notionary.page.content.syntax.models import SyntaxDefinition, SyntaxRegistryKey
5
+
6
+
7
+ class SyntaxRegistry:
8
+ def __init__(self, markdown_markdown_grammar: MarkdownGrammar | None = None) -> None:
9
+ self._markdown_grammar = markdown_markdown_grammar or MarkdownGrammar()
10
+
11
+ self._definitions: dict[SyntaxRegistryKey, SyntaxDefinition] = {}
12
+ self._register_defaults()
13
+
14
+ def get_audio_syntax(self) -> SyntaxDefinition:
15
+ return self._definitions[SyntaxRegistryKey.AUDIO]
16
+
17
+ def get_bookmark_syntax(self) -> SyntaxDefinition:
18
+ return self._definitions[SyntaxRegistryKey.BOOKMARK]
19
+
20
+ def get_breadcrumb_syntax(self) -> SyntaxDefinition:
21
+ return self._definitions[SyntaxRegistryKey.BREADCRUMB]
22
+
23
+ def get_bulleted_list_syntax(self) -> SyntaxDefinition:
24
+ return self._definitions[SyntaxRegistryKey.BULLETED_LIST]
25
+
26
+ def get_callout_syntax(self) -> SyntaxDefinition:
27
+ return self._definitions[SyntaxRegistryKey.CALLOUT]
28
+
29
+ def get_code_syntax(self) -> SyntaxDefinition:
30
+ return self._definitions[SyntaxRegistryKey.CODE]
31
+
32
+ def get_column_syntax(self) -> SyntaxDefinition:
33
+ return self._definitions[SyntaxRegistryKey.COLUMN]
34
+
35
+ def get_column_list_syntax(self) -> SyntaxDefinition:
36
+ return self._definitions[SyntaxRegistryKey.COLUMN_LIST]
37
+
38
+ def get_divider_syntax(self) -> SyntaxDefinition:
39
+ return self._definitions[SyntaxRegistryKey.DIVIDER]
40
+
41
+ def get_embed_syntax(self) -> SyntaxDefinition:
42
+ return self._definitions[SyntaxRegistryKey.EMBED]
43
+
44
+ def get_equation_syntax(self) -> SyntaxDefinition:
45
+ return self._definitions[SyntaxRegistryKey.EQUATION]
46
+
47
+ def get_file_syntax(self) -> SyntaxDefinition:
48
+ return self._definitions[SyntaxRegistryKey.FILE]
49
+
50
+ def get_image_syntax(self) -> SyntaxDefinition:
51
+ return self._definitions[SyntaxRegistryKey.IMAGE]
52
+
53
+ def get_numbered_list_syntax(self) -> SyntaxDefinition:
54
+ return self._definitions[SyntaxRegistryKey.NUMBERED_LIST]
55
+
56
+ def get_pdf_syntax(self) -> SyntaxDefinition:
57
+ return self._definitions[SyntaxRegistryKey.PDF]
58
+
59
+ def get_quote_syntax(self) -> SyntaxDefinition:
60
+ return self._definitions[SyntaxRegistryKey.QUOTE]
61
+
62
+ def get_table_syntax(self) -> SyntaxDefinition:
63
+ return self._definitions[SyntaxRegistryKey.TABLE]
64
+
65
+ def get_table_row_syntax(self) -> SyntaxDefinition:
66
+ return self._definitions[SyntaxRegistryKey.TABLE_ROW]
67
+
68
+ def get_table_of_contents_syntax(self) -> SyntaxDefinition:
69
+ return self._definitions[SyntaxRegistryKey.TABLE_OF_CONTENTS]
70
+
71
+ def get_todo_syntax(self) -> SyntaxDefinition:
72
+ return self._definitions[SyntaxRegistryKey.TO_DO]
73
+
74
+ def get_todo_done_syntax(self) -> SyntaxDefinition:
75
+ return self._definitions[SyntaxRegistryKey.TO_DO_DONE]
76
+
77
+ def get_toggle_syntax(self) -> SyntaxDefinition:
78
+ return self._definitions[SyntaxRegistryKey.TOGGLE]
79
+
80
+ def get_toggleable_heading_syntax(self) -> SyntaxDefinition:
81
+ return self._definitions[SyntaxRegistryKey.TOGGLEABLE_HEADING]
82
+
83
+ def get_video_syntax(self) -> SyntaxDefinition:
84
+ return self._definitions[SyntaxRegistryKey.VIDEO]
85
+
86
+ def get_caption_syntax(self) -> SyntaxDefinition:
87
+ return self._definitions[SyntaxRegistryKey.CAPTION]
88
+
89
+ def get_space_syntax(self) -> SyntaxDefinition:
90
+ return self._definitions[SyntaxRegistryKey.SPACE]
91
+
92
+ def get_heading_syntax(self) -> SyntaxDefinition:
93
+ return self._definitions[SyntaxRegistryKey.HEADING]
94
+
95
+ def _register_defaults(self) -> None:
96
+ self._register_audio_syntax()
97
+ self._register_bookmark_syntax()
98
+ self._register_image_syntax()
99
+ self._register_video_syntax()
100
+ self._register_file_syntax()
101
+ self._register_pdf_syntax()
102
+
103
+ # List blocks
104
+ self._register_bulleted_list_syntax()
105
+ self._register_numbered_list_syntax()
106
+ self._register_todo_syntax()
107
+ self._register_todo_done_syntax()
108
+
109
+ # Container blocks
110
+ self._register_toggle_syntax()
111
+ self._register_toggleable_heading_syntax()
112
+ self._register_callout_syntax()
113
+ self._register_quote_syntax()
114
+ self._register_code_syntax()
115
+
116
+ # Column layout blocks
117
+ self._register_column_list_syntax()
118
+ self._register_column_syntax()
119
+
120
+ self._register_heading_1_syntax()
121
+ self._register_heading_2_syntax()
122
+ self._register_heading_3_syntax()
123
+ self._register_heading_syntax() # Shared pattern for regular headings
124
+
125
+ self._register_divider_syntax()
126
+ self._register_breadcrumb_syntax()
127
+ self._register_table_of_contents_syntax()
128
+ self._register_equation_syntax()
129
+ self._register_embed_syntax()
130
+ self._register_table_syntax()
131
+ self._register_table_row_syntax()
132
+
133
+ # Post-processing and utility blocks
134
+ self._register_caption_syntax()
135
+ self._register_space_syntax()
136
+
137
+ def _register_audio_syntax(self) -> None:
138
+ definition = SyntaxDefinition(
139
+ start_delimiter="[audio](",
140
+ end_delimiter=")",
141
+ regex_pattern=re.compile(r"\[audio\]\(([^)]+)\)"),
142
+ )
143
+ self._definitions[SyntaxRegistryKey.AUDIO] = definition
144
+
145
+ def _register_bookmark_syntax(self) -> None:
146
+ definition = SyntaxDefinition(
147
+ start_delimiter="[bookmark](",
148
+ end_delimiter=")",
149
+ regex_pattern=re.compile(r"\[bookmark\]\((https?://[^\s\"]+)\)"),
150
+ )
151
+ self._definitions[SyntaxRegistryKey.BOOKMARK] = definition
152
+
153
+ def _register_breadcrumb_syntax(self) -> None:
154
+ definition = SyntaxDefinition(
155
+ start_delimiter="[breadcrumb]",
156
+ end_delimiter="",
157
+ regex_pattern=re.compile(r"^\[breadcrumb\]\s*$", re.IGNORECASE),
158
+ )
159
+ self._definitions[SyntaxRegistryKey.BREADCRUMB] = definition
160
+
161
+ def _register_bulleted_list_syntax(self) -> None:
162
+ definition = SyntaxDefinition(
163
+ start_delimiter="- ",
164
+ end_delimiter="",
165
+ regex_pattern=re.compile(r"^(\s*)-\s+(?!\[[ xX]\])(.+)$"),
166
+ )
167
+ self._definitions[SyntaxRegistryKey.BULLETED_LIST] = definition
168
+
169
+ def _register_callout_syntax(self) -> None:
170
+ definition = SyntaxDefinition(
171
+ start_delimiter="[callout]",
172
+ end_delimiter=")",
173
+ regex_pattern=re.compile(
174
+ r'\[callout\](?:\(([^")]+?)(?:\s+"([^"]+)")?\)|(?:\s+([^"\n]+?)(?:\s+"([^"]+)")?)(?:\n|$))'
175
+ ),
176
+ )
177
+ self._definitions[SyntaxRegistryKey.CALLOUT] = definition
178
+
179
+ def _register_code_syntax(self) -> None:
180
+ code_delimiter = "```"
181
+ definition = SyntaxDefinition(
182
+ start_delimiter=code_delimiter,
183
+ end_delimiter=code_delimiter,
184
+ regex_pattern=re.compile("^" + re.escape(code_delimiter) + r"(\w*)\s*$"),
185
+ end_regex_pattern=re.compile("^" + re.escape(code_delimiter) + r"\s*$"),
186
+ )
187
+ self._definitions[SyntaxRegistryKey.CODE] = definition
188
+
189
+ def _register_column_syntax(self) -> None:
190
+ delimiter = self._markdown_grammar.column_delimiter
191
+ definition = SyntaxDefinition(
192
+ start_delimiter=f"{delimiter} column",
193
+ end_delimiter=delimiter,
194
+ regex_pattern=re.compile(
195
+ rf"^{re.escape(delimiter)}\s*column(?:\s+(0?\.\d+|1(?:\.0?)?))??\s*$",
196
+ re.IGNORECASE | re.MULTILINE,
197
+ ),
198
+ end_regex_pattern=re.compile(rf"^{re.escape(delimiter)}\s*$", re.MULTILINE),
199
+ )
200
+ self._definitions[SyntaxRegistryKey.COLUMN] = definition
201
+
202
+ def _register_column_list_syntax(self) -> None:
203
+ delimiter = self._markdown_grammar.column_delimiter
204
+ definition = SyntaxDefinition(
205
+ start_delimiter=f"{delimiter} columns",
206
+ end_delimiter=delimiter,
207
+ regex_pattern=re.compile(rf"^{re.escape(delimiter)}\s*columns?\s*$", re.IGNORECASE),
208
+ end_regex_pattern=re.compile(rf"^{re.escape(delimiter)}\s*$"),
209
+ )
210
+ self._definitions[SyntaxRegistryKey.COLUMN_LIST] = definition
211
+
212
+ def _register_divider_syntax(self) -> None:
213
+ definition = SyntaxDefinition(
214
+ start_delimiter="---",
215
+ end_delimiter="",
216
+ regex_pattern=re.compile(r"^\s*-{3,}\s*$"),
217
+ )
218
+ self._definitions[SyntaxRegistryKey.DIVIDER] = definition
219
+
220
+ def _register_embed_syntax(self) -> None:
221
+ definition = SyntaxDefinition(
222
+ start_delimiter="[embed](",
223
+ end_delimiter=")",
224
+ regex_pattern=re.compile(r"\[embed\]\((https?://[^\s)]+)\)"),
225
+ )
226
+ self._definitions[SyntaxRegistryKey.EMBED] = definition
227
+
228
+ def _register_equation_syntax(self) -> None:
229
+ definition = SyntaxDefinition(
230
+ start_delimiter="$$",
231
+ end_delimiter="$$",
232
+ regex_pattern=re.compile(r"^\$\$\s*$"),
233
+ )
234
+ self._definitions[SyntaxRegistryKey.EQUATION] = definition
235
+
236
+ def _register_file_syntax(self) -> None:
237
+ definition = SyntaxDefinition(
238
+ start_delimiter="[file](",
239
+ end_delimiter=")",
240
+ regex_pattern=re.compile(r"\[file\]\(([^)]+)\)"),
241
+ )
242
+ self._definitions[SyntaxRegistryKey.FILE] = definition
243
+
244
+ def _register_heading_1_syntax(self) -> None:
245
+ definition = SyntaxDefinition(
246
+ start_delimiter="# ",
247
+ end_delimiter="",
248
+ regex_pattern=re.compile(r"^#\s+(.+)$"),
249
+ )
250
+ self._definitions[SyntaxRegistryKey.HEADING_1] = definition
251
+
252
+ def _register_heading_2_syntax(self) -> None:
253
+ definition = SyntaxDefinition(
254
+ start_delimiter="## ",
255
+ end_delimiter="",
256
+ regex_pattern=re.compile(r"^#{2}\s+(.+)$"),
257
+ )
258
+ self._definitions[SyntaxRegistryKey.HEADING_2] = definition
259
+
260
+ def _register_heading_3_syntax(self) -> None:
261
+ definition = SyntaxDefinition(
262
+ start_delimiter="### ",
263
+ end_delimiter="",
264
+ regex_pattern=re.compile(r"^#{3}\s+(.+)$"),
265
+ )
266
+ self._definitions[SyntaxRegistryKey.HEADING_3] = definition
267
+
268
+ def _register_image_syntax(self) -> None:
269
+ definition = SyntaxDefinition(
270
+ start_delimiter="[image](",
271
+ end_delimiter=")",
272
+ regex_pattern=re.compile(r"(?<!!)\[image\]\(([^)]+)\)"),
273
+ )
274
+ self._definitions[SyntaxRegistryKey.IMAGE] = definition
275
+
276
+ def _register_numbered_list_syntax(self) -> None:
277
+ definition = SyntaxDefinition(
278
+ start_delimiter="1. ",
279
+ end_delimiter="",
280
+ regex_pattern=re.compile(r"^(\s*)(\d+)\.\s+(.+)$"),
281
+ )
282
+ self._definitions[SyntaxRegistryKey.NUMBERED_LIST] = definition
283
+
284
+ def _register_pdf_syntax(self) -> None:
285
+ definition = SyntaxDefinition(
286
+ start_delimiter="[pdf](",
287
+ end_delimiter=")",
288
+ regex_pattern=re.compile(r"\[pdf\]\(([^)]+)\)"),
289
+ )
290
+ self._definitions[SyntaxRegistryKey.PDF] = definition
291
+
292
+ def _register_quote_syntax(self) -> None:
293
+ definition = SyntaxDefinition(
294
+ start_delimiter="> ",
295
+ end_delimiter="",
296
+ regex_pattern=re.compile(r"^>(?!>)\s*(.+)$"),
297
+ )
298
+ self._definitions[SyntaxRegistryKey.QUOTE] = definition
299
+
300
+ def _register_table_syntax(self) -> None:
301
+ delimiter = self._markdown_grammar.table_delimiter
302
+ definition = SyntaxDefinition(
303
+ start_delimiter=delimiter,
304
+ end_delimiter="",
305
+ regex_pattern=re.compile(rf"^\s*{re.escape(delimiter)}(.+){re.escape(delimiter)}\s*$"),
306
+ )
307
+ self._definitions[SyntaxRegistryKey.TABLE] = definition
308
+
309
+ def _register_table_row_syntax(self) -> None:
310
+ delimiter = self._markdown_grammar.table_delimiter
311
+ definition = SyntaxDefinition(
312
+ start_delimiter=delimiter,
313
+ end_delimiter="",
314
+ regex_pattern=re.compile(rf"^\s*{re.escape(delimiter)}([\s\-:|]+){re.escape(delimiter)}\s*$"),
315
+ )
316
+ self._definitions[SyntaxRegistryKey.TABLE_ROW] = definition
317
+
318
+ def _register_table_of_contents_syntax(self) -> None:
319
+ definition = SyntaxDefinition(
320
+ start_delimiter="[toc]",
321
+ end_delimiter="",
322
+ regex_pattern=re.compile(r"^\[toc\]$", re.IGNORECASE),
323
+ )
324
+ self._definitions[SyntaxRegistryKey.TABLE_OF_CONTENTS] = definition
325
+
326
+ def _register_todo_syntax(self) -> None:
327
+ definition = SyntaxDefinition(
328
+ start_delimiter="- [ ]",
329
+ end_delimiter="",
330
+ regex_pattern=re.compile(r"^\s*-\s+\[ \]\s+(.+)$"),
331
+ )
332
+ self._definitions[SyntaxRegistryKey.TO_DO] = definition
333
+
334
+ def _register_todo_done_syntax(self) -> None:
335
+ definition = SyntaxDefinition(
336
+ start_delimiter="- [x]",
337
+ end_delimiter="",
338
+ regex_pattern=re.compile(r"^\s*-\s+\[x\]\s+(.+)$", re.IGNORECASE),
339
+ )
340
+ self._definitions[SyntaxRegistryKey.TO_DO_DONE] = definition
341
+
342
+ def _register_toggle_syntax(self) -> None:
343
+ delimiter = self._markdown_grammar.toggle_delimiter
344
+ definition = SyntaxDefinition(
345
+ start_delimiter=delimiter,
346
+ end_delimiter=delimiter,
347
+ regex_pattern=re.compile(rf"^{re.escape(delimiter)}\s+(.+)$"),
348
+ end_regex_pattern=re.compile(rf"^{re.escape(delimiter)}\s*$"),
349
+ )
350
+ self._definitions[SyntaxRegistryKey.TOGGLE] = definition
351
+
352
+ def _register_toggleable_heading_syntax(self) -> None:
353
+ delimiter = self._markdown_grammar.toggle_delimiter
354
+ escaped_delimiter = re.escape(delimiter)
355
+ definition = SyntaxDefinition(
356
+ start_delimiter=f"{delimiter} #",
357
+ end_delimiter=delimiter,
358
+ regex_pattern=re.compile(rf"^{escaped_delimiter}\s*(?P<level>#{{1,3}})(?!#)\s*(.+)$", re.IGNORECASE),
359
+ end_regex_pattern=re.compile(rf"^{escaped_delimiter}\s*$"),
360
+ )
361
+ self._definitions[SyntaxRegistryKey.TOGGLEABLE_HEADING] = definition
362
+
363
+ def _register_video_syntax(self) -> None:
364
+ definition = SyntaxDefinition(
365
+ start_delimiter="[video](",
366
+ end_delimiter=")",
367
+ regex_pattern=re.compile(r"\[video\]\(([^)]+)\)"),
368
+ )
369
+ self._definitions[SyntaxRegistryKey.VIDEO] = definition
370
+
371
+ def _register_caption_syntax(self) -> None:
372
+ definition = SyntaxDefinition(
373
+ start_delimiter="[caption]",
374
+ end_delimiter="",
375
+ regex_pattern=re.compile(r"^\[caption\]\s+(\S.*)$"),
376
+ )
377
+ self._definitions[SyntaxRegistryKey.CAPTION] = definition
378
+
379
+ def _register_space_syntax(self) -> None:
380
+ definition = SyntaxDefinition(
381
+ start_delimiter="[space]",
382
+ end_delimiter="",
383
+ regex_pattern=re.compile(r"^\[space\]\s*$"),
384
+ )
385
+ self._definitions[SyntaxRegistryKey.SPACE] = definition
386
+
387
+ def _register_heading_syntax(self) -> None:
388
+ definition = SyntaxDefinition(
389
+ start_delimiter="#",
390
+ end_delimiter="",
391
+ regex_pattern=re.compile(r"^(#{1,3})[ \t]+(.+)$"),
392
+ )
393
+ self._definitions[SyntaxRegistryKey.HEADING] = definition
@@ -1,12 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Optional
4
- from dataclasses import dataclass
5
3
  from contextvars import ContextVar
4
+ from dataclasses import dataclass
5
+ from typing import TYPE_CHECKING
6
6
 
7
7
  if TYPE_CHECKING:
8
- from notionary.database.client import NotionDatabaseClient
9
- from notionary.file_upload import NotionFileUploadClient
8
+ from notionary.file_upload import FileUploadHttpClient
10
9
 
11
10
 
12
11
  @dataclass(frozen=True)
@@ -14,35 +13,27 @@ class PageContextProvider:
14
13
  """Context object that provides dependencies for block conversion operations."""
15
14
 
16
15
  page_id: str
17
- database_client: NotionDatabaseClient
18
- file_upload_client: NotionFileUploadClient
16
+ file_upload_client: FileUploadHttpClient
19
17
 
20
18
 
21
19
  # Context variable
22
- _page_context: ContextVar[Optional[PageContextProvider]] = ContextVar(
23
- "page_context", default=None
24
- )
20
+ _page_context: ContextVar[PageContextProvider | None] = ContextVar("page_context", default=None)
25
21
 
26
22
 
27
23
  def get_page_context() -> PageContextProvider:
28
24
  """Get current page context or raise if not available."""
29
25
  context = _page_context.get()
30
26
  if context is None:
31
- raise RuntimeError(
32
- "No page context available. Use 'async with page_context(...)'"
33
- )
27
+ raise RuntimeError("No page context available. Use 'async with page_context(...)'")
34
28
  return context
35
29
 
36
30
 
37
31
  class page_context:
38
- """Async-only context manager for page operations."""
39
-
40
- def __init__(self, provider: PageContextProvider):
32
+ def __init__(self, provider: PageContextProvider) -> None:
41
33
  self.provider = provider
42
34
  self._token = None
43
35
 
44
36
  def _set_context(self) -> PageContextProvider:
45
- """Helper to set context and return provider."""
46
37
  self._token = _page_context.set(self.provider)
47
38
  return self.provider
48
39
 
@@ -0,0 +1,15 @@
1
+ from notionary.http.client import NotionHttpClient
2
+ from notionary.page.schemas import NotionPageDto
3
+
4
+
5
+ class NotionPageHttpClient(NotionHttpClient):
6
+ def __init__(
7
+ self,
8
+ page_id: str,
9
+ ):
10
+ super().__init__()
11
+ self._page_id = page_id
12
+
13
+ async def get_page(self) -> NotionPageDto:
14
+ response = await self.get(f"pages/{self._page_id}")
15
+ return NotionPageDto.model_validate(response)
@@ -0,0 +1,19 @@
1
+ from typing import override
2
+
3
+ from notionary.http.client import NotionHttpClient
4
+ from notionary.page.schemas import NotionPageDto
5
+ from notionary.shared.entity.entity_metadata_update_client import EntityMetadataUpdateClient
6
+ from notionary.shared.entity.schemas import NotionEntityUpdateDto
7
+
8
+
9
+ class PageMetadataUpdateClient(NotionHttpClient, EntityMetadataUpdateClient):
10
+ def __init__(self, page_id: str, timeout: int = 30) -> None:
11
+ super().__init__(timeout)
12
+ self._page_id = page_id
13
+
14
+ @override
15
+ async def patch_metadata(self, updated_data: NotionEntityUpdateDto) -> NotionPageDto:
16
+ updated_data_dict = updated_data.model_dump(exclude_unset=True, exclude_none=True)
17
+
18
+ response_dict = await self.patch(f"pages/{self._page_id}", data=updated_data_dict)
19
+ return NotionPageDto.model_validate(response_dict)
@@ -0,0 +1,144 @@
1
+ from typing import Any
2
+
3
+ from pydantic import BaseModel
4
+
5
+ from notionary.blocks.rich_text.models import RichText
6
+ from notionary.http.client import NotionHttpClient
7
+ from notionary.page.properties.models import (
8
+ DateValue,
9
+ PageCheckboxProperty,
10
+ PageDateProperty,
11
+ PageEmailProperty,
12
+ PageMultiSelectProperty,
13
+ PageNumberProperty,
14
+ PagePhoneNumberProperty,
15
+ PagePropertyT,
16
+ PageRelationProperty,
17
+ PageRichTextProperty,
18
+ PageSelectProperty,
19
+ PageStatusProperty,
20
+ PageTitleProperty,
21
+ PageURLProperty,
22
+ RelationItem,
23
+ SelectOption,
24
+ StatusOption,
25
+ )
26
+ from notionary.page.schemas import NotionPageDto, PgePropertiesUpdateDto
27
+
28
+
29
+ class PagePropertyHttpClient(NotionHttpClient):
30
+ def __init__(self, page_id: str) -> None:
31
+ super().__init__()
32
+ self._page_id = page_id
33
+
34
+ async def patch_page(self, data: BaseModel) -> NotionPageDto:
35
+ data_dict = data.model_dump(exclude_unset=True, exclude_none=True)
36
+
37
+ result_dict = await self.patch(f"pages/{self._page_id}", data=data_dict)
38
+ return NotionPageDto.model_validate(result_dict)
39
+
40
+ async def _patch_property(
41
+ self,
42
+ property_name: str,
43
+ value: Any,
44
+ property_type: type[PagePropertyT],
45
+ current_property: PagePropertyT | None = None,
46
+ ) -> NotionPageDto:
47
+ updated_property = self._create_updated_property(property_type, current_property, value)
48
+
49
+ properties = {property_name: updated_property}
50
+ update_dto = PgePropertiesUpdateDto(properties=properties)
51
+
52
+ return await self.patch_page(update_dto)
53
+
54
+ async def patch_title(self, title: str) -> NotionPageDto:
55
+ return await self._patch_property("title", title, PageTitleProperty)
56
+
57
+ async def patch_rich_text_property(self, property_name: str, text: str) -> NotionPageDto:
58
+ return await self._patch_property(property_name, text, PageRichTextProperty)
59
+
60
+ async def patch_url_property(self, property_name: str, url: str) -> NotionPageDto:
61
+ return await self._patch_property(property_name, url, PageURLProperty)
62
+
63
+ async def patch_email_property(self, property_name: str, email: str) -> NotionPageDto:
64
+ return await self._patch_property(property_name, email, PageEmailProperty)
65
+
66
+ async def patch_phone_property(self, property_name: str, phone: str) -> NotionPageDto:
67
+ return await self._patch_property(property_name, phone, PagePhoneNumberProperty)
68
+
69
+ async def patch_number_property(self, property_name: str, number: int | float) -> NotionPageDto:
70
+ return await self._patch_property(property_name, number, PageNumberProperty)
71
+
72
+ async def patch_checkbox_property(self, property_name: str, checked: bool) -> NotionPageDto:
73
+ return await self._patch_property(property_name, checked, PageCheckboxProperty)
74
+
75
+ async def patch_select_property(self, property_name: str, value: str) -> NotionPageDto:
76
+ return await self._patch_property(property_name, value, PageSelectProperty)
77
+
78
+ async def patch_multi_select_property(self, property_name: str, values: list[str]) -> NotionPageDto:
79
+ return await self._patch_property(property_name, values, PageMultiSelectProperty)
80
+
81
+ async def patch_date_property(self, property_name: str, date_value: str | dict) -> NotionPageDto:
82
+ return await self._patch_property(property_name, date_value, PageDateProperty)
83
+
84
+ async def patch_status_property(self, property_name: str, status: str) -> NotionPageDto:
85
+ return await self._patch_property(property_name, status, PageStatusProperty)
86
+
87
+ async def patch_relation_property(self, property_name: str, relation_ids: str | list[str]) -> NotionPageDto:
88
+ if isinstance(relation_ids, str):
89
+ relation_ids = [relation_ids]
90
+ return await self._patch_property(property_name, relation_ids, PageRelationProperty)
91
+
92
+ # TODO: Fix this shit here
93
+ def _create_updated_property(
94
+ self,
95
+ property_type: type[PagePropertyT],
96
+ current_property: PagePropertyT | None,
97
+ value: Any,
98
+ ) -> PagePropertyT:
99
+ """
100
+ Creates an updated property instance based on the property type and new value.
101
+ """
102
+ # Get the property ID from the current property if it exists
103
+ property_id = current_property.id if current_property else ""
104
+
105
+ if property_type == PageTitleProperty:
106
+ return PageTitleProperty(
107
+ id=property_id,
108
+ title=[RichText(type="text", text={"content": str(value)})],
109
+ )
110
+ elif property_type == PageRichTextProperty:
111
+ return PageRichTextProperty(
112
+ id=property_id,
113
+ rich_text=[RichText(type="text", text={"content": str(value)})],
114
+ )
115
+ elif property_type == PageURLProperty:
116
+ return PageURLProperty(id=property_id, url=str(value))
117
+ elif property_type == PageEmailProperty:
118
+ return PageEmailProperty(id=property_id, email=str(value))
119
+ elif property_type == PagePhoneNumberProperty:
120
+ return PagePhoneNumberProperty(id=property_id, phone_number=str(value))
121
+ elif property_type == PageNumberProperty:
122
+ return PageNumberProperty(id=property_id, number=float(value))
123
+ elif property_type == PageCheckboxProperty:
124
+ return PageCheckboxProperty(id=property_id, checkbox=bool(value))
125
+ elif property_type == PageSelectProperty:
126
+ select_option = SelectOption(name=str(value))
127
+ return PageSelectProperty(id=property_id, select=select_option)
128
+ elif property_type == PageMultiSelectProperty:
129
+ multi_select_options = [SelectOption(id="", name=str(item)) for item in value]
130
+ return PageMultiSelectProperty(id=property_id, multi_select=multi_select_options)
131
+ elif property_type == PageDateProperty:
132
+ if isinstance(value, dict) and "start" in value:
133
+ date_value = DateValue(**value)
134
+ else:
135
+ date_value = DateValue(start=str(value))
136
+ return PageDateProperty(id=property_id, date=date_value)
137
+ elif property_type == PageStatusProperty:
138
+ status_option = StatusOption(id="", name=str(value))
139
+ return PageStatusProperty(id=property_id, status=status_option)
140
+ elif property_type == PageRelationProperty:
141
+ relation_items = [RelationItem(id=str(item)) for item in value]
142
+ return PageRelationProperty(id=property_id, relation=relation_items)
143
+ else:
144
+ raise ValueError(f"Unsupported property type: {property_type}")
@@ -0,0 +1,26 @@
1
+ from typing import cast
2
+
3
+ from notionary.page.properties.client import PagePropertyHttpClient
4
+ from notionary.page.properties.service import PagePropertyHandler
5
+ from notionary.page.schemas import NotionPageDto
6
+ from notionary.shared.models.parent import DataSourceParent, ParentType
7
+
8
+
9
+ class PagePropertyHandlerFactory:
10
+ def create_from_page_response(self, page_response: NotionPageDto) -> PagePropertyHandler:
11
+ return PagePropertyHandler(
12
+ properties=page_response.properties,
13
+ parent_type=page_response.parent.type,
14
+ page_url=page_response.url,
15
+ page_property_http_client=self._create_http_client(page_id=page_response.id),
16
+ parent_data_source=self._extract_parent_data_source_id(page_response),
17
+ )
18
+
19
+ def _create_http_client(self, page_id: str) -> PagePropertyHttpClient:
20
+ return PagePropertyHttpClient(page_id=page_id)
21
+
22
+ def _extract_parent_data_source_id(self, response: NotionPageDto) -> str | None:
23
+ if response.parent.type != ParentType.DATA_SOURCE_ID:
24
+ return None
25
+ data_source_parent = cast(DataSourceParent, response.parent)
26
+ return data_source_parent.data_source_id if data_source_parent else None