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.
- {better_notion-2.1.1 → better_notion-2.1.7}/PKG-INFO +1 -1
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/schemas.py +19 -13
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/workspace.py +199 -54
- {better_notion-2.1.1 → better_notion-2.1.7}/pyproject.toml +1 -1
- {better_notion-2.1.1 → better_notion-2.1.7}/.gitignore +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/LICENSE +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/README.md +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/client.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/collections/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/collections/blocks.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/collections/comments.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/collections/databases.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/collections/pages.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/collections/users.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/entities/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/entities/block.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/entities/comment.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/entities/database.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/entities/page.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/entities/user.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/errors.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/oauth.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/base.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/checkbox.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/date.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/email.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/number.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/phone.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/relation.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/rich_text.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/select.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/title.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/properties/url.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/utils/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_api/utils/pagination.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/async_typer.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/auth.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/blocks.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/comments.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/config.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/databases.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/pages.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/plugins.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/search.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/update.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/users.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/commands/workspace.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/config.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/display.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/docs/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/docs/base.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/docs/formatters.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/docs/registry.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/errors.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/main.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/markdown.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/response.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_cli/utils/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/base/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/base/entity.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/cache/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/cache/cache.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/client.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/managers/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/managers/block_manager.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/managers/comment_manager.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/managers/database_manager.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/managers/page_manager.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/managers/user_manager.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/block.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/audio.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/bookmark.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/breadcrumb.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/bullet.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/callout.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/code.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/column.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/column_list.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/divider.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/embed.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/equation.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/file.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/heading.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/image.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/numbered.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/paragraph.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/pdf.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/quote.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/synced_block.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/table.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/table_row.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/template.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/todo.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/toggle.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/blocks/video.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/comment.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/database.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/page.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/models/user.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/parents/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/plugins.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/properties/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/properties/formula.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/properties/parsers.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/properties/relation.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/query/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/query/database_query.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/_sdk/query/filter_translator.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/base.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/loader.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/agents.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/agents_cli.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/agents_schema.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/agents_sdk/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/agents_sdk/managers.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/agents_sdk/models.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/agents_sdk/plugin.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/official/productivity.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/plugins/state.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/auth.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/dependency_resolver.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/metadata.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/project_context.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/rbac.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/agents/state_machine.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/helpers.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/retry.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/better_notion/utils/validators.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/base/test_entity.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/cache/test_cache.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/models/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/models/blocks/test_advanced_blocks.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/models/test_block.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/models/test_database.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/models/test_database_bug.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/models/test_page.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/models/test_user.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/properties/test_formula.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/properties/test_parsers.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/properties/test_relation.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/query/test_database_query.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/query/test_filter_translator.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/test_client.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/_sdk/test_comment.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_auth.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_dependency_resolver.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_plugin.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_project_context.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_rbac.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_schemas.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_state_machine.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/agents/test_workspace.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_async_typer.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_config.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_display.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_errors.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_main.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_pages_commands.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_response.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/cli/test_update.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/conftest.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/integration/conftest.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/integration/test_blocks.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/integration/test_databases.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/integration/test_pages.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/integration/test_search.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/integration/test_users.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_agents_cli.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_agents_sdk_integration.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_agents_sdk_managers.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_agents_sdk_models.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_base.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_loader.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_marketplace.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_plugin_commands_state.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_productivity_plugin.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/plugins/test_state.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/sdk/__init__.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/sdk/test_plugin_system.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/test_metadata.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/test_schema_command.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/unit/test_client.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/unit/test_collections.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/unit/test_entities.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/unit/test_errors.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/unit/test_helpers.py +0 -0
- {better_notion-2.1.1 → better_notion-2.1.7}/tests/unit/test_properties.py +0 -0
- {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.
|
|
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
|
|
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,64 @@ class WorkspaceInitializer:
|
|
|
126
133
|
("Incidents", "incidents", self._create_incidents_db),
|
|
127
134
|
]
|
|
128
135
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
+
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
|
|
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
|
|
341
|
-
"""
|
|
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
|
-
|
|
344
|
-
|
|
385
|
+
Args:
|
|
386
|
+
parent: Parent page
|
|
387
|
+
database_ids: Dict of database IDs to delete
|
|
345
388
|
"""
|
|
346
|
-
|
|
347
|
-
db = await self._client.databases.get(database_id)
|
|
389
|
+
import asyncio
|
|
348
390
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
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
|
-
#
|
|
355
|
-
|
|
356
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
"""
|
|
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
|
-
#
|
|
477
|
+
# Prepare the new property schema
|
|
478
|
+
new_property_schema = None
|
|
479
|
+
|
|
422
480
|
if property_name in schema:
|
|
423
|
-
|
|
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
|
-
|
|
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=
|
|
565
|
+
json=update_payload
|
|
430
566
|
)
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
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.
|
|
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
|