better-notion 2.1.1__tar.gz → 2.1.5__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.
- {better_notion-2.1.1 → better_notion-2.1.5}/PKG-INFO +1 -1
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/utils/agents/schemas.py +19 -13
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/utils/agents/workspace.py +170 -56
- {better_notion-2.1.1 → better_notion-2.1.5}/pyproject.toml +1 -1
- {better_notion-2.1.1 → better_notion-2.1.5}/.gitignore +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/LICENSE +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/README.md +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/client.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/collections/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/collections/blocks.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/collections/comments.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/collections/databases.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/collections/pages.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/collections/users.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/entities/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/entities/block.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/entities/comment.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/entities/database.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/entities/page.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/entities/user.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/errors.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/oauth.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/properties/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/properties/base.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/properties/checkbox.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/properties/date.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/properties/email.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/properties/number.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/properties/phone.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/properties/relation.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/properties/rich_text.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/properties/select.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/properties/title.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/properties/url.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/utils/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_api/utils/pagination.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/async_typer.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/commands/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/commands/auth.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/commands/blocks.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/commands/comments.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/commands/config.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/commands/databases.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/commands/pages.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/commands/plugins.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/commands/search.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/commands/update.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/commands/users.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/commands/workspace.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/config.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/display.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/docs/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/docs/base.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/docs/formatters.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/docs/registry.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/errors.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/main.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/markdown.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/response.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_cli/utils/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/base/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/base/entity.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/cache/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/cache/cache.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/client.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/managers/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/managers/block_manager.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/managers/comment_manager.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/managers/database_manager.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/managers/page_manager.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/managers/user_manager.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/block.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/audio.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/bookmark.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/breadcrumb.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/bullet.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/callout.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/code.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/column.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/column_list.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/divider.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/embed.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/equation.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/file.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/heading.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/image.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/numbered.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/paragraph.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/pdf.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/quote.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/synced_block.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/table.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/table_row.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/template.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/todo.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/toggle.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/blocks/video.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/comment.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/database.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/page.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/models/user.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/parents/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/plugins.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/properties/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/properties/formula.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/properties/parsers.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/properties/relation.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/query/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/query/database_query.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/_sdk/query/filter_translator.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/plugins/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/plugins/base.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/plugins/loader.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/plugins/official/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/plugins/official/agents.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/plugins/official/agents_cli.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/plugins/official/agents_schema.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/plugins/official/agents_sdk/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/plugins/official/agents_sdk/managers.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/plugins/official/agents_sdk/models.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/plugins/official/agents_sdk/plugin.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/plugins/official/productivity.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/plugins/state.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/utils/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/utils/agents/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/utils/agents/auth.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/utils/agents/dependency_resolver.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/utils/agents/metadata.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/utils/agents/project_context.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/utils/agents/rbac.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/utils/agents/state_machine.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/utils/helpers.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/utils/retry.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/better_notion/utils/validators.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/base/test_entity.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/cache/test_cache.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/models/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/models/blocks/test_advanced_blocks.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/models/test_block.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/models/test_database.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/models/test_database_bug.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/models/test_page.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/models/test_user.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/properties/test_formula.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/properties/test_parsers.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/properties/test_relation.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/query/test_database_query.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/query/test_filter_translator.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/test_client.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/_sdk/test_comment.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/agents/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/agents/test_auth.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/agents/test_dependency_resolver.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/agents/test_plugin.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/agents/test_project_context.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/agents/test_rbac.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/agents/test_schemas.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/agents/test_state_machine.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/agents/test_workspace.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/cli/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/cli/test_async_typer.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/cli/test_config.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/cli/test_display.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/cli/test_errors.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/cli/test_main.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/cli/test_pages_commands.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/cli/test_response.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/cli/test_update.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/conftest.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/integration/conftest.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/integration/test_blocks.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/integration/test_databases.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/integration/test_pages.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/integration/test_search.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/integration/test_users.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/plugins/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/plugins/test_agents_cli.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/plugins/test_agents_sdk_integration.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/plugins/test_agents_sdk_managers.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/plugins/test_agents_sdk_models.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/plugins/test_base.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/plugins/test_loader.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/plugins/test_marketplace.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/plugins/test_plugin_commands_state.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/plugins/test_productivity_plugin.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/plugins/test_state.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/sdk/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/sdk/test_plugin_system.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/test_metadata.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/test_schema_command.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/unit/test_client.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/unit/test_collections.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/unit/test_entities.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/unit/test_errors.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/unit/test_helpers.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/tests/unit/test_properties.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.5}/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.
|
|
3
|
+
Version: 2.1.5
|
|
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
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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,50 @@ class WorkspaceInitializer:
|
|
|
126
133
|
("Incidents", "incidents", self._create_incidents_db),
|
|
127
134
|
]
|
|
128
135
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
f"
|
|
139
|
-
f"
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
+
logger.error(f"Failed to create {display_name} database: {str(e)}")
|
|
146
|
+
logger.error(f"Full traceback:\n{traceback.format_exc()}")
|
|
147
|
+
|
|
148
|
+
# Try to get more error details if available
|
|
149
|
+
error_details = str(e)
|
|
150
|
+
if hasattr(e, 'response') and hasattr(e.response, 'text'):
|
|
151
|
+
logger.error(f"Notion API response: {e.response.text}")
|
|
152
|
+
error_details += f"\nNotion API response: {e.response.text}"
|
|
153
|
+
|
|
154
|
+
logger.warning(f"Cleaning up {len(self._database_ids)} databases that were created...")
|
|
155
|
+
await self._delete_existing_databases(parent, self._database_ids)
|
|
156
|
+
|
|
157
|
+
error_msg = (
|
|
158
|
+
f"Failed to create {display_name} database: {error_details}\n"
|
|
159
|
+
f"All partially created databases have been deleted.\n"
|
|
160
|
+
f"Parent page: {parent_page_id}\n"
|
|
161
|
+
f"Workspace name: {workspace_name}"
|
|
162
|
+
)
|
|
163
|
+
logger.error(error_msg)
|
|
164
|
+
raise Exception(error_msg) from e
|
|
165
|
+
except Exception as e:
|
|
166
|
+
# Re-raise the exception
|
|
167
|
+
raise e
|
|
143
168
|
|
|
144
169
|
# Update cross-database relations that require both databases to exist
|
|
145
170
|
await self._update_cross_database_relations()
|
|
146
171
|
|
|
172
|
+
# Add self-referential Dependencies relation to Tasks database
|
|
173
|
+
if "tasks" in self._database_ids:
|
|
174
|
+
await self._update_relation(
|
|
175
|
+
self._database_ids["tasks"],
|
|
176
|
+
"Dependencies",
|
|
177
|
+
self._database_ids["tasks"] # Self-reference
|
|
178
|
+
)
|
|
179
|
+
|
|
147
180
|
# Save workspace metadata
|
|
148
181
|
self.save_database_ids()
|
|
149
182
|
|
|
@@ -224,7 +257,7 @@ class WorkspaceInitializer:
|
|
|
224
257
|
)
|
|
225
258
|
|
|
226
259
|
async def _create_tasks_db(self, parent: Page) -> None:
|
|
227
|
-
"""Create Tasks database with relations to Versions
|
|
260
|
+
"""Create Tasks database with relations to Versions."""
|
|
228
261
|
schema = TaskSchema.get_schema()
|
|
229
262
|
|
|
230
263
|
# Update relations with Versions database ID
|
|
@@ -234,8 +267,6 @@ class WorkspaceInitializer:
|
|
|
234
267
|
"versions"
|
|
235
268
|
]
|
|
236
269
|
|
|
237
|
-
# Tasks reference themselves for dependencies
|
|
238
|
-
# Will be updated after database creation
|
|
239
270
|
db = await self._client.databases.create(
|
|
240
271
|
parent=parent,
|
|
241
272
|
title="Tasks",
|
|
@@ -244,9 +275,6 @@ class WorkspaceInitializer:
|
|
|
244
275
|
|
|
245
276
|
self._database_ids["tasks"] = db.id
|
|
246
277
|
|
|
247
|
-
# Update self-referential relations
|
|
248
|
-
await self._update_self_relations(db.id)
|
|
249
|
-
|
|
250
278
|
# Update Versions database with reverse relation
|
|
251
279
|
await self._add_reverse_relation(
|
|
252
280
|
self._database_ids["versions"],
|
|
@@ -337,37 +365,51 @@ class WorkspaceInitializer:
|
|
|
337
365
|
# This is a no-op but documents the intent
|
|
338
366
|
pass
|
|
339
367
|
|
|
340
|
-
async def
|
|
341
|
-
"""
|
|
368
|
+
async def _delete_existing_databases(self, parent: Page, database_ids: dict) -> None:
|
|
369
|
+
"""Delete all existing databases in the parent page.
|
|
342
370
|
|
|
343
|
-
|
|
344
|
-
|
|
371
|
+
Args:
|
|
372
|
+
parent: Parent page
|
|
373
|
+
database_ids: Dict of database IDs to delete
|
|
345
374
|
"""
|
|
346
|
-
|
|
347
|
-
db = await self._client.databases.get(database_id)
|
|
375
|
+
import asyncio
|
|
348
376
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
377
|
+
deletion_tasks = []
|
|
378
|
+
for db_name, db_id in database_ids.items():
|
|
379
|
+
if db_id:
|
|
380
|
+
logger.info(f"Deleting {db_name} database ({db_id})...")
|
|
381
|
+
deletion_tasks.append(self._delete_database(db_id))
|
|
353
382
|
|
|
354
|
-
#
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
f"/databases/{database_id}",
|
|
358
|
-
json={"properties": schema}
|
|
359
|
-
)
|
|
383
|
+
# Delete all databases concurrently
|
|
384
|
+
if deletion_tasks:
|
|
385
|
+
await asyncio.gather(*deletion_tasks, return_exceptions=True)
|
|
360
386
|
|
|
361
|
-
|
|
387
|
+
async def _delete_database(self, database_id: str) -> None:
|
|
388
|
+
"""Delete a single database.
|
|
389
|
+
|
|
390
|
+
Args:
|
|
391
|
+
database_id: ID of the database to delete
|
|
392
|
+
"""
|
|
393
|
+
try:
|
|
394
|
+
await self._client._api._request(
|
|
395
|
+
"DELETE",
|
|
396
|
+
f"/blocks/{database_id}"
|
|
397
|
+
)
|
|
398
|
+
logger.info(f"Deleted database {database_id}")
|
|
399
|
+
except Exception as e:
|
|
400
|
+
logger.warning(f"Failed to delete database {database_id}: {str(e)}")
|
|
401
|
+
# Continue with other deletions even if this one fails
|
|
362
402
|
|
|
363
403
|
async def _update_cross_database_relations(self) -> None:
|
|
364
404
|
"""Update cross-database relations after all databases are created.
|
|
365
405
|
|
|
366
|
-
This
|
|
367
|
-
- Tasks: Related Work Issue -> Work Issues
|
|
368
|
-
- Work Issues: Blocking Tasks -> Tasks
|
|
369
|
-
- Work Issues: Caused Incidents -> Incidents
|
|
406
|
+
This adds:
|
|
407
|
+
- Tasks: Dependencies (self-referential), Related Work Issue -> Work Issues
|
|
408
|
+
- Work Issues: Blocking Tasks -> Tasks, Caused Incidents -> Incidents
|
|
370
409
|
- Incidents: Root Cause Work Issue -> Work Issues
|
|
410
|
+
|
|
411
|
+
All these properties are added AFTER database creation because they
|
|
412
|
+
reference databases that may not exist yet during initial creation.
|
|
371
413
|
"""
|
|
372
414
|
if "tasks" in self._database_ids:
|
|
373
415
|
await self._update_relation(
|
|
@@ -403,7 +445,7 @@ class WorkspaceInitializer:
|
|
|
403
445
|
property_name: str,
|
|
404
446
|
target_database_id: Optional[str],
|
|
405
447
|
) -> None:
|
|
406
|
-
"""
|
|
448
|
+
"""Add or update a relation property to point to the target database.
|
|
407
449
|
|
|
408
450
|
Args:
|
|
409
451
|
database_id: Database to update
|
|
@@ -418,20 +460,92 @@ class WorkspaceInitializer:
|
|
|
418
460
|
db = await self._client.databases.get(database_id)
|
|
419
461
|
schema = db.schema
|
|
420
462
|
|
|
421
|
-
#
|
|
463
|
+
# Add or update the relation property
|
|
464
|
+
# Some properties (like Dependencies, Related Work Issue) are added AFTER
|
|
465
|
+
# database creation, so they may not exist in the initial schema
|
|
422
466
|
if property_name in schema:
|
|
467
|
+
# Property exists, just update the database_id
|
|
423
468
|
schema[property_name]["relation"]["database_id"] = target_database_id
|
|
469
|
+
else:
|
|
470
|
+
# Property doesn't exist, ADD it
|
|
471
|
+
# This handles cases where the property couldn't be in the initial schema
|
|
472
|
+
if property_name == "Dependencies":
|
|
473
|
+
# Self-referential relation
|
|
474
|
+
schema[property_name] = {
|
|
475
|
+
"relation": {
|
|
476
|
+
"database_id": database_id, # Self-reference
|
|
477
|
+
"type": "dual_property",
|
|
478
|
+
"dual_property": {
|
|
479
|
+
"synced_property_name": "Dependent Tasks",
|
|
480
|
+
"synced_property_type": "relation"
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
elif property_name == "Related Work Issue":
|
|
485
|
+
# Relation to Work Issues database
|
|
486
|
+
schema[property_name] = {
|
|
487
|
+
"relation": {
|
|
488
|
+
"database_id": target_database_id,
|
|
489
|
+
"type": "dual_property",
|
|
490
|
+
"dual_property": {
|
|
491
|
+
"synced_property_name": "Related Tasks",
|
|
492
|
+
"synced_property_type": "relation"
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
elif property_name == "Blocking Tasks":
|
|
497
|
+
# Relation from Work Issues to Tasks
|
|
498
|
+
schema[property_name] = {
|
|
499
|
+
"relation": {
|
|
500
|
+
"database_id": target_database_id,
|
|
501
|
+
"type": "dual_property",
|
|
502
|
+
"dual_property": {
|
|
503
|
+
"synced_property_name": "Blocked By Work Issue",
|
|
504
|
+
"synced_property_type": "relation"
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
elif property_name == "Caused Incidents":
|
|
509
|
+
# Relation from Work Issues to Incidents
|
|
510
|
+
schema[property_name] = {
|
|
511
|
+
"relation": {
|
|
512
|
+
"database_id": target_database_id,
|
|
513
|
+
"type": "dual_property",
|
|
514
|
+
"dual_property": {
|
|
515
|
+
"synced_property_name": "Root Cause Work Issue",
|
|
516
|
+
"synced_property_type": "relation"
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
elif property_name == "Root Cause Work Issue":
|
|
521
|
+
# Relation from Incidents to Work Issues
|
|
522
|
+
schema[property_name] = {
|
|
523
|
+
"relation": {
|
|
524
|
+
"database_id": target_database_id,
|
|
525
|
+
"type": "dual_property",
|
|
526
|
+
"dual_property": {
|
|
527
|
+
"synced_property_name": "Caused Incidents",
|
|
528
|
+
"synced_property_type": "relation"
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
else:
|
|
533
|
+
# Generic relation
|
|
534
|
+
schema[property_name] = {
|
|
535
|
+
"relation": {
|
|
536
|
+
"database_id": target_database_id,
|
|
537
|
+
"dual_property": {}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
424
540
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
541
|
+
# Update the database schema via API
|
|
542
|
+
await self._client._api._request(
|
|
543
|
+
"PATCH",
|
|
544
|
+
f"/databases/{database_id}",
|
|
545
|
+
json={"properties": schema}
|
|
546
|
+
)
|
|
431
547
|
|
|
432
|
-
|
|
433
|
-
else:
|
|
434
|
-
logger.warning(f"Property {property_name} not found in database {database_id}")
|
|
548
|
+
logger.info(f"Added/Updated {property_name} relation to {target_database_id}")
|
|
435
549
|
|
|
436
550
|
def save_database_ids(self, path: Optional[Path] = None) -> None:
|
|
437
551
|
"""Save workspace metadata (database IDs and workspace info) to config file.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|