notionary 0.2.28__tar.gz → 0.3.0__tar.gz

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 (244) hide show
  1. {notionary-0.2.28 → notionary-0.3.0}/PKG-INFO +27 -101
  2. {notionary-0.2.28 → notionary-0.3.0}/README.md +26 -100
  3. notionary-0.3.0/notionary/blocks/__init__.py +5 -0
  4. {notionary-0.2.28 → notionary-0.3.0}/notionary/blocks/client.py +6 -4
  5. {notionary-0.2.28 → notionary-0.3.0}/notionary/blocks/enums.py +1 -1
  6. {notionary-0.2.28 → notionary-0.3.0}/notionary/blocks/rich_text/markdown_rich_text_converter.py +14 -0
  7. {notionary-0.2.28 → notionary-0.3.0}/notionary/blocks/rich_text/models.py +14 -0
  8. {notionary-0.2.28 → notionary-0.3.0}/notionary/blocks/rich_text/name_id_resolver/__init__.py +2 -0
  9. notionary-0.3.0/notionary/blocks/rich_text/name_id_resolver/data_source.py +32 -0
  10. {notionary-0.2.28 → notionary-0.3.0}/notionary/blocks/rich_text/rich_text_markdown_converter.py +12 -0
  11. {notionary-0.2.28 → notionary-0.3.0}/notionary/blocks/rich_text/rich_text_patterns.py +3 -0
  12. {notionary-0.2.28 → notionary-0.3.0}/notionary/blocks/schemas.py +42 -10
  13. notionary-0.3.0/notionary/comments/__init__.py +5 -0
  14. {notionary-0.2.28 → notionary-0.3.0}/notionary/comments/client.py +1 -1
  15. {notionary-0.2.28 → notionary-0.3.0}/notionary/comments/factory.py +4 -6
  16. {notionary-0.2.28 → notionary-0.3.0}/notionary/data_source/http/data_source_instance_client.py +14 -4
  17. notionary-0.2.28/notionary/data_source/properties/models.py → notionary-0.3.0/notionary/data_source/properties/schemas.py +4 -8
  18. {notionary-0.2.28 → notionary-0.3.0}/notionary/data_source/query/builder.py +29 -10
  19. {notionary-0.2.28 → notionary-0.3.0}/notionary/data_source/query/schema.py +8 -10
  20. {notionary-0.2.28 → notionary-0.3.0}/notionary/data_source/query/validator.py +11 -11
  21. notionary-0.3.0/notionary/data_source/schema/registry.py +104 -0
  22. notionary-0.3.0/notionary/data_source/schema/service.py +136 -0
  23. {notionary-0.2.28 → notionary-0.3.0}/notionary/data_source/schemas.py +1 -1
  24. {notionary-0.2.28 → notionary-0.3.0}/notionary/data_source/service.py +33 -9
  25. {notionary-0.2.28 → notionary-0.3.0}/notionary/database/service.py +1 -2
  26. {notionary-0.2.28 → notionary-0.3.0}/notionary/exceptions/__init__.py +1 -1
  27. {notionary-0.2.28 → notionary-0.3.0}/notionary/exceptions/search.py +24 -0
  28. {notionary-0.2.28 → notionary-0.3.0}/notionary/http/client.py +8 -9
  29. {notionary-0.2.28 → notionary-0.3.0}/notionary/http/models.py +5 -4
  30. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/factory.py +8 -3
  31. notionary-0.3.0/notionary/page/content/markdown/builder.py +226 -0
  32. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/__init__.py +0 -2
  33. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/audio.py +1 -1
  34. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/base.py +1 -1
  35. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/bookmark.py +1 -1
  36. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/breadcrumb.py +1 -1
  37. notionary-0.3.0/notionary/page/content/markdown/nodes/bulleted_list.py +41 -0
  38. notionary-0.3.0/notionary/page/content/markdown/nodes/callout.py +34 -0
  39. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/code.py +3 -5
  40. notionary-0.3.0/notionary/page/content/markdown/nodes/columns.py +69 -0
  41. notionary-0.3.0/notionary/page/content/markdown/nodes/container.py +64 -0
  42. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/divider.py +1 -1
  43. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/embed.py +1 -1
  44. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/equation.py +1 -1
  45. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/file.py +1 -1
  46. notionary-0.3.0/notionary/page/content/markdown/nodes/heading.py +36 -0
  47. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/image.py +1 -1
  48. notionary-0.3.0/notionary/page/content/markdown/nodes/mixins/__init__.py +5 -0
  49. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/mixins/caption.py +1 -1
  50. notionary-0.3.0/notionary/page/content/markdown/nodes/numbered_list.py +38 -0
  51. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/paragraph.py +1 -1
  52. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/pdf.py +1 -1
  53. notionary-0.3.0/notionary/page/content/markdown/nodes/quote.py +27 -0
  54. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/space.py +1 -1
  55. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/table.py +1 -1
  56. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/table_of_contents.py +1 -1
  57. notionary-0.3.0/notionary/page/content/markdown/nodes/todo.py +38 -0
  58. notionary-0.3.0/notionary/page/content/markdown/nodes/toggle.py +27 -0
  59. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/nodes/video.py +1 -1
  60. notionary-0.3.0/notionary/page/content/parser/context.py +126 -0
  61. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/factory.py +1 -10
  62. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/__init__.py +0 -2
  63. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/audio.py +1 -1
  64. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/base.py +1 -1
  65. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/bookmark.py +1 -1
  66. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/breadcrumb.py +1 -1
  67. notionary-0.3.0/notionary/page/content/parser/parsers/bulleted_list.py +85 -0
  68. notionary-0.3.0/notionary/page/content/parser/parsers/callout.py +100 -0
  69. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/caption.py +1 -1
  70. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/code.py +5 -5
  71. notionary-0.3.0/notionary/page/content/parser/parsers/column.py +76 -0
  72. notionary-0.3.0/notionary/page/content/parser/parsers/column_list.py +81 -0
  73. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/divider.py +1 -1
  74. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/embed.py +1 -1
  75. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/equation.py +1 -1
  76. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/file.py +1 -1
  77. notionary-0.3.0/notionary/page/content/parser/parsers/heading.py +115 -0
  78. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/image.py +1 -1
  79. notionary-0.3.0/notionary/page/content/parser/parsers/numbered_list.py +89 -0
  80. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/paragraph.py +3 -2
  81. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/pdf.py +1 -1
  82. notionary-0.3.0/notionary/page/content/parser/parsers/quote.py +125 -0
  83. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/space.py +14 -8
  84. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/table.py +1 -1
  85. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/table_of_contents.py +1 -1
  86. notionary-0.3.0/notionary/page/content/parser/parsers/todo.py +96 -0
  87. notionary-0.3.0/notionary/page/content/parser/parsers/toggle.py +70 -0
  88. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/parsers/video.py +1 -1
  89. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/post_processing/handlers/rich_text_length.py +6 -4
  90. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/post_processing/handlers/rich_text_length_truncation.py +43 -22
  91. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/pre_processsing/handlers/__init__.py +2 -0
  92. notionary-0.3.0/notionary/page/content/parser/pre_processsing/handlers/column_syntax.py +130 -0
  93. notionary-0.3.0/notionary/page/content/parser/pre_processsing/handlers/indentation.py +84 -0
  94. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/pre_processsing/handlers/whitespace.py +12 -7
  95. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/service.py +9 -0
  96. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/context.py +5 -2
  97. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/factory.py +2 -11
  98. notionary-0.3.0/notionary/page/content/renderer/post_processing/handlers/__init__.py +5 -0
  99. notionary-0.3.0/notionary/page/content/renderer/post_processing/handlers/numbered_list.py +156 -0
  100. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/__init__.py +0 -2
  101. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/base.py +1 -1
  102. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/bulleted_list.py +1 -1
  103. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/callout.py +6 -21
  104. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/captioned_block.py +1 -1
  105. notionary-0.3.0/notionary/page/content/renderer/renderers/column.py +53 -0
  106. notionary-0.3.0/notionary/page/content/renderer/renderers/column_list.py +44 -0
  107. notionary-0.3.0/notionary/page/content/renderer/renderers/heading.py +95 -0
  108. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/numbered_list.py +6 -5
  109. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/quote.py +1 -1
  110. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/todo.py +1 -1
  111. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/toggle.py +6 -7
  112. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/service.py +4 -1
  113. notionary-0.3.0/notionary/page/content/syntax/__init__.py +4 -0
  114. notionary-0.3.0/notionary/page/content/syntax/grammar.py +10 -0
  115. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/syntax/models.py +0 -2
  116. notionary-0.2.28/notionary/page/content/syntax/service.py → notionary-0.3.0/notionary/page/content/syntax/registry.py +31 -91
  117. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/properties/client.py +1 -1
  118. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/properties/models.py +3 -2
  119. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/properties/service.py +4 -0
  120. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/service.py +5 -2
  121. {notionary-0.2.28 → notionary-0.3.0}/notionary/shared/models/cover.py +1 -1
  122. notionary-0.3.0/notionary/shared/typings.py +3 -0
  123. notionary-0.3.0/notionary/user/base.py +138 -0
  124. notionary-0.3.0/notionary/user/factory.py +0 -0
  125. notionary-0.3.0/notionary/utils/decorators.py +122 -0
  126. {notionary-0.2.28 → notionary-0.3.0}/notionary/utils/fuzzy.py +18 -6
  127. notionary-0.3.0/notionary/utils/mixins/logging.py +58 -0
  128. notionary-0.3.0/notionary/utils/pagination.py +100 -0
  129. notionary-0.3.0/notionary/workspace/__init__.py +4 -0
  130. {notionary-0.2.28 → notionary-0.3.0}/notionary/workspace/client.py +2 -2
  131. notionary-0.3.0/notionary/workspace/query/__init__.py +3 -0
  132. {notionary-0.2.28 → notionary-0.3.0}/notionary/workspace/query/models.py +4 -3
  133. {notionary-0.2.28 → notionary-0.3.0}/notionary/workspace/query/service.py +29 -22
  134. {notionary-0.2.28 → notionary-0.3.0}/pyproject.toml +1 -1
  135. notionary-0.2.28/notionary/page/content/markdown/builder.py +0 -304
  136. notionary-0.2.28/notionary/page/content/markdown/nodes/bulleted_list.py +0 -18
  137. notionary-0.2.28/notionary/page/content/markdown/nodes/callout.py +0 -32
  138. notionary-0.2.28/notionary/page/content/markdown/nodes/columns.py +0 -51
  139. notionary-0.2.28/notionary/page/content/markdown/nodes/heading.py +0 -16
  140. notionary-0.2.28/notionary/page/content/markdown/nodes/numbered_list.py +0 -15
  141. notionary-0.2.28/notionary/page/content/markdown/nodes/quote.py +0 -15
  142. notionary-0.2.28/notionary/page/content/markdown/nodes/todo.py +0 -22
  143. notionary-0.2.28/notionary/page/content/markdown/nodes/toggle.py +0 -28
  144. notionary-0.2.28/notionary/page/content/markdown/nodes/toggleable_heading.py +0 -35
  145. notionary-0.2.28/notionary/page/content/parser/context.py +0 -49
  146. notionary-0.2.28/notionary/page/content/parser/parsers/bulleted_list.py +0 -41
  147. notionary-0.2.28/notionary/page/content/parser/parsers/callout.py +0 -129
  148. notionary-0.2.28/notionary/page/content/parser/parsers/column.py +0 -117
  149. notionary-0.2.28/notionary/page/content/parser/parsers/column_list.py +0 -81
  150. notionary-0.2.28/notionary/page/content/parser/parsers/heading.py +0 -58
  151. notionary-0.2.28/notionary/page/content/parser/parsers/numbered_list.py +0 -45
  152. notionary-0.2.28/notionary/page/content/parser/parsers/quote.py +0 -65
  153. notionary-0.2.28/notionary/page/content/parser/parsers/todo.py +0 -58
  154. notionary-0.2.28/notionary/page/content/parser/parsers/toggle.py +0 -127
  155. notionary-0.2.28/notionary/page/content/parser/parsers/toggleable_heading.py +0 -150
  156. notionary-0.2.28/notionary/page/content/parser/pre_processsing/handlers/column_syntax.py +0 -80
  157. notionary-0.2.28/notionary/page/content/renderer/post_processing/handlers/__init__.py +0 -5
  158. notionary-0.2.28/notionary/page/content/renderer/post_processing/handlers/numbered_list_placeholdere.py +0 -62
  159. notionary-0.2.28/notionary/page/content/renderer/renderers/column.py +0 -44
  160. notionary-0.2.28/notionary/page/content/renderer/renderers/column_list.py +0 -31
  161. notionary-0.2.28/notionary/page/content/renderer/renderers/heading.py +0 -69
  162. notionary-0.2.28/notionary/page/content/renderer/renderers/toggleable_heading.py +0 -78
  163. notionary-0.2.28/notionary/user/base.py +0 -89
  164. notionary-0.2.28/notionary/utils/async_retry.py +0 -39
  165. notionary-0.2.28/notionary/utils/mixins/logging.py +0 -47
  166. notionary-0.2.28/notionary/utils/pagination.py +0 -50
  167. notionary-0.2.28/notionary/utils/singleton.py +0 -13
  168. notionary-0.2.28/notionary/workspace/__init__.py +0 -3
  169. {notionary-0.2.28 → notionary-0.3.0}/.gitignore +0 -0
  170. {notionary-0.2.28 → notionary-0.3.0}/LICENSE +0 -0
  171. {notionary-0.2.28 → notionary-0.3.0}/notionary/__init__.py +0 -0
  172. {notionary-0.2.28 → notionary-0.3.0}/notionary/blocks/rich_text/name_id_resolver/database.py +0 -0
  173. {notionary-0.2.28 → notionary-0.3.0}/notionary/blocks/rich_text/name_id_resolver/page.py +0 -0
  174. {notionary-0.2.28 → notionary-0.3.0}/notionary/blocks/rich_text/name_id_resolver/person.py +0 -0
  175. {notionary-0.2.28 → notionary-0.3.0}/notionary/blocks/rich_text/name_id_resolver/port.py +0 -0
  176. {notionary-0.2.28 → notionary-0.3.0}/notionary/comments/models.py +0 -0
  177. {notionary-0.2.28 → notionary-0.3.0}/notionary/comments/schemas.py +0 -0
  178. {notionary-0.2.28 → notionary-0.3.0}/notionary/comments/service.py +0 -0
  179. {notionary-0.2.28 → notionary-0.3.0}/notionary/data_source/http/client.py +0 -0
  180. {notionary-0.2.28 → notionary-0.3.0}/notionary/data_source/query/resolver.py +0 -0
  181. {notionary-0.2.28 → notionary-0.3.0}/notionary/database/client.py +0 -0
  182. {notionary-0.2.28 → notionary-0.3.0}/notionary/database/database_metadata_update_client.py +0 -0
  183. {notionary-0.2.28 → notionary-0.3.0}/notionary/database/schemas.py +0 -0
  184. {notionary-0.2.28 → notionary-0.3.0}/notionary/exceptions/api.py +0 -0
  185. {notionary-0.2.28 → notionary-0.3.0}/notionary/exceptions/base.py +0 -0
  186. {notionary-0.2.28 → notionary-0.3.0}/notionary/exceptions/block_parsing.py +0 -0
  187. {notionary-0.2.28 → notionary-0.3.0}/notionary/exceptions/data_source/__init__.py +0 -0
  188. {notionary-0.2.28 → notionary-0.3.0}/notionary/exceptions/data_source/builder.py +0 -0
  189. {notionary-0.2.28 → notionary-0.3.0}/notionary/exceptions/data_source/properties.py +0 -0
  190. {notionary-0.2.28 → notionary-0.3.0}/notionary/exceptions/properties.py +0 -0
  191. {notionary-0.2.28 → notionary-0.3.0}/notionary/file_upload/client.py +0 -0
  192. {notionary-0.2.28 → notionary-0.3.0}/notionary/file_upload/models.py +0 -0
  193. {notionary-0.2.28 → notionary-0.3.0}/notionary/file_upload/service.py +0 -0
  194. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/blocks/client.py +0 -0
  195. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/markdown/__init__.py +0 -0
  196. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/post_processing/handlers/__init__.py +0 -0
  197. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/post_processing/port.py +0 -0
  198. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/post_processing/service.py +0 -0
  199. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/pre_processsing/handlers/port.py +0 -0
  200. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/parser/pre_processsing/service.py +0 -0
  201. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/post_processing/port.py +0 -0
  202. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/post_processing/service.py +0 -0
  203. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/audio.py +0 -0
  204. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/bookmark.py +0 -0
  205. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/breadcrumb.py +0 -0
  206. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/code.py +0 -0
  207. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/divider.py +0 -0
  208. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/embed.py +0 -0
  209. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/equation.py +0 -0
  210. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/fallback.py +0 -0
  211. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/file.py +0 -0
  212. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/image.py +0 -0
  213. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/paragraph.py +0 -0
  214. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/pdf.py +0 -0
  215. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/table.py +0 -0
  216. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/table_of_contents.py +0 -0
  217. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/table_row.py +0 -0
  218. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/renderers/video.py +0 -0
  219. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/content/renderer/service.py +0 -0
  220. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/page_context.py +0 -0
  221. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/page_http_client.py +0 -0
  222. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/page_metadata_update_client.py +0 -0
  223. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/properties/factory.py +0 -0
  224. {notionary-0.2.28 → notionary-0.3.0}/notionary/page/schemas.py +0 -0
  225. {notionary-0.2.28 → notionary-0.3.0}/notionary/shared/entity/client.py +0 -0
  226. {notionary-0.2.28 → notionary-0.3.0}/notionary/shared/entity/dto_parsers.py +0 -0
  227. {notionary-0.2.28 → notionary-0.3.0}/notionary/shared/entity/entity_metadata_update_client.py +0 -0
  228. {notionary-0.2.28 → notionary-0.3.0}/notionary/shared/entity/schemas.py +0 -0
  229. {notionary-0.2.28 → notionary-0.3.0}/notionary/shared/entity/service.py +0 -0
  230. {notionary-0.2.28 → notionary-0.3.0}/notionary/shared/models/file.py +0 -0
  231. {notionary-0.2.28 → notionary-0.3.0}/notionary/shared/models/icon.py +0 -0
  232. {notionary-0.2.28 → notionary-0.3.0}/notionary/shared/models/parent.py +0 -0
  233. {notionary-0.2.28 → notionary-0.3.0}/notionary/shared/properties/type.py +0 -0
  234. {notionary-0.2.28 → notionary-0.3.0}/notionary/user/__init__.py +0 -0
  235. {notionary-0.2.28 → notionary-0.3.0}/notionary/user/bot.py +0 -0
  236. {notionary-0.2.28 → notionary-0.3.0}/notionary/user/client.py +0 -0
  237. {notionary-0.2.28 → notionary-0.3.0}/notionary/user/person.py +0 -0
  238. {notionary-0.2.28 → notionary-0.3.0}/notionary/user/schemas.py +0 -0
  239. {notionary-0.2.28 → notionary-0.3.0}/notionary/user/service.py +0 -0
  240. {notionary-0.2.28 → notionary-0.3.0}/notionary/utils/date.py +0 -0
  241. {notionary-0.2.28 → notionary-0.3.0}/notionary/utils/uuid_utils.py +0 -0
  242. {notionary-0.2.28 → notionary-0.3.0}/notionary/workspace/query/builder.py +0 -0
  243. {notionary-0.2.28 → notionary-0.3.0}/notionary/workspace/schemas.py +0 -0
  244. {notionary-0.2.28 → notionary-0.3.0}/notionary/workspace/service.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: notionary
3
- Version: 0.2.28
3
+ Version: 0.3.0
4
4
  Summary: Python library for programmatic Notion workspace management - databases, pages, and content with advanced Markdown support
5
5
  Project-URL: Homepage, https://github.com/mathisarends/notionary
6
6
  Author-email: Mathis Arends <mathisarends27@gmail.com>
@@ -61,17 +61,9 @@ export NOTION_SECRET=your_integration_key
61
61
 
62
62
  ## See It in Action
63
63
 
64
- ### Creating Rich Database Entries
65
-
66
64
  https://github.com/user-attachments/assets/da8b4691-bee4-4b0f-801e-dccacb630398
67
65
 
68
- _Create styled project pages with properties, content, and rich formatting_
69
-
70
- ### Local File Uploads (Videos & Images)
71
-
72
- https://github.com/user-attachments/assets/a079ec01-bb56-4c65-8260-7b1fca42ac68
73
-
74
- _Upload videos and images using simple markdown syntax - files are automatically uploaded to Notion_
66
+ _Create rich database entries with properties, content, and beautiful formatting_
75
67
 
76
68
  ---
77
69
 
@@ -80,50 +72,30 @@ _Upload videos and images using simple markdown syntax - files are automatically
80
72
  ### Find → Create → Update Flow
81
73
 
82
74
  ```python
83
- import asyncio
84
- from notionary import NotionPage, NotionDatabase
85
-
86
- async def main():
87
- # Find pages by name - fuzzy matching included!
88
- page = await NotionPage.from_title("Meeting Notes")
89
-
90
- # Option 1: Direct Extended Markdown
91
- await page.append_markdown("""
92
- ## Action Items
93
- - [x] Review project proposal
94
- - [ ] Schedule team meeting
95
- - [ ] Update documentation
96
-
97
- [callout](Meeting decisions require follow-up "💡")
98
-
99
- +++ Details
100
- Additional context and next steps...
101
- +++
102
- """)
103
-
104
- # Option 2: Type-Safe Builder (maps to same markdown internally)
105
- await page.append_markdown(lambda builder: (
106
- builder
107
- .h2("Project Status")
108
- .callout("Milestone reached!", "🎉")
109
- .columns(
110
- lambda col: col.h3("Completed").bulleted_list([
111
- "API design", "Database setup", "Authentication"
112
- ]),
113
- lambda col: col.h3("In Progress").bulleted_list([
114
- "Frontend UI", "Testing", "Documentation"
115
- ]),
116
- width_ratios=[0.6, 0.4]
117
- )
118
- .toggle("Budget Details", lambda t: t
119
- .table(["Item", "Cost", "Status"], [
120
- ["Development", "$15,000", "Paid"],
121
- ["Design", "$8,000", "Pending"]
122
- ])
123
- )
124
- ))
125
-
126
- asyncio.run(main())
75
+ from notionary import NotionPage
76
+
77
+ # Find pages by name with fuzzy matching
78
+ page = await NotionPage.from_title("Meeting Notes")
79
+
80
+ # Define rich content with extended markdown
81
+ content = """
82
+ ## Action Items
83
+ - [x] Review proposal
84
+ - [ ] Schedule meeting
85
+
86
+ [callout](Key decision made! "💡")
87
+
88
+ | Task | Owner | Deadline |
89
+ |------|-------|----------|
90
+ | Design Review | Alice | 2024-03-15 |
91
+ | Implementation | Bob | 2024-03-22 |
92
+
93
+ +++ Budget Details
94
+ See attached spreadsheet...
95
+ +++
96
+ """
97
+
98
+ await page.append_markdown(content)
127
99
  ```
128
100
 
129
101
  ### Complete Block Support
@@ -132,36 +104,13 @@ Every Notion block type with extended syntax:
132
104
 
133
105
  | Block Type | Markdown Syntax | Use Case |
134
106
  | ------------- | -------------------------------------------- | ---------------------------- |
135
- | **Callouts** | `[callout](Text "🔥")` | Highlighting key information |
136
107
  | **Toggles** | `+++ Title\nContent\n+++` | Collapsible sections |
137
108
  | **Columns** | `::: columns\n::: column\nContent\n:::\n:::` | Side-by-side layouts |
138
109
  | **Tables** | Standard markdown tables | Structured data |
139
110
  | **Media** | `[video](./file.mp4)(caption:Description)` | Auto-uploading files |
140
111
  | **Code** | Standard code fences with captions | Code snippets |
141
112
  | **Equations** | `$LaTeX$` | Mathematical expressions |
142
- | **TOC** | `[toc](blue_background)` | Auto-generated navigation |
143
-
144
- ---
145
-
146
- ## What You Can Build 💡
147
-
148
- ### **AI Content Systems**
149
-
150
- - **Report Generation**: AI agents that create structured reports, documentation, and analysis
151
- - **Content Pipelines**: Automated workflows that process data and generate Notion pages
152
- - **Knowledge Management**: AI-powered documentation systems with smart categorization
153
-
154
- ### **Workflow Automation**
155
-
156
- - **Project Management**: Sync project status, update timelines, generate progress reports
157
- - **Data Integration**: Connect external APIs and databases to Notion workspaces
158
- - **Template Systems**: Dynamic page generation from templates and data sources
159
-
160
- ### **Content Management**
161
-
162
- - **Bulk Operations**: Mass page updates, content migration, and database management
163
- - **Media Handling**: Automated image/video uploads with proper organization
164
- - **Cross-Platform**: Sync content between Notion and other platforms
113
+ | **TOC** | `[toc]` | Auto-generated navigation |
165
114
 
166
115
  ---
167
116
 
@@ -222,29 +171,6 @@ Every Notion block type with extended syntax:
222
171
 
223
172
  [**mathisarends.github.io/notionary**](https://mathisarends.github.io/notionary/) - Complete API reference, guides, and tutorials
224
173
 
225
- ### Quick Links
226
-
227
- - [**Getting Started**](https://mathisarends.github.io/notionary/get-started/) - Setup and first steps
228
- - [**Page Management**](https://mathisarends.github.io/notionary/page/) - Content and properties
229
- - [**Database Operations**](https://mathisarends.github.io/notionary/database/) - Queries and management
230
- - [**Block Types Reference**](https://mathisarends.github.io/notionary/blocks/) - Complete syntax guide
231
-
232
- ### Hands-On Examples
233
-
234
- **Core Functionality:**
235
-
236
- - [Page Management](examples/page_example.py) - Create, update, and manage pages
237
- - [Database Operations](examples/database.py) - Connect and query databases
238
- - [Workspace Discovery](examples/workspace_discovery.py) - Explore your workspace
239
-
240
- **Extended Markdown:**
241
-
242
- - [Basic Formatting](examples/markdown/basic.py) - Text, lists, and links
243
- - [Callouts & Highlights](examples/markdown/callout.py) - Information boxes
244
- - [Toggle Sections](examples/markdown/toggle.py) - Collapsible content
245
- - [Multi-Column Layouts](examples/markdown/columns.py) - Side-by-side design
246
- - [Tables & Data](examples/markdown/table.py) - Structured presentations
247
-
248
174
  ---
249
175
 
250
176
  ## Contributing
@@ -46,17 +46,9 @@ export NOTION_SECRET=your_integration_key
46
46
 
47
47
  ## See It in Action
48
48
 
49
- ### Creating Rich Database Entries
50
-
51
49
  https://github.com/user-attachments/assets/da8b4691-bee4-4b0f-801e-dccacb630398
52
50
 
53
- _Create styled project pages with properties, content, and rich formatting_
54
-
55
- ### Local File Uploads (Videos & Images)
56
-
57
- https://github.com/user-attachments/assets/a079ec01-bb56-4c65-8260-7b1fca42ac68
58
-
59
- _Upload videos and images using simple markdown syntax - files are automatically uploaded to Notion_
51
+ _Create rich database entries with properties, content, and beautiful formatting_
60
52
 
61
53
  ---
62
54
 
@@ -65,50 +57,30 @@ _Upload videos and images using simple markdown syntax - files are automatically
65
57
  ### Find → Create → Update Flow
66
58
 
67
59
  ```python
68
- import asyncio
69
- from notionary import NotionPage, NotionDatabase
70
-
71
- async def main():
72
- # Find pages by name - fuzzy matching included!
73
- page = await NotionPage.from_title("Meeting Notes")
74
-
75
- # Option 1: Direct Extended Markdown
76
- await page.append_markdown("""
77
- ## Action Items
78
- - [x] Review project proposal
79
- - [ ] Schedule team meeting
80
- - [ ] Update documentation
81
-
82
- [callout](Meeting decisions require follow-up "💡")
83
-
84
- +++ Details
85
- Additional context and next steps...
86
- +++
87
- """)
88
-
89
- # Option 2: Type-Safe Builder (maps to same markdown internally)
90
- await page.append_markdown(lambda builder: (
91
- builder
92
- .h2("Project Status")
93
- .callout("Milestone reached!", "🎉")
94
- .columns(
95
- lambda col: col.h3("Completed").bulleted_list([
96
- "API design", "Database setup", "Authentication"
97
- ]),
98
- lambda col: col.h3("In Progress").bulleted_list([
99
- "Frontend UI", "Testing", "Documentation"
100
- ]),
101
- width_ratios=[0.6, 0.4]
102
- )
103
- .toggle("Budget Details", lambda t: t
104
- .table(["Item", "Cost", "Status"], [
105
- ["Development", "$15,000", "Paid"],
106
- ["Design", "$8,000", "Pending"]
107
- ])
108
- )
109
- ))
110
-
111
- asyncio.run(main())
60
+ from notionary import NotionPage
61
+
62
+ # Find pages by name with fuzzy matching
63
+ page = await NotionPage.from_title("Meeting Notes")
64
+
65
+ # Define rich content with extended markdown
66
+ content = """
67
+ ## Action Items
68
+ - [x] Review proposal
69
+ - [ ] Schedule meeting
70
+
71
+ [callout](Key decision made! "💡")
72
+
73
+ | Task | Owner | Deadline |
74
+ |------|-------|----------|
75
+ | Design Review | Alice | 2024-03-15 |
76
+ | Implementation | Bob | 2024-03-22 |
77
+
78
+ +++ Budget Details
79
+ See attached spreadsheet...
80
+ +++
81
+ """
82
+
83
+ await page.append_markdown(content)
112
84
  ```
113
85
 
114
86
  ### Complete Block Support
@@ -117,36 +89,13 @@ Every Notion block type with extended syntax:
117
89
 
118
90
  | Block Type | Markdown Syntax | Use Case |
119
91
  | ------------- | -------------------------------------------- | ---------------------------- |
120
- | **Callouts** | `[callout](Text "🔥")` | Highlighting key information |
121
92
  | **Toggles** | `+++ Title\nContent\n+++` | Collapsible sections |
122
93
  | **Columns** | `::: columns\n::: column\nContent\n:::\n:::` | Side-by-side layouts |
123
94
  | **Tables** | Standard markdown tables | Structured data |
124
95
  | **Media** | `[video](./file.mp4)(caption:Description)` | Auto-uploading files |
125
96
  | **Code** | Standard code fences with captions | Code snippets |
126
97
  | **Equations** | `$LaTeX$` | Mathematical expressions |
127
- | **TOC** | `[toc](blue_background)` | Auto-generated navigation |
128
-
129
- ---
130
-
131
- ## What You Can Build 💡
132
-
133
- ### **AI Content Systems**
134
-
135
- - **Report Generation**: AI agents that create structured reports, documentation, and analysis
136
- - **Content Pipelines**: Automated workflows that process data and generate Notion pages
137
- - **Knowledge Management**: AI-powered documentation systems with smart categorization
138
-
139
- ### **Workflow Automation**
140
-
141
- - **Project Management**: Sync project status, update timelines, generate progress reports
142
- - **Data Integration**: Connect external APIs and databases to Notion workspaces
143
- - **Template Systems**: Dynamic page generation from templates and data sources
144
-
145
- ### **Content Management**
146
-
147
- - **Bulk Operations**: Mass page updates, content migration, and database management
148
- - **Media Handling**: Automated image/video uploads with proper organization
149
- - **Cross-Platform**: Sync content between Notion and other platforms
98
+ | **TOC** | `[toc]` | Auto-generated navigation |
150
99
 
151
100
  ---
152
101
 
@@ -207,29 +156,6 @@ Every Notion block type with extended syntax:
207
156
 
208
157
  [**mathisarends.github.io/notionary**](https://mathisarends.github.io/notionary/) - Complete API reference, guides, and tutorials
209
158
 
210
- ### Quick Links
211
-
212
- - [**Getting Started**](https://mathisarends.github.io/notionary/get-started/) - Setup and first steps
213
- - [**Page Management**](https://mathisarends.github.io/notionary/page/) - Content and properties
214
- - [**Database Operations**](https://mathisarends.github.io/notionary/database/) - Queries and management
215
- - [**Block Types Reference**](https://mathisarends.github.io/notionary/blocks/) - Complete syntax guide
216
-
217
- ### Hands-On Examples
218
-
219
- **Core Functionality:**
220
-
221
- - [Page Management](examples/page_example.py) - Create, update, and manage pages
222
- - [Database Operations](examples/database.py) - Connect and query databases
223
- - [Workspace Discovery](examples/workspace_discovery.py) - Explore your workspace
224
-
225
- **Extended Markdown:**
226
-
227
- - [Basic Formatting](examples/markdown/basic.py) - Text, lists, and links
228
- - [Callouts & Highlights](examples/markdown/callout.py) - Information boxes
229
- - [Toggle Sections](examples/markdown/toggle.py) - Collapsible content
230
- - [Multi-Column Layouts](examples/markdown/columns.py) - Side-by-side design
231
- - [Tables & Data](examples/markdown/table.py) - Structured presentations
232
-
233
159
  ---
234
160
 
235
161
  ## Contributing
@@ -0,0 +1,5 @@
1
+ from .enums import CodingLanguage
2
+
3
+ # Import from schemas aswell
4
+
5
+ __all__ = ["CodingLanguage"]
@@ -1,7 +1,7 @@
1
- from typing import Any
2
-
3
1
  from notionary.blocks.schemas import Block, BlockChildrenResponse, BlockCreatePayload
4
2
  from notionary.http.client import NotionHttpClient
3
+ from notionary.shared.typings import JsonDict
4
+ from notionary.utils.decorators import time_execution_async
5
5
  from notionary.utils.pagination import paginate_notion_api
6
6
 
7
7
 
@@ -16,6 +16,7 @@ class NotionBlockHttpClient(NotionHttpClient):
16
16
  self.logger.debug("Deleting block: %s", block_id)
17
17
  await self.delete(f"blocks/{block_id}")
18
18
 
19
+ @time_execution_async()
19
20
  async def get_block_tree(self, parent_block_id: str) -> list[Block]:
20
21
  blocks_at_this_level = await self.get_all_block_children(parent_block_id)
21
22
 
@@ -26,6 +27,7 @@ class NotionBlockHttpClient(NotionHttpClient):
26
27
 
27
28
  return blocks_at_this_level
28
29
 
30
+ @time_execution_async()
29
31
  async def get_all_block_children(self, parent_block_id: str) -> list[Block]:
30
32
  self.logger.debug("Retrieving all children for block: %s", parent_block_id)
31
33
 
@@ -73,11 +75,11 @@ class NotionBlockHttpClient(NotionHttpClient):
73
75
  batches.append(batch)
74
76
  return batches
75
77
 
76
- def _serialize_blocks(self, blocks: list[BlockCreatePayload]) -> list[dict[str, Any]]:
78
+ def _serialize_blocks(self, blocks: list[BlockCreatePayload]) -> list[JsonDict]:
77
79
  return [block.model_dump(exclude_none=True) for block in blocks]
78
80
 
79
81
  async def _send_append_request(
80
- self, block_id: str, children: list[dict[str, Any]], after_block_id: str | None = None
82
+ self, block_id: str, children: list[JsonDict], after_block_id: str | None = None
81
83
  ) -> BlockChildrenResponse:
82
84
  payload = {"children": children}
83
85
  if after_block_id:
@@ -68,7 +68,7 @@ class FileType(StrEnum):
68
68
  FILE_UPLOAD = "file_upload"
69
69
 
70
70
 
71
- class CodeLanguage(StrEnum):
71
+ class CodingLanguage(StrEnum):
72
72
  ABAP = "abap"
73
73
  ARDUINO = "arduino"
74
74
  BASH = "bash"
@@ -7,6 +7,7 @@ from typing import ClassVar
7
7
  from notionary.blocks.rich_text.models import MentionType, RichText, RichTextType, TextAnnotations
8
8
  from notionary.blocks.rich_text.name_id_resolver import (
9
9
  DatabaseNameIdResolver,
10
+ DataSourceNameIdResolver,
10
11
  NameIdResolver,
11
12
  PageNameIdResolver,
12
13
  PersonNameIdResolver,
@@ -44,10 +45,12 @@ class MarkdownRichTextConverter:
44
45
  *,
45
46
  page_resolver: NameIdResolver | None = None,
46
47
  database_resolver: NameIdResolver | None = None,
48
+ data_source_resolver: NameIdResolver | None = None,
47
49
  person_resolver: NameIdResolver | None = None,
48
50
  ):
49
51
  self.page_resolver = page_resolver or PageNameIdResolver()
50
52
  self.database_resolver = database_resolver or DatabaseNameIdResolver()
53
+ self.data_source_resolver = data_source_resolver or DataSourceNameIdResolver()
51
54
  self.person_resolver = person_resolver or PersonNameIdResolver()
52
55
  self.format_handlers = self._setup_format_handlers()
53
56
 
@@ -64,6 +67,7 @@ class MarkdownRichTextConverter:
64
67
  PatternHandler(RichTextPatterns.COLOR, self._handle_color_pattern),
65
68
  PatternHandler(RichTextPatterns.PAGE_MENTION, self._handle_page_mention_pattern),
66
69
  PatternHandler(RichTextPatterns.DATABASE_MENTION, self._handle_database_mention_pattern),
70
+ PatternHandler(RichTextPatterns.DATASOURCE_MENTION, self._handle_data_source_mention_pattern),
67
71
  PatternHandler(RichTextPatterns.USER_MENTION, self._handle_user_mention_pattern),
68
72
  ]
69
73
 
@@ -119,6 +123,7 @@ class MarkdownRichTextConverter:
119
123
  async_handlers = {
120
124
  self._handle_page_mention_pattern,
121
125
  self._handle_database_mention_pattern,
126
+ self._handle_data_source_mention_pattern,
122
127
  self._handle_color_pattern, # Color pattern needs async for recursive parsing
123
128
  self._handle_user_mention_pattern,
124
129
  }
@@ -210,6 +215,15 @@ class MarkdownRichTextConverter:
210
215
  mention_type=MentionType.DATABASE,
211
216
  )
212
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
+
213
227
  async def _handle_user_mention_pattern(self, match: Match) -> RichText:
214
228
  identifier = match.group(1)
215
229
  return await self._create_mention_or_fallback(
@@ -16,6 +16,7 @@ class MentionType(StrEnum):
16
16
  USER = "user"
17
17
  PAGE = "page"
18
18
  DATABASE = "database"
19
+ DATASOURCE = "data_source"
19
20
  DATE = "date"
20
21
  LINK_PREVIEW = "link_preview"
21
22
  TEMPLATE_MENTION = "template_mention"
@@ -60,6 +61,10 @@ class MentionDatabaseRef(BaseModel):
60
61
  id: str
61
62
 
62
63
 
64
+ class MentionDataSourceRef(BaseModel):
65
+ id: str
66
+
67
+
63
68
  class MentionLinkPreview(BaseModel):
64
69
  url: str
65
70
 
@@ -81,6 +86,7 @@ class MentionObject(BaseModel):
81
86
  user: MentionUserRef | None = None
82
87
  page: MentionPageRef | None = None
83
88
  database: MentionDatabaseRef | None = None
89
+ data_source: MentionDataSourceRef | None = None
84
90
  date: MentionDate | None = None
85
91
  link_preview: MentionLinkPreview | None = None
86
92
  template_mention: MentionTemplateMention | None = None
@@ -154,6 +160,14 @@ class RichText(BaseModel):
154
160
  annotations=TextAnnotations(),
155
161
  )
156
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
+
157
171
  @classmethod
158
172
  def equation_inline(cls, expression: str) -> Self:
159
173
  return cls(
@@ -1,9 +1,11 @@
1
+ from .data_source import DataSourceNameIdResolver
1
2
  from .database import DatabaseNameIdResolver
2
3
  from .page import PageNameIdResolver
3
4
  from .person import PersonNameIdResolver
4
5
  from .port import NameIdResolver
5
6
 
6
7
  __all__ = [
8
+ "DataSourceNameIdResolver",
7
9
  "DatabaseNameIdResolver",
8
10
  "NameIdResolver",
9
11
  "PageNameIdResolver",
@@ -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
@@ -8,6 +8,7 @@ from notionary.blocks.rich_text.models import (
8
8
  )
9
9
  from notionary.blocks.rich_text.name_id_resolver import (
10
10
  DatabaseNameIdResolver,
11
+ DataSourceNameIdResolver,
11
12
  NameIdResolver,
12
13
  PageNameIdResolver,
13
14
  PersonNameIdResolver,
@@ -23,10 +24,12 @@ class RichTextToMarkdownConverter:
23
24
  *,
24
25
  page_resolver: NameIdResolver | None = None,
25
26
  database_resolver: NameIdResolver | None = None,
27
+ data_source_resolver: NameIdResolver | None = None,
26
28
  person_resolver: NameIdResolver | None = None,
27
29
  ) -> None:
28
30
  self.page_resolver = page_resolver or PageNameIdResolver()
29
31
  self.database_resolver = database_resolver or DatabaseNameIdResolver()
32
+ self.data_source_resolver = data_source_resolver or DataSourceNameIdResolver()
30
33
  self.person_resolver = person_resolver or PersonNameIdResolver()
31
34
 
32
35
  async def to_markdown(self, rich_text: list[RichText]) -> str:
@@ -65,6 +68,9 @@ class RichTextToMarkdownConverter:
65
68
  elif mention.type == MentionType.DATABASE and mention.database:
66
69
  return await self._extract_database_mention_markdown(mention.database.id)
67
70
 
71
+ elif mention.type == MentionType.DATASOURCE and mention.data_source:
72
+ return await self._extract_data_source_mention_markdown(mention.data_source.id)
73
+
68
74
  elif mention.type == MentionType.USER and mention.user:
69
75
  return await self._extract_user_mention_markdown(mention.user.id)
70
76
 
@@ -81,6 +87,10 @@ class RichTextToMarkdownConverter:
81
87
  database_name = await self.database_resolver.resolve_id_to_name(database_id)
82
88
  return f"@database[{database_name or database_id}]"
83
89
 
90
+ async def _extract_data_source_mention_markdown(self, data_source_id: str) -> str:
91
+ data_source_name = await self.data_source_resolver.resolve_id_to_name(data_source_id)
92
+ return f"@datasource[{data_source_name or data_source_id}]"
93
+
84
94
  async def _extract_user_mention_markdown(self, user_id: str) -> str:
85
95
  user_name = await self.person_resolver.resolve_id_to_name(user_id)
86
96
  return f"@user[{user_name or user_id}]"
@@ -122,11 +132,13 @@ async def convert_rich_text_to_markdown(
122
132
  *,
123
133
  page_resolver: NameIdResolver | None = None,
124
134
  database_resolver: NameIdResolver | None = None,
135
+ data_source_resolver: NameIdResolver | None = None,
125
136
  person_resolver: NameIdResolver | None = None,
126
137
  ) -> str:
127
138
  converter = RichTextToMarkdownConverter(
128
139
  page_resolver=page_resolver,
129
140
  database_resolver=database_resolver,
141
+ data_source_resolver=data_source_resolver,
130
142
  person_resolver=person_resolver,
131
143
  )
132
144
  return await converter.to_markdown(rich_text)
@@ -35,5 +35,8 @@ class RichTextPatterns(StrEnum):
35
35
  DATABASE_MENTION = r"@database\[([^\]]+)\]"
36
36
  """Matches a Notion database mention by name or ID. Example: `@database[Tasks]`."""
37
37
 
38
+ DATASOURCE_MENTION = r"@datasource\[([^\]]+)\]"
39
+ """Matches a Notion data source mention by name or ID. Example: `@datasource[My Data]`."""
40
+
38
41
  USER_MENTION = r"@user\[([^\]]+)\]"
39
42
  """Matches a Notion user mention by name or ID. Example: `@user[Some Person]`."""