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,280 @@
1
+ import re
2
+ from collections.abc import Callable
3
+ from dataclasses import dataclass
4
+ from re import Match
5
+ from typing import ClassVar
6
+
7
+ from notionary.blocks.rich_text.models import MentionType, RichText, RichTextType, TextAnnotations
8
+ from notionary.blocks.rich_text.name_id_resolver import (
9
+ DatabaseNameIdResolver,
10
+ DataSourceNameIdResolver,
11
+ NameIdResolver,
12
+ PageNameIdResolver,
13
+ PersonNameIdResolver,
14
+ )
15
+ from notionary.blocks.rich_text.rich_text_patterns import RichTextPatterns
16
+ from notionary.blocks.schemas import BlockColor
17
+
18
+
19
+ @dataclass
20
+ class PatternMatch:
21
+ match: Match
22
+ handler: Callable[[Match], RichText | list[RichText]]
23
+ position: int
24
+
25
+ @property
26
+ def matched_text(self) -> str:
27
+ return self.match.group(0)
28
+
29
+ @property
30
+ def end_position(self) -> int:
31
+ return self.position + len(self.matched_text)
32
+
33
+
34
+ @dataclass
35
+ class PatternHandler:
36
+ pattern: str
37
+ handler: Callable[[Match], RichText | list[RichText]]
38
+
39
+
40
+ class MarkdownRichTextConverter:
41
+ VALID_COLORS: ClassVar[set[str]] = {color.value for color in BlockColor}
42
+
43
+ def __init__(
44
+ self,
45
+ *,
46
+ page_resolver: NameIdResolver | None = None,
47
+ database_resolver: NameIdResolver | None = None,
48
+ data_source_resolver: NameIdResolver | None = None,
49
+ person_resolver: NameIdResolver | None = None,
50
+ ):
51
+ self.page_resolver = page_resolver or PageNameIdResolver()
52
+ self.database_resolver = database_resolver or DatabaseNameIdResolver()
53
+ self.data_source_resolver = data_source_resolver or DataSourceNameIdResolver()
54
+ self.person_resolver = person_resolver or PersonNameIdResolver()
55
+ self.format_handlers = self._setup_format_handlers()
56
+
57
+ def _setup_format_handlers(self) -> list[PatternHandler]:
58
+ return [
59
+ PatternHandler(RichTextPatterns.BOLD, self._handle_bold_pattern),
60
+ PatternHandler(RichTextPatterns.ITALIC, self._handle_italic_pattern),
61
+ PatternHandler(RichTextPatterns.ITALIC_UNDERSCORE, self._handle_italic_pattern),
62
+ PatternHandler(RichTextPatterns.UNDERLINE, self._handle_underline_pattern),
63
+ PatternHandler(RichTextPatterns.STRIKETHROUGH, self._handle_strikethrough_pattern),
64
+ PatternHandler(RichTextPatterns.CODE, self._handle_code_pattern),
65
+ PatternHandler(RichTextPatterns.LINK, self._handle_link_pattern),
66
+ PatternHandler(RichTextPatterns.INLINE_EQUATION, self._handle_equation_pattern),
67
+ PatternHandler(RichTextPatterns.COLOR, self._handle_color_pattern),
68
+ PatternHandler(RichTextPatterns.PAGE_MENTION, self._handle_page_mention_pattern),
69
+ PatternHandler(RichTextPatterns.DATABASE_MENTION, self._handle_database_mention_pattern),
70
+ PatternHandler(RichTextPatterns.DATASOURCE_MENTION, self._handle_data_source_mention_pattern),
71
+ PatternHandler(RichTextPatterns.USER_MENTION, self._handle_user_mention_pattern),
72
+ ]
73
+
74
+ async def to_rich_text(self, text: str) -> list[RichText]:
75
+ if not text:
76
+ return []
77
+ return await self._split_text_into_segments(text)
78
+
79
+ async def _split_text_into_segments(self, text: str) -> list[RichText]:
80
+ segments: list[RichText] = []
81
+ remaining_text = text
82
+
83
+ while remaining_text:
84
+ pattern_match = self._find_earliest_pattern_match(remaining_text)
85
+
86
+ if not pattern_match:
87
+ segments.append(RichText.from_plain_text(remaining_text))
88
+ break
89
+
90
+ plain_text_before = remaining_text[: pattern_match.position]
91
+ if plain_text_before:
92
+ segments.append(RichText.from_plain_text(plain_text_before))
93
+
94
+ pattern_result = await self._process_pattern_match(pattern_match)
95
+ self._add_pattern_result_to_segments(segments, pattern_result)
96
+
97
+ remaining_text = remaining_text[pattern_match.end_position :]
98
+
99
+ return segments
100
+
101
+ def _find_earliest_pattern_match(self, text: str) -> PatternMatch | None:
102
+ """Find the pattern that appears earliest in the text."""
103
+ earliest_match = None
104
+ earliest_position = len(text)
105
+
106
+ for pattern_handler in self.format_handlers:
107
+ match = re.search(pattern_handler.pattern, text)
108
+ if match and match.start() < earliest_position:
109
+ earliest_match = PatternMatch(match=match, handler=pattern_handler.handler, position=match.start())
110
+ earliest_position = match.start()
111
+
112
+ return earliest_match
113
+
114
+ async def _process_pattern_match(self, pattern_match: PatternMatch) -> RichText | list[RichText]:
115
+ handler_method = pattern_match.handler
116
+
117
+ if self._is_async_handler(handler_method):
118
+ return await handler_method(pattern_match.match)
119
+ else:
120
+ return handler_method(pattern_match.match)
121
+
122
+ def _is_async_handler(self, handler_method: Callable) -> bool:
123
+ async_handlers = {
124
+ self._handle_page_mention_pattern,
125
+ self._handle_database_mention_pattern,
126
+ self._handle_data_source_mention_pattern,
127
+ self._handle_color_pattern, # Color pattern needs async for recursive parsing
128
+ self._handle_user_mention_pattern,
129
+ }
130
+ return handler_method in async_handlers
131
+
132
+ def _add_pattern_result_to_segments(
133
+ self, segments: list[RichText], pattern_result: RichText | list[RichText]
134
+ ) -> None:
135
+ if isinstance(pattern_result, list):
136
+ segments.extend(pattern_result)
137
+ elif pattern_result:
138
+ segments.append(pattern_result)
139
+
140
+ async def _handle_color_pattern(self, match: Match) -> list[RichText]:
141
+ color, content = match.group(1).lower(), match.group(2)
142
+
143
+ if color not in self.VALID_COLORS:
144
+ return [RichText.from_plain_text(f"({match.group(1)}:{content})")]
145
+
146
+ parsed_segments = await self._split_text_into_segments(content)
147
+
148
+ colored_segments = []
149
+ for segment in parsed_segments:
150
+ if segment.type == RichTextType.TEXT:
151
+ colored_segment = self._apply_color_to_text_segment(segment, color)
152
+ colored_segments.append(colored_segment)
153
+ else:
154
+ colored_segments.append(segment)
155
+
156
+ return colored_segments
157
+
158
+ def _apply_color_to_text_segment(self, segment: RichText, color: str) -> RichText:
159
+ if segment.type != RichTextType.TEXT:
160
+ return segment
161
+
162
+ has_link = segment.text and segment.text.link
163
+
164
+ if has_link:
165
+ return self._apply_color_to_link_segment(segment, color)
166
+ else:
167
+ return self._apply_color_to_plain_text_segment(segment, color)
168
+
169
+ def _apply_color_to_link_segment(self, segment: RichText, color: str) -> RichText:
170
+ formatting = self._extract_formatting_attributes(segment.annotations)
171
+
172
+ return RichText.for_link(segment.plain_text, segment.text.link.url, color=color, **formatting)
173
+
174
+ def _apply_color_to_plain_text_segment(self, segment: RichText, color: str) -> RichText:
175
+ if segment.type != RichTextType.TEXT:
176
+ return segment
177
+
178
+ formatting = self._extract_formatting_attributes(segment.annotations)
179
+
180
+ return RichText.from_plain_text(segment.plain_text, color=color, **formatting)
181
+
182
+ def _extract_formatting_attributes(self, annotations: TextAnnotations) -> dict[str, bool]:
183
+ if not annotations:
184
+ return {
185
+ "bold": False,
186
+ "italic": False,
187
+ "strikethrough": False,
188
+ "underline": False,
189
+ "code": False,
190
+ }
191
+
192
+ return {
193
+ "bold": annotations.bold,
194
+ "italic": annotations.italic,
195
+ "strikethrough": annotations.strikethrough,
196
+ "underline": annotations.underline,
197
+ "code": annotations.code,
198
+ }
199
+
200
+ async def _handle_page_mention_pattern(self, match: Match) -> RichText:
201
+ identifier = match.group(1)
202
+ return await self._create_mention_or_fallback(
203
+ identifier=identifier,
204
+ resolve_func=self.page_resolver.resolve_name_to_id,
205
+ create_mention_func=RichText.mention_page,
206
+ mention_type=MentionType.PAGE,
207
+ )
208
+
209
+ async def _handle_database_mention_pattern(self, match: Match) -> RichText:
210
+ identifier = match.group(1)
211
+ return await self._create_mention_or_fallback(
212
+ identifier=identifier,
213
+ resolve_func=self.database_resolver.resolve_name_to_id,
214
+ create_mention_func=RichText.mention_database,
215
+ mention_type=MentionType.DATABASE,
216
+ )
217
+
218
+ async def _handle_data_source_mention_pattern(self, match: Match) -> RichText:
219
+ identifier = match.group(1)
220
+ return await self._create_mention_or_fallback(
221
+ identifier=identifier,
222
+ resolve_func=self.data_source_resolver.resolve_name_to_id,
223
+ create_mention_func=RichText.mention_data_source,
224
+ mention_type=MentionType.DATASOURCE,
225
+ )
226
+
227
+ async def _handle_user_mention_pattern(self, match: Match) -> RichText:
228
+ identifier = match.group(1)
229
+ return await self._create_mention_or_fallback(
230
+ identifier=identifier,
231
+ resolve_func=self.person_resolver.resolve_name_to_id,
232
+ create_mention_func=RichText.mention_user,
233
+ mention_type=MentionType.USER,
234
+ )
235
+
236
+ async def _create_mention_or_fallback(
237
+ self,
238
+ identifier: str,
239
+ resolve_func: Callable[[str], str | None],
240
+ create_mention_func: Callable[[str], RichText],
241
+ mention_type: MentionType,
242
+ ) -> RichText:
243
+ try:
244
+ resolved_id = await resolve_func(identifier)
245
+
246
+ if resolved_id:
247
+ return create_mention_func(resolved_id)
248
+ else:
249
+ return self._create_unresolved_mention_fallback(identifier, mention_type)
250
+
251
+ except Exception:
252
+ # If resolution throws an error, fallback to plain text
253
+ return self._create_unresolved_mention_fallback(identifier, mention_type)
254
+
255
+ def _create_unresolved_mention_fallback(self, identifier: str, mention_type: MentionType) -> RichText:
256
+ fallback_text = f"@{mention_type.value}[{identifier}]"
257
+ return RichText.for_caption(fallback_text)
258
+
259
+ def _handle_bold_pattern(self, match: Match) -> RichText:
260
+ return RichText.from_plain_text(match.group(1), bold=True)
261
+
262
+ def _handle_italic_pattern(self, match: Match) -> RichText:
263
+ return RichText.from_plain_text(match.group(1), italic=True)
264
+
265
+ def _handle_underline_pattern(self, match: Match) -> RichText:
266
+ return RichText.from_plain_text(match.group(1), underline=True)
267
+
268
+ def _handle_strikethrough_pattern(self, match: Match) -> RichText:
269
+ return RichText.from_plain_text(match.group(1), strikethrough=True)
270
+
271
+ def _handle_code_pattern(self, match: Match) -> RichText:
272
+ return RichText.from_plain_text(match.group(1), code=True)
273
+
274
+ def _handle_link_pattern(self, match: Match) -> RichText:
275
+ link_text, url = match.group(1), match.group(2)
276
+ return RichText.for_link(link_text, url)
277
+
278
+ def _handle_equation_pattern(self, match: Match) -> RichText:
279
+ expression = match.group(1)
280
+ return RichText.equation_inline(expression)
@@ -0,0 +1,178 @@
1
+ from enum import StrEnum
2
+ from typing import Self
3
+
4
+ from pydantic import BaseModel
5
+
6
+ from notionary.blocks.enums import BlockColor
7
+
8
+
9
+ class RichTextType(StrEnum):
10
+ TEXT = "text"
11
+ MENTION = "mention"
12
+ EQUATION = "equation"
13
+
14
+
15
+ class MentionType(StrEnum):
16
+ USER = "user"
17
+ PAGE = "page"
18
+ DATABASE = "database"
19
+ DATASOURCE = "data_source"
20
+ DATE = "date"
21
+ LINK_PREVIEW = "link_preview"
22
+ TEMPLATE_MENTION = "template_mention"
23
+
24
+
25
+ class TemplateMentionType(StrEnum):
26
+ USER = "template_mention_user"
27
+ DATE = "template_mention_date"
28
+
29
+
30
+ class TextAnnotations(BaseModel):
31
+ bold: bool = False
32
+ italic: bool = False
33
+ strikethrough: bool = False
34
+ underline: bool = False
35
+ code: bool = False
36
+ color: BlockColor | None = None
37
+
38
+
39
+ class LinkObject(BaseModel):
40
+ url: str
41
+
42
+
43
+ class TextContent(BaseModel):
44
+ content: str
45
+ link: LinkObject | None = None
46
+
47
+
48
+ class EquationObject(BaseModel):
49
+ expression: str
50
+
51
+
52
+ class MentionUserRef(BaseModel):
53
+ id: str # Notion user id
54
+
55
+
56
+ class MentionPageRef(BaseModel):
57
+ id: str
58
+
59
+
60
+ class MentionDatabaseRef(BaseModel):
61
+ id: str
62
+
63
+
64
+ class MentionDataSourceRef(BaseModel):
65
+ id: str
66
+
67
+
68
+ class MentionLinkPreview(BaseModel):
69
+ url: str
70
+
71
+
72
+ class MentionDate(BaseModel):
73
+ # entspricht Notion date object (start Pflicht, end/time_zone optional)
74
+ start: str # ISO 8601 date or datetime
75
+ end: str | None = None
76
+ time_zone: str | None = None
77
+
78
+
79
+ class MentionTemplateMention(BaseModel):
80
+ # Notion hat zwei Template-Mention-Typen
81
+ type: TemplateMentionType
82
+
83
+
84
+ class MentionObject(BaseModel):
85
+ type: MentionType
86
+ user: MentionUserRef | None = None
87
+ page: MentionPageRef | None = None
88
+ database: MentionDatabaseRef | None = None
89
+ data_source: MentionDataSourceRef | None = None
90
+ date: MentionDate | None = None
91
+ link_preview: MentionLinkPreview | None = None
92
+ template_mention: MentionTemplateMention | None = None
93
+
94
+
95
+ class RichText(BaseModel):
96
+ type: RichTextType = RichTextType.TEXT
97
+
98
+ text: TextContent | None = None
99
+ annotations: TextAnnotations | None = None
100
+ plain_text: str = ""
101
+ href: str | None = None
102
+
103
+ mention: MentionObject | None = None
104
+
105
+ equation: EquationObject | None = None
106
+
107
+ @classmethod
108
+ def from_plain_text(cls, content: str, **ann) -> Self:
109
+ return cls(
110
+ type=RichTextType.TEXT,
111
+ text=TextContent(content=content),
112
+ annotations=TextAnnotations(**ann) if ann else TextAnnotations(),
113
+ plain_text=content,
114
+ )
115
+
116
+ @classmethod
117
+ def for_caption(cls, content: str) -> Self:
118
+ return cls(
119
+ type=RichTextType.TEXT,
120
+ text=TextContent(content=content),
121
+ annotations=None,
122
+ plain_text=content,
123
+ )
124
+
125
+ @classmethod
126
+ def for_code_block(cls, content: str) -> Self:
127
+ # keine annotations setzen → Notion Code-Highlight bleibt an
128
+ return cls.for_caption(content)
129
+
130
+ @classmethod
131
+ def for_link(cls, content: str, url: str, **ann) -> Self:
132
+ return cls(
133
+ type=RichTextType.TEXT,
134
+ text=TextContent(content=content, link=LinkObject(url=url)),
135
+ annotations=TextAnnotations(**ann) if ann else TextAnnotations(),
136
+ plain_text=content,
137
+ )
138
+
139
+ @classmethod
140
+ def mention_user(cls, user_id: str) -> Self:
141
+ return cls(
142
+ type=RichTextType.MENTION,
143
+ mention=MentionObject(type=MentionType.USER, user=MentionUserRef(id=user_id)),
144
+ annotations=TextAnnotations(),
145
+ )
146
+
147
+ @classmethod
148
+ def mention_page(cls, page_id: str) -> Self:
149
+ return cls(
150
+ type=RichTextType.MENTION,
151
+ mention=MentionObject(type=MentionType.PAGE, page=MentionPageRef(id=page_id)),
152
+ annotations=TextAnnotations(),
153
+ )
154
+
155
+ @classmethod
156
+ def mention_database(cls, database_id: str) -> Self:
157
+ return cls(
158
+ type=RichTextType.MENTION,
159
+ mention=MentionObject(type=MentionType.DATABASE, database=MentionDatabaseRef(id=database_id)),
160
+ annotations=TextAnnotations(),
161
+ )
162
+
163
+ @classmethod
164
+ def mention_data_source(cls, data_source_id: str) -> Self:
165
+ return cls(
166
+ type=RichTextType.MENTION,
167
+ mention=MentionObject(type=MentionType.DATASOURCE, data_source=MentionDataSourceRef(id=data_source_id)),
168
+ annotations=TextAnnotations(),
169
+ )
170
+
171
+ @classmethod
172
+ def equation_inline(cls, expression: str) -> Self:
173
+ return cls(
174
+ type=RichTextType.EQUATION,
175
+ equation=EquationObject(expression=expression),
176
+ annotations=TextAnnotations(),
177
+ plain_text=expression,
178
+ )
@@ -0,0 +1,13 @@
1
+ from .data_source import DataSourceNameIdResolver
2
+ from .database import DatabaseNameIdResolver
3
+ from .page import PageNameIdResolver
4
+ from .person import PersonNameIdResolver
5
+ from .port import NameIdResolver
6
+
7
+ __all__ = [
8
+ "DataSourceNameIdResolver",
9
+ "DatabaseNameIdResolver",
10
+ "NameIdResolver",
11
+ "PageNameIdResolver",
12
+ "PersonNameIdResolver",
13
+ ]
@@ -0,0 +1,32 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.rich_text.name_id_resolver.port import NameIdResolver
4
+ from notionary.workspace.query.service import WorkspaceQueryService
5
+
6
+
7
+ # !!! in the notion api mentions that reference datasources are not provided yet (it's a limiation of the API as of now)
8
+ class DataSourceNameIdResolver(NameIdResolver):
9
+ def __init__(self, workspace_query_service: WorkspaceQueryService | None = None) -> None:
10
+ self._workspace_query_service = workspace_query_service or WorkspaceQueryService()
11
+
12
+ @override
13
+ async def resolve_name_to_id(self, name: str) -> str | None:
14
+ if not name:
15
+ return None
16
+
17
+ cleaned_name = name.strip()
18
+ data_source = await self._workspace_query_service.find_data_source(query=cleaned_name)
19
+ return data_source.id if data_source else None
20
+
21
+ @override
22
+ async def resolve_id_to_name(self, data_source_id: str) -> str | None:
23
+ if not data_source_id:
24
+ return None
25
+
26
+ try:
27
+ from notionary import NotionDataSource
28
+
29
+ data_source = await NotionDataSource.from_id(data_source_id)
30
+ return data_source.title if data_source else None
31
+ except Exception:
32
+ return None
@@ -0,0 +1,31 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.rich_text.name_id_resolver.port import NameIdResolver
4
+ from notionary.workspace.query.service import WorkspaceQueryService
5
+
6
+
7
+ class DatabaseNameIdResolver(NameIdResolver):
8
+ def __init__(self, search_service: WorkspaceQueryService | None = None) -> None:
9
+ self.search_service = search_service or WorkspaceQueryService()
10
+
11
+ @override
12
+ async def resolve_name_to_id(self, name: str) -> str | None:
13
+ if not name:
14
+ return None
15
+
16
+ cleaned_name = name.strip()
17
+ database = await self.search_service.find_database(query=cleaned_name)
18
+ return database.id if database else None
19
+
20
+ @override
21
+ async def resolve_id_to_name(self, database_id: str) -> str | None:
22
+ if not database_id:
23
+ return None
24
+
25
+ try:
26
+ from notionary import NotionDatabase
27
+
28
+ database = await NotionDatabase.from_id(database_id)
29
+ return database.title if database else None
30
+ except Exception:
31
+ return None
@@ -0,0 +1,34 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.rich_text.name_id_resolver.port import NameIdResolver
4
+ from notionary.workspace.query.service import WorkspaceQueryService
5
+
6
+
7
+ class PageNameIdResolver(NameIdResolver):
8
+ def __init__(self, search_service: WorkspaceQueryService | None = None) -> None:
9
+ self.search_service = search_service or WorkspaceQueryService()
10
+
11
+ @override
12
+ async def resolve_name_to_id(self, name: str) -> str | None:
13
+ if not name:
14
+ return None
15
+
16
+ cleaned_name = name.strip()
17
+ return await self._resolve_page_id(cleaned_name)
18
+
19
+ @override
20
+ async def resolve_id_to_name(self, page_id: str) -> str | None:
21
+ if not page_id:
22
+ return None
23
+
24
+ try:
25
+ from notionary import NotionPage
26
+
27
+ page = await NotionPage.from_id(page_id)
28
+ return page.title if page else None
29
+ except Exception:
30
+ return None
31
+
32
+ async def _resolve_page_id(self, name: str) -> str | None:
33
+ page = await self.search_service.find_page(query=name)
34
+ return page.id if page else None
@@ -0,0 +1,37 @@
1
+ from typing import override
2
+
3
+ from notionary.blocks.rich_text.name_id_resolver.port import NameIdResolver
4
+ from notionary.user.client import UserHttpClient
5
+ from notionary.user.person import PersonUser
6
+
7
+
8
+ class PersonNameIdResolver(NameIdResolver):
9
+ def __init__(self, person_user_factory=None, http_client: UserHttpClient | None = None) -> None:
10
+ if person_user_factory is None:
11
+ person_user_factory = PersonUser
12
+ self.person_user_factory = person_user_factory
13
+ self.http_client = http_client
14
+
15
+ @override
16
+ async def resolve_name_to_id(self, name: str | None) -> str | None:
17
+ if not name or not name.strip():
18
+ return None
19
+
20
+ name = name.strip()
21
+
22
+ try:
23
+ user = await self.person_user_factory.from_name(name, self.http_client)
24
+ return user.id if user else None
25
+ except Exception:
26
+ return None
27
+
28
+ @override
29
+ async def resolve_id_to_name(self, user_id: str | None) -> str | None:
30
+ if not user_id or not user_id.strip():
31
+ return None
32
+
33
+ try:
34
+ user = await self.person_user_factory.from_id(user_id.strip(), self.http_client)
35
+ return user.name if user else None
36
+ except Exception:
37
+ return None
@@ -0,0 +1,11 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class NameIdResolver(ABC):
5
+ @abstractmethod
6
+ def resolve_name_to_id(self, name: str) -> str | None:
7
+ pass
8
+
9
+ @abstractmethod
10
+ def resolve_id_to_name(self, id: str) -> str | None:
11
+ pass