better-notion 2.1.1__tar.gz → 2.1.7__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 (203) hide show
  1. {better_notion-2.1.1 → better_notion-2.1.7}/PKG-INFO +1 -1
  2. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/schemas.py +19 -13
  3. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/workspace.py +199 -54
  4. {better_notion-2.1.1 → better_notion-2.1.7}/pyproject.toml +1 -1
  5. {better_notion-2.1.1 → better_notion-2.1.7}/.gitignore +0 -0
  6. {better_notion-2.1.1 → better_notion-2.1.7}/LICENSE +0 -0
  7. {better_notion-2.1.1 → better_notion-2.1.7}/README.md +0 -0
  8. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/__init__.py +0 -0
  9. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/__init__.py +0 -0
  10. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/client.py +0 -0
  11. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/collections/__init__.py +0 -0
  12. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/collections/blocks.py +0 -0
  13. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/collections/comments.py +0 -0
  14. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/collections/databases.py +0 -0
  15. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/collections/pages.py +0 -0
  16. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/collections/users.py +0 -0
  17. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/entities/__init__.py +0 -0
  18. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/entities/block.py +0 -0
  19. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/entities/comment.py +0 -0
  20. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/entities/database.py +0 -0
  21. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/entities/page.py +0 -0
  22. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/entities/user.py +0 -0
  23. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/errors.py +0 -0
  24. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/oauth.py +0 -0
  25. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/__init__.py +0 -0
  26. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/base.py +0 -0
  27. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/checkbox.py +0 -0
  28. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/date.py +0 -0
  29. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/email.py +0 -0
  30. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/number.py +0 -0
  31. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/phone.py +0 -0
  32. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/relation.py +0 -0
  33. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/rich_text.py +0 -0
  34. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/select.py +0 -0
  35. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/title.py +0 -0
  36. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/url.py +0 -0
  37. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/utils/__init__.py +0 -0
  38. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/utils/pagination.py +0 -0
  39. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/__init__.py +0 -0
  40. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/async_typer.py +0 -0
  41. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/__init__.py +0 -0
  42. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/auth.py +0 -0
  43. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/blocks.py +0 -0
  44. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/comments.py +0 -0
  45. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/config.py +0 -0
  46. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/databases.py +0 -0
  47. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/pages.py +0 -0
  48. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/plugins.py +0 -0
  49. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/search.py +0 -0
  50. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/update.py +0 -0
  51. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/users.py +0 -0
  52. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/workspace.py +0 -0
  53. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/config.py +0 -0
  54. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/display.py +0 -0
  55. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/docs/__init__.py +0 -0
  56. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/docs/base.py +0 -0
  57. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/docs/formatters.py +0 -0
  58. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/docs/registry.py +0 -0
  59. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/errors.py +0 -0
  60. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/main.py +0 -0
  61. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/markdown.py +0 -0
  62. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/response.py +0 -0
  63. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/utils/__init__.py +0 -0
  64. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/__init__.py +0 -0
  65. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/base/__init__.py +0 -0
  66. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/base/entity.py +0 -0
  67. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/cache/__init__.py +0 -0
  68. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/cache/cache.py +0 -0
  69. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/client.py +0 -0
  70. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/managers/__init__.py +0 -0
  71. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/managers/block_manager.py +0 -0
  72. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/managers/comment_manager.py +0 -0
  73. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/managers/database_manager.py +0 -0
  74. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/managers/page_manager.py +0 -0
  75. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/managers/user_manager.py +0 -0
  76. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/__init__.py +0 -0
  77. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/block.py +0 -0
  78. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/__init__.py +0 -0
  79. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/audio.py +0 -0
  80. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/bookmark.py +0 -0
  81. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/breadcrumb.py +0 -0
  82. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/bullet.py +0 -0
  83. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/callout.py +0 -0
  84. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/code.py +0 -0
  85. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/column.py +0 -0
  86. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/column_list.py +0 -0
  87. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/divider.py +0 -0
  88. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/embed.py +0 -0
  89. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/equation.py +0 -0
  90. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/file.py +0 -0
  91. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/heading.py +0 -0
  92. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/image.py +0 -0
  93. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/numbered.py +0 -0
  94. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/paragraph.py +0 -0
  95. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/pdf.py +0 -0
  96. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/quote.py +0 -0
  97. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/synced_block.py +0 -0
  98. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/table.py +0 -0
  99. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/table_row.py +0 -0
  100. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/template.py +0 -0
  101. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/todo.py +0 -0
  102. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/toggle.py +0 -0
  103. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/video.py +0 -0
  104. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/comment.py +0 -0
  105. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/database.py +0 -0
  106. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/page.py +0 -0
  107. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/user.py +0 -0
  108. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/parents/__init__.py +0 -0
  109. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/plugins.py +0 -0
  110. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/properties/__init__.py +0 -0
  111. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/properties/formula.py +0 -0
  112. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/properties/parsers.py +0 -0
  113. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/properties/relation.py +0 -0
  114. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/query/__init__.py +0 -0
  115. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/query/database_query.py +0 -0
  116. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/query/filter_translator.py +0 -0
  117. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/__init__.py +0 -0
  118. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/base.py +0 -0
  119. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/loader.py +0 -0
  120. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/__init__.py +0 -0
  121. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/agents.py +0 -0
  122. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/agents_cli.py +0 -0
  123. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/agents_schema.py +0 -0
  124. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/agents_sdk/__init__.py +0 -0
  125. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/agents_sdk/managers.py +0 -0
  126. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/agents_sdk/models.py +0 -0
  127. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/agents_sdk/plugin.py +0 -0
  128. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/productivity.py +0 -0
  129. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/state.py +0 -0
  130. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/__init__.py +0 -0
  131. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/__init__.py +0 -0
  132. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/auth.py +0 -0
  133. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/dependency_resolver.py +0 -0
  134. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/metadata.py +0 -0
  135. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/project_context.py +0 -0
  136. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/rbac.py +0 -0
  137. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/state_machine.py +0 -0
  138. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/helpers.py +0 -0
  139. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/retry.py +0 -0
  140. {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/validators.py +0 -0
  141. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/base/test_entity.py +0 -0
  142. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/cache/test_cache.py +0 -0
  143. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/models/__init__.py +0 -0
  144. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/models/blocks/test_advanced_blocks.py +0 -0
  145. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/models/test_block.py +0 -0
  146. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/models/test_database.py +0 -0
  147. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/models/test_database_bug.py +0 -0
  148. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/models/test_page.py +0 -0
  149. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/models/test_user.py +0 -0
  150. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/properties/test_formula.py +0 -0
  151. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/properties/test_parsers.py +0 -0
  152. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/properties/test_relation.py +0 -0
  153. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/query/test_database_query.py +0 -0
  154. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/query/test_filter_translator.py +0 -0
  155. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/test_client.py +0 -0
  156. {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/test_comment.py +0 -0
  157. {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/__init__.py +0 -0
  158. {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_auth.py +0 -0
  159. {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_dependency_resolver.py +0 -0
  160. {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_plugin.py +0 -0
  161. {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_project_context.py +0 -0
  162. {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_rbac.py +0 -0
  163. {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_schemas.py +0 -0
  164. {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_state_machine.py +0 -0
  165. {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_workspace.py +0 -0
  166. {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/__init__.py +0 -0
  167. {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_async_typer.py +0 -0
  168. {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_config.py +0 -0
  169. {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_display.py +0 -0
  170. {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_errors.py +0 -0
  171. {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_main.py +0 -0
  172. {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_pages_commands.py +0 -0
  173. {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_response.py +0 -0
  174. {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_update.py +0 -0
  175. {better_notion-2.1.1 → better_notion-2.1.7}/tests/conftest.py +0 -0
  176. {better_notion-2.1.1 → better_notion-2.1.7}/tests/integration/conftest.py +0 -0
  177. {better_notion-2.1.1 → better_notion-2.1.7}/tests/integration/test_blocks.py +0 -0
  178. {better_notion-2.1.1 → better_notion-2.1.7}/tests/integration/test_databases.py +0 -0
  179. {better_notion-2.1.1 → better_notion-2.1.7}/tests/integration/test_pages.py +0 -0
  180. {better_notion-2.1.1 → better_notion-2.1.7}/tests/integration/test_search.py +0 -0
  181. {better_notion-2.1.1 → better_notion-2.1.7}/tests/integration/test_users.py +0 -0
  182. {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/__init__.py +0 -0
  183. {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_agents_cli.py +0 -0
  184. {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_agents_sdk_integration.py +0 -0
  185. {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_agents_sdk_managers.py +0 -0
  186. {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_agents_sdk_models.py +0 -0
  187. {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_base.py +0 -0
  188. {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_loader.py +0 -0
  189. {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_marketplace.py +0 -0
  190. {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_plugin_commands_state.py +0 -0
  191. {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_productivity_plugin.py +0 -0
  192. {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_state.py +0 -0
  193. {better_notion-2.1.1 → better_notion-2.1.7}/tests/sdk/__init__.py +0 -0
  194. {better_notion-2.1.1 → better_notion-2.1.7}/tests/sdk/test_plugin_system.py +0 -0
  195. {better_notion-2.1.1 → better_notion-2.1.7}/tests/test_metadata.py +0 -0
  196. {better_notion-2.1.1 → better_notion-2.1.7}/tests/test_schema_command.py +0 -0
  197. {better_notion-2.1.1 → better_notion-2.1.7}/tests/unit/test_client.py +0 -0
  198. {better_notion-2.1.1 → better_notion-2.1.7}/tests/unit/test_collections.py +0 -0
  199. {better_notion-2.1.1 → better_notion-2.1.7}/tests/unit/test_entities.py +0 -0
  200. {better_notion-2.1.1 → better_notion-2.1.7}/tests/unit/test_errors.py +0 -0
  201. {better_notion-2.1.1 → better_notion-2.1.7}/tests/unit/test_helpers.py +0 -0
  202. {better_notion-2.1.1 → better_notion-2.1.7}/tests/unit/test_properties.py +0 -0
  203. {better_notion-2.1.1 → better_notion-2.1.7}/tests/utils/test_retry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: better-notion
3
- Version: 2.1.1
3
+ Version: 2.1.7
4
4
  Summary: A high-level Python SDK for the Notion API with developer experience in mind.
5
5
  Project-URL: Homepage, https://github.com/nesalia-inc/better-notion
6
6
  Project-URL: Documentation, https://github.com/nesalia-inc/better-notion#readme
@@ -421,7 +421,13 @@ class TaskSchema:
421
421
 
422
422
  @staticmethod
423
423
  def get_schema() -> Dict[str, Dict[str, Any]]:
424
- """Return Notion database schema for Tasks."""
424
+ """Return Notion database schema for Tasks.
425
+
426
+ Note: The following properties are NOT included here and will be added
427
+ after database creation via database.update():
428
+ - "Dependencies": Self-referential relation (requires database's own ID)
429
+ - "Related Work Issue": Relation to Work Issues (Work Issues created after Tasks)
430
+ """
425
431
  return {
426
432
  "Title": PropertyBuilder.title("Title"),
427
433
  "Version": PropertyBuilder.relation("Version"),
@@ -458,10 +464,6 @@ class TaskSchema:
458
464
  SelectOption.option("Low", "blue"),
459
465
  ],
460
466
  ),
461
- # Dependencies: Self-referential relation (will be updated after database creation)
462
- "Dependencies": PropertyBuilder.relation("Dependencies", dual_property=False),
463
- # Related Work Issue: Relation to Work Issues (will be updated after database creation)
464
- "Related Work Issue": PropertyBuilder.relation("Related Work Issue", dual_property=False),
465
467
  "Estimated Hours": PropertyBuilder.number("Estimated Hours"),
466
468
  "Actual Hours": PropertyBuilder.number("Actual Hours"),
467
469
  "Assignee": PropertyBuilder.people("Assignee"),
@@ -520,7 +522,13 @@ class WorkIssueSchema:
520
522
 
521
523
  @staticmethod
522
524
  def get_schema() -> Dict[str, Dict[str, Any]]:
523
- """Return Notion database schema for Work Issues."""
525
+ """Return Notion database schema for Work Issues.
526
+
527
+ Note: The following properties are NOT included here and will be added
528
+ after database creation via database.update():
529
+ - "Blocking Tasks": Relation to Tasks (added in post-processing)
530
+ - "Caused Incidents": Relation to Incidents (Incidents created after Work Issues)
531
+ """
524
532
  return {
525
533
  "Title": PropertyBuilder.title("Title"),
526
534
  "Project": PropertyBuilder.relation("Project"),
@@ -559,10 +567,6 @@ class WorkIssueSchema:
559
567
  "Proposed Solution": PropertyBuilder.text("Proposed Solution"),
560
568
  "Related Idea": PropertyBuilder.relation("Related Idea", dual_property=False),
561
569
  "Fix Tasks": PropertyBuilder.relation("Fix Tasks", dual_property=False),
562
- # Blocking Tasks: Tasks blocked by this work issue (will be updated after database creation)
563
- "Blocking Tasks": PropertyBuilder.relation("Blocking Tasks", dual_property=False),
564
- # Caused Incidents: Incidents caused by this work issue (will be updated after database creation)
565
- "Caused Incidents": PropertyBuilder.relation("Caused Incidents", dual_property=False),
566
570
  }
567
571
 
568
572
 
@@ -571,7 +575,11 @@ class IncidentSchema:
571
575
 
572
576
  @staticmethod
573
577
  def get_schema() -> Dict[str, Dict[str, Any]]:
574
- """Return Notion database schema for Incidents."""
578
+ """Return Notion database schema for Incidents.
579
+
580
+ Note: "Root Cause Work Issue" is NOT included here and will be added
581
+ after database creation via database.update() for consistency.
582
+ """
575
583
  return {
576
584
  "Title": PropertyBuilder.title("Title"),
577
585
  "Project": PropertyBuilder.relation("Project"),
@@ -605,8 +613,6 @@ class IncidentSchema:
605
613
  ],
606
614
  ),
607
615
  "Fix Task": PropertyBuilder.relation("Fix Task", dual_property=False),
608
- # Root Cause Work Issue: Relation to Work Issues (will be updated after database creation)
609
- "Root Cause Work Issue": PropertyBuilder.relation("Root Cause Work Issue", dual_property=False),
610
616
  "Root Cause": PropertyBuilder.text("Root Cause"),
611
617
  "Detected Date": PropertyBuilder.date("Detected Date"),
612
618
  "Resolved Date": PropertyBuilder.date("Resolved Date"),
@@ -93,10 +93,17 @@ class WorkspaceInitializer:
93
93
  logger.error(error_msg)
94
94
  raise Exception(error_msg) from e
95
95
 
96
- # Check for existing workspace unless skipped
97
- if not skip_detection:
98
- existing = await WorkspaceMetadata.detect_workspace(parent, self._client)
99
- if existing:
96
+ # Check for existing workspace
97
+ existing = await WorkspaceMetadata.detect_workspace(parent, self._client)
98
+
99
+ if existing:
100
+ if skip_detection:
101
+ # --reset flag: Delete all existing databases first
102
+ logger.warning(f"Reset mode: Deleting {len(existing.get('database_ids', {}))} existing databases...")
103
+ await self._delete_existing_databases(parent, existing.get("database_ids", {}))
104
+ logger.info("All existing databases deleted")
105
+ else:
106
+ # Normal mode: Raise error if workspace exists
100
107
  workspace_info = {
101
108
  "workspace_id": existing.get("workspace_id", "unknown"),
102
109
  "workspace_name": existing.get("workspace_name", workspace_name),
@@ -126,24 +133,64 @@ class WorkspaceInitializer:
126
133
  ("Incidents", "incidents", self._create_incidents_db),
127
134
  ]
128
135
 
129
- for display_name, key, create_func in databases_order:
130
- try:
131
- logger.info(f"Creating {display_name} database...")
132
- await create_func(parent)
133
- logger.info(f"✓ {display_name} database created: {self._database_ids[key]}")
134
- except Exception as e:
135
- error_msg = (
136
- f"Failed to create {display_name} database: {str(e)}\n"
137
- f"Databases created so far: {list(self._database_ids.keys())}\n"
138
- f"Parent page: {parent_page_id}\n"
139
- f"Workspace name: {workspace_name}"
140
- )
141
- logger.error(error_msg)
142
- raise Exception(error_msg) from e
136
+ try:
137
+ for display_name, key, create_func in databases_order:
138
+ try:
139
+ logger.info(f"Creating {display_name} database...")
140
+ await create_func(parent)
141
+ logger.info(f"✓ {display_name} database created: {self._database_ids[key]}")
142
+ except Exception as e:
143
+ # Clean up databases created so far
144
+ import traceback
145
+ import sys
146
+
147
+ # Log to stderr for visibility
148
+ print(f"\n{'='*60}", file=sys.stderr)
149
+ print(f"❌ FAILED TO CREATE: {display_name} database", file=sys.stderr)
150
+ print(f"{'='*60}", file=sys.stderr)
151
+ print(f"Error: {str(e)}", file=sys.stderr)
152
+ print(f"\nFull traceback:", file=sys.stderr)
153
+ traceback.print_exc(file=sys.stderr)
154
+
155
+ # Try to get more error details if available
156
+ error_details = str(e)
157
+ if hasattr(e, 'response') and hasattr(e.response, 'text'):
158
+ print(f"\nNotion API response:", file=sys.stderr)
159
+ print(f"{e.response.text}", file=sys.stderr)
160
+ error_details += f"\nNotion API response: {e.response.text}"
161
+
162
+ print(f"\nDatabases created before failure: {list(self._database_ids.keys())}", file=sys.stderr)
163
+ print(f"{'='*60}\n", file=sys.stderr)
164
+
165
+ logger.error(f"Failed to create {display_name} database: {str(e)}")
166
+ logger.error(f"Full traceback:\n{traceback.format_exc()}")
167
+
168
+ logger.warning(f"Cleaning up {len(self._database_ids)} databases that were created...")
169
+ await self._delete_existing_databases(parent, self._database_ids)
170
+
171
+ error_msg = (
172
+ f"Failed to create {display_name} database: {error_details}\n"
173
+ f"All partially created databases have been deleted.\n"
174
+ f"Parent page: {parent_page_id}\n"
175
+ f"Workspace name: {workspace_name}"
176
+ )
177
+ logger.error(error_msg)
178
+ raise Exception(error_msg) from e
179
+ except Exception as e:
180
+ # Re-raise the exception
181
+ raise e
143
182
 
144
183
  # Update cross-database relations that require both databases to exist
145
184
  await self._update_cross_database_relations()
146
185
 
186
+ # Add self-referential Dependencies relation to Tasks database
187
+ if "tasks" in self._database_ids:
188
+ await self._update_relation(
189
+ self._database_ids["tasks"],
190
+ "Dependencies",
191
+ self._database_ids["tasks"] # Self-reference
192
+ )
193
+
147
194
  # Save workspace metadata
148
195
  self.save_database_ids()
149
196
 
@@ -224,7 +271,7 @@ class WorkspaceInitializer:
224
271
  )
225
272
 
226
273
  async def _create_tasks_db(self, parent: Page) -> None:
227
- """Create Tasks database with relations to Versions (self-referencing for dependencies)."""
274
+ """Create Tasks database with relations to Versions."""
228
275
  schema = TaskSchema.get_schema()
229
276
 
230
277
  # Update relations with Versions database ID
@@ -234,8 +281,6 @@ class WorkspaceInitializer:
234
281
  "versions"
235
282
  ]
236
283
 
237
- # Tasks reference themselves for dependencies
238
- # Will be updated after database creation
239
284
  db = await self._client.databases.create(
240
285
  parent=parent,
241
286
  title="Tasks",
@@ -244,9 +289,6 @@ class WorkspaceInitializer:
244
289
 
245
290
  self._database_ids["tasks"] = db.id
246
291
 
247
- # Update self-referential relations
248
- await self._update_self_relations(db.id)
249
-
250
292
  # Update Versions database with reverse relation
251
293
  await self._add_reverse_relation(
252
294
  self._database_ids["versions"],
@@ -337,37 +379,51 @@ class WorkspaceInitializer:
337
379
  # This is a no-op but documents the intent
338
380
  pass
339
381
 
340
- async def _update_self_relations(self, database_id: str) -> None:
341
- """Update self-referential relations in Tasks database.
382
+ async def _delete_existing_databases(self, parent: Page, database_ids: dict) -> None:
383
+ """Delete all existing databases in the parent page.
342
384
 
343
- Note: The database was created with placeholder relations.
344
- This method updates them to point to themselves.
385
+ Args:
386
+ parent: Parent page
387
+ database_ids: Dict of database IDs to delete
345
388
  """
346
- # Get the current database schema
347
- db = await self._client.databases.get(database_id)
389
+ import asyncio
348
390
 
349
- # Update the Dependencies relation to point to itself
350
- schema = db.schema
351
- if "Dependencies" in schema:
352
- schema["Dependencies"]["relation"]["database_id"] = database_id
391
+ deletion_tasks = []
392
+ for db_name, db_id in database_ids.items():
393
+ if db_id:
394
+ logger.info(f"Deleting {db_name} database ({db_id})...")
395
+ deletion_tasks.append(self._delete_database(db_id))
353
396
 
354
- # Update the database schema via API
355
- await self._client._api._request(
356
- "PATCH",
357
- f"/databases/{database_id}",
358
- json={"properties": schema}
359
- )
397
+ # Delete all databases concurrently
398
+ if deletion_tasks:
399
+ await asyncio.gather(*deletion_tasks, return_exceptions=True)
360
400
 
361
- logger.info(f"Updated self-referential relations for Tasks database {database_id}")
401
+ async def _delete_database(self, database_id: str) -> None:
402
+ """Delete a single database.
403
+
404
+ Args:
405
+ database_id: ID of the database to delete
406
+ """
407
+ try:
408
+ await self._client._api._request(
409
+ "DELETE",
410
+ f"/blocks/{database_id}"
411
+ )
412
+ logger.info(f"Deleted database {database_id}")
413
+ except Exception as e:
414
+ logger.warning(f"Failed to delete database {database_id}: {str(e)}")
415
+ # Continue with other deletions even if this one fails
362
416
 
363
417
  async def _update_cross_database_relations(self) -> None:
364
418
  """Update cross-database relations after all databases are created.
365
419
 
366
- This updates:
367
- - Tasks: Related Work Issue -> Work Issues
368
- - Work Issues: Blocking Tasks -> Tasks
369
- - Work Issues: Caused Incidents -> Incidents
420
+ This adds:
421
+ - Tasks: Dependencies (self-referential), Related Work Issue -> Work Issues
422
+ - Work Issues: Blocking Tasks -> Tasks, Caused Incidents -> Incidents
370
423
  - Incidents: Root Cause Work Issue -> Work Issues
424
+
425
+ All these properties are added AFTER database creation because they
426
+ reference databases that may not exist yet during initial creation.
371
427
  """
372
428
  if "tasks" in self._database_ids:
373
429
  await self._update_relation(
@@ -403,7 +459,7 @@ class WorkspaceInitializer:
403
459
  property_name: str,
404
460
  target_database_id: Optional[str],
405
461
  ) -> None:
406
- """Update a relation property to point to the target database.
462
+ """Add or update a relation property to point to the target database.
407
463
 
408
464
  Args:
409
465
  database_id: Database to update
@@ -418,20 +474,109 @@ class WorkspaceInitializer:
418
474
  db = await self._client.databases.get(database_id)
419
475
  schema = db.schema
420
476
 
421
- # Update the relation property
477
+ # Prepare the new property schema
478
+ new_property_schema = None
479
+
422
480
  if property_name in schema:
423
- schema[property_name]["relation"]["database_id"] = target_database_id
481
+ # Property exists, just update the database_id
482
+ new_property_schema = schema[property_name]
483
+ new_property_schema["relation"]["database_id"] = target_database_id
484
+ else:
485
+ # Property doesn't exist, CREATE it
486
+ # This handles cases where the property couldn't be in the initial schema
487
+ if property_name == "Dependencies":
488
+ # Self-referential relation
489
+ new_property_schema = {
490
+ "relation": {
491
+ "database_id": database_id, # Self-reference
492
+ "type": "dual_property",
493
+ "dual_property": {
494
+ "synced_property_name": "Dependent Tasks",
495
+ "synced_property_type": "relation"
496
+ }
497
+ }
498
+ }
499
+ elif property_name == "Related Work Issue":
500
+ # Relation to Work Issues database
501
+ new_property_schema = {
502
+ "relation": {
503
+ "database_id": target_database_id,
504
+ "type": "dual_property",
505
+ "dual_property": {
506
+ "synced_property_name": "Related Tasks",
507
+ "synced_property_type": "relation"
508
+ }
509
+ }
510
+ }
511
+ elif property_name == "Blocking Tasks":
512
+ # Relation from Work Issues to Tasks
513
+ new_property_schema = {
514
+ "relation": {
515
+ "database_id": target_database_id,
516
+ "type": "dual_property",
517
+ "dual_property": {
518
+ "synced_property_name": "Blocked By Work Issue",
519
+ "synced_property_type": "relation"
520
+ }
521
+ }
522
+ }
523
+ elif property_name == "Caused Incidents":
524
+ # Relation from Work Issues to Incidents
525
+ new_property_schema = {
526
+ "relation": {
527
+ "database_id": target_database_id,
528
+ "type": "dual_property",
529
+ "dual_property": {
530
+ "synced_property_name": "Root Cause Work Issue",
531
+ "synced_property_type": "relation"
532
+ }
533
+ }
534
+ }
535
+ elif property_name == "Root Cause Work Issue":
536
+ # Relation from Incidents to Work Issues
537
+ new_property_schema = {
538
+ "relation": {
539
+ "database_id": target_database_id,
540
+ "type": "dual_property",
541
+ "dual_property": {
542
+ "synced_property_name": "Caused Incidents",
543
+ "synced_property_type": "relation"
544
+ }
545
+ }
546
+ }
547
+ else:
548
+ # Generic relation
549
+ new_property_schema = {
550
+ "relation": {
551
+ "database_id": target_database_id,
552
+ "dual_property": {}
553
+ }
554
+ }
424
555
 
425
- # Update the database schema via API
556
+ # Send ONLY the new/updated property, not the entire schema
557
+ # This is the key fix - Notion API expects only the changed properties
558
+ update_payload = {"properties": {property_name: new_property_schema}}
559
+
560
+ # Update the database schema via API
561
+ try:
426
562
  await self._client._api._request(
427
563
  "PATCH",
428
564
  f"/databases/{database_id}",
429
- json={"properties": schema}
565
+ json=update_payload
430
566
  )
431
-
432
- logger.info(f"Updated {property_name} relation to {target_database_id}")
433
- else:
434
- logger.warning(f"Property {property_name} not found in database {database_id}")
567
+ logger.info(f"Added/Updated {property_name} relation to {target_database_id}")
568
+ except Exception as e:
569
+ # Debug: Print schema details to see what's wrong
570
+ import sys
571
+ print(f"\n{'='*60}", file=sys.stderr)
572
+ print(f"❌ FAILED TO ADD PROPERTY: {property_name}", file=sys.stderr)
573
+ print(f"Database ID: {database_id}", file=sys.stderr)
574
+ print(f"Target: {target_database_id}", file=sys.stderr)
575
+ print(f"Payload being sent:", file=sys.stderr)
576
+ import json
577
+ print(json.dumps(update_payload, indent=2), file=sys.stderr)
578
+ print(f"{'='*60}\n", file=sys.stderr)
579
+ raise e
435
580
 
436
581
  def save_database_ids(self, path: Optional[Path] = None) -> None:
437
582
  """Save workspace metadata (database IDs and workspace info) to config file.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "better-notion"
3
- version = "2.1.1"
3
+ version = "2.1.7"
4
4
  description = "A high-level Python SDK for the Notion API with developer experience in mind."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
File without changes
File without changes
File without changes