notionary 0.2.27__py3-none-any.whl → 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- notionary/__init__.py +5 -20
- notionary/blocks/__init__.py +4 -4
- notionary/blocks/client.py +90 -216
- notionary/blocks/enums.py +167 -0
- notionary/blocks/rich_text/markdown_rich_text_converter.py +280 -0
- notionary/blocks/rich_text/models.py +178 -0
- notionary/blocks/rich_text/name_id_resolver/__init__.py +13 -0
- notionary/blocks/rich_text/name_id_resolver/data_source.py +32 -0
- notionary/blocks/rich_text/name_id_resolver/database.py +31 -0
- notionary/blocks/rich_text/name_id_resolver/page.py +34 -0
- notionary/blocks/rich_text/name_id_resolver/person.py +37 -0
- notionary/blocks/rich_text/name_id_resolver/port.py +11 -0
- notionary/blocks/rich_text/rich_text_markdown_converter.py +144 -0
- notionary/blocks/rich_text/rich_text_patterns.py +42 -0
- notionary/blocks/schemas.py +778 -0
- notionary/comments/__init__.py +1 -22
- notionary/comments/client.py +52 -187
- notionary/comments/factory.py +38 -0
- notionary/comments/models.py +5 -127
- notionary/comments/schemas.py +240 -0
- notionary/comments/service.py +34 -0
- notionary/data_source/http/client.py +11 -0
- notionary/data_source/http/data_source_instance_client.py +104 -0
- notionary/data_source/properties/schemas.py +402 -0
- notionary/data_source/query/builder.py +448 -0
- notionary/data_source/query/resolver.py +114 -0
- notionary/data_source/query/schema.py +302 -0
- notionary/data_source/query/validator.py +73 -0
- notionary/data_source/schema/registry.py +104 -0
- notionary/data_source/schema/service.py +136 -0
- notionary/data_source/schemas.py +27 -0
- notionary/data_source/service.py +377 -0
- notionary/database/client.py +30 -135
- notionary/database/database_metadata_update_client.py +19 -0
- notionary/database/schemas.py +29 -0
- notionary/database/service.py +168 -0
- notionary/exceptions/__init__.py +33 -0
- notionary/exceptions/api.py +41 -0
- notionary/exceptions/base.py +2 -0
- notionary/exceptions/block_parsing.py +16 -0
- notionary/exceptions/data_source/__init__.py +6 -0
- notionary/exceptions/data_source/builder.py +182 -0
- notionary/exceptions/data_source/properties.py +34 -0
- notionary/exceptions/properties.py +58 -0
- notionary/exceptions/search.py +57 -0
- notionary/file_upload/client.py +18 -30
- notionary/file_upload/models.py +7 -8
- notionary/file_upload/{notion_file_upload.py → service.py} +29 -64
- notionary/http/client.py +204 -0
- notionary/http/models.py +50 -0
- notionary/page/blocks/client.py +1 -0
- notionary/page/content/factory.py +73 -0
- notionary/page/content/markdown/__init__.py +5 -0
- notionary/page/content/markdown/builder.py +226 -0
- notionary/page/content/markdown/nodes/__init__.py +52 -0
- notionary/page/content/markdown/nodes/audio.py +23 -0
- notionary/page/content/markdown/nodes/base.py +12 -0
- notionary/page/content/markdown/nodes/bookmark.py +25 -0
- notionary/page/content/markdown/nodes/breadcrumb.py +14 -0
- notionary/page/content/markdown/nodes/bulleted_list.py +41 -0
- notionary/page/content/markdown/nodes/callout.py +34 -0
- notionary/page/content/markdown/nodes/code.py +28 -0
- notionary/page/content/markdown/nodes/columns.py +69 -0
- notionary/page/content/markdown/nodes/container.py +64 -0
- notionary/page/content/markdown/nodes/divider.py +14 -0
- notionary/page/content/markdown/nodes/embed.py +23 -0
- notionary/page/content/markdown/nodes/equation.py +19 -0
- notionary/page/content/markdown/nodes/file.py +23 -0
- notionary/page/content/markdown/nodes/heading.py +36 -0
- notionary/page/content/markdown/nodes/image.py +23 -0
- notionary/page/content/markdown/nodes/mixins/__init__.py +5 -0
- notionary/page/content/markdown/nodes/mixins/caption.py +12 -0
- notionary/page/content/markdown/nodes/numbered_list.py +38 -0
- notionary/page/content/markdown/nodes/paragraph.py +14 -0
- notionary/page/content/markdown/nodes/pdf.py +23 -0
- notionary/page/content/markdown/nodes/quote.py +27 -0
- notionary/page/content/markdown/nodes/space.py +14 -0
- notionary/page/content/markdown/nodes/table.py +45 -0
- notionary/page/content/markdown/nodes/table_of_contents.py +14 -0
- notionary/page/content/markdown/nodes/todo.py +38 -0
- notionary/page/content/markdown/nodes/toggle.py +27 -0
- notionary/page/content/markdown/nodes/video.py +23 -0
- notionary/page/content/parser/context.py +126 -0
- notionary/page/content/parser/factory.py +210 -0
- notionary/page/content/parser/parsers/__init__.py +58 -0
- notionary/page/content/parser/parsers/audio.py +40 -0
- notionary/page/content/parser/parsers/base.py +30 -0
- notionary/page/content/parser/parsers/bookmark.py +33 -0
- notionary/page/content/parser/parsers/breadcrumb.py +33 -0
- notionary/page/content/parser/parsers/bulleted_list.py +85 -0
- notionary/page/content/parser/parsers/callout.py +100 -0
- notionary/page/content/parser/parsers/caption.py +55 -0
- notionary/page/content/parser/parsers/code.py +81 -0
- notionary/page/content/parser/parsers/column.py +76 -0
- notionary/page/content/parser/parsers/column_list.py +81 -0
- notionary/page/content/parser/parsers/divider.py +33 -0
- notionary/page/content/parser/parsers/embed.py +33 -0
- notionary/page/content/parser/parsers/equation.py +65 -0
- notionary/page/content/parser/parsers/file.py +42 -0
- notionary/page/content/parser/parsers/heading.py +115 -0
- notionary/page/content/parser/parsers/image.py +42 -0
- notionary/page/content/parser/parsers/numbered_list.py +89 -0
- notionary/page/content/parser/parsers/paragraph.py +37 -0
- notionary/page/content/parser/parsers/pdf.py +42 -0
- notionary/page/content/parser/parsers/quote.py +125 -0
- notionary/page/content/parser/parsers/space.py +41 -0
- notionary/page/content/parser/parsers/table.py +144 -0
- notionary/page/content/parser/parsers/table_of_contents.py +32 -0
- notionary/page/content/parser/parsers/todo.py +96 -0
- notionary/page/content/parser/parsers/toggle.py +70 -0
- notionary/page/content/parser/parsers/video.py +42 -0
- notionary/page/content/parser/post_processing/handlers/__init__.py +5 -0
- notionary/page/content/parser/post_processing/handlers/rich_text_length.py +95 -0
- notionary/page/content/parser/post_processing/handlers/rich_text_length_truncation.py +114 -0
- notionary/page/content/parser/post_processing/port.py +9 -0
- notionary/page/content/parser/post_processing/service.py +16 -0
- notionary/page/content/parser/pre_processsing/handlers/__init__.py +11 -0
- notionary/page/content/parser/pre_processsing/handlers/column_syntax.py +130 -0
- notionary/page/content/parser/pre_processsing/handlers/indentation.py +84 -0
- notionary/page/content/parser/pre_processsing/handlers/port.py +7 -0
- notionary/page/content/parser/pre_processsing/handlers/whitespace.py +73 -0
- notionary/page/content/parser/pre_processsing/service.py +15 -0
- notionary/page/content/parser/service.py +78 -0
- notionary/page/content/renderer/context.py +51 -0
- notionary/page/content/renderer/factory.py +231 -0
- notionary/page/content/renderer/post_processing/handlers/__init__.py +5 -0
- notionary/page/content/renderer/post_processing/handlers/numbered_list.py +156 -0
- notionary/page/content/renderer/post_processing/port.py +7 -0
- notionary/page/content/renderer/post_processing/service.py +15 -0
- notionary/page/content/renderer/renderers/__init__.py +55 -0
- notionary/page/content/renderer/renderers/audio.py +31 -0
- notionary/page/content/renderer/renderers/base.py +31 -0
- notionary/page/content/renderer/renderers/bookmark.py +25 -0
- notionary/page/content/renderer/renderers/breadcrumb.py +21 -0
- notionary/page/content/renderer/renderers/bulleted_list.py +48 -0
- notionary/page/content/renderer/renderers/callout.py +50 -0
- notionary/page/content/renderer/renderers/captioned_block.py +58 -0
- notionary/page/content/renderer/renderers/code.py +34 -0
- notionary/page/content/renderer/renderers/column.py +53 -0
- notionary/page/content/renderer/renderers/column_list.py +44 -0
- notionary/page/content/renderer/renderers/divider.py +22 -0
- notionary/page/content/renderer/renderers/embed.py +25 -0
- notionary/page/content/renderer/renderers/equation.py +37 -0
- notionary/page/content/renderer/renderers/fallback.py +24 -0
- notionary/page/content/renderer/renderers/file.py +40 -0
- notionary/page/content/renderer/renderers/heading.py +95 -0
- notionary/page/content/renderer/renderers/image.py +31 -0
- notionary/page/content/renderer/renderers/numbered_list.py +42 -0
- notionary/page/content/renderer/renderers/paragraph.py +40 -0
- notionary/page/content/renderer/renderers/pdf.py +31 -0
- notionary/page/content/renderer/renderers/quote.py +49 -0
- notionary/page/content/renderer/renderers/table.py +115 -0
- notionary/page/content/renderer/renderers/table_of_contents.py +26 -0
- notionary/page/content/renderer/renderers/table_row.py +17 -0
- notionary/page/content/renderer/renderers/todo.py +56 -0
- notionary/page/content/renderer/renderers/toggle.py +52 -0
- notionary/page/content/renderer/renderers/video.py +31 -0
- notionary/page/content/renderer/service.py +50 -0
- notionary/page/content/service.py +68 -0
- notionary/page/content/syntax/__init__.py +4 -0
- notionary/page/content/syntax/grammar.py +10 -0
- notionary/page/content/syntax/models.py +66 -0
- notionary/page/content/syntax/registry.py +393 -0
- notionary/page/page_context.py +7 -16
- notionary/page/page_http_client.py +15 -0
- notionary/page/page_metadata_update_client.py +19 -0
- notionary/page/properties/client.py +144 -0
- notionary/page/properties/factory.py +26 -0
- notionary/page/properties/models.py +308 -0
- notionary/page/properties/service.py +261 -0
- notionary/page/schemas.py +13 -0
- notionary/page/service.py +225 -0
- notionary/shared/entity/client.py +29 -0
- notionary/shared/entity/dto_parsers.py +53 -0
- notionary/shared/entity/entity_metadata_update_client.py +41 -0
- notionary/shared/entity/schemas.py +45 -0
- notionary/shared/entity/service.py +171 -0
- notionary/shared/models/cover.py +20 -0
- notionary/shared/models/file.py +21 -0
- notionary/shared/models/icon.py +28 -0
- notionary/shared/models/parent.py +41 -0
- notionary/shared/properties/type.py +30 -0
- notionary/shared/typings.py +3 -0
- notionary/user/__init__.py +4 -8
- notionary/user/base.py +138 -0
- notionary/user/bot.py +70 -0
- notionary/user/client.py +22 -111
- notionary/user/person.py +41 -0
- notionary/user/schemas.py +67 -0
- notionary/user/service.py +65 -0
- notionary/utils/date.py +51 -0
- notionary/utils/decorators.py +122 -0
- notionary/utils/fuzzy.py +68 -0
- notionary/utils/mixins/logging.py +58 -0
- notionary/utils/pagination.py +100 -0
- notionary/utils/uuid_utils.py +20 -0
- notionary/workspace/__init__.py +4 -0
- notionary/workspace/client.py +62 -0
- notionary/workspace/query/__init__.py +3 -0
- notionary/workspace/query/builder.py +60 -0
- notionary/workspace/query/models.py +61 -0
- notionary/workspace/query/service.py +100 -0
- notionary/workspace/schemas.py +21 -0
- notionary/workspace/service.py +116 -0
- notionary-0.3.0.dist-info/METADATA +201 -0
- notionary-0.3.0.dist-info/RECORD +209 -0
- {notionary-0.2.27.dist-info → notionary-0.3.0.dist-info}/WHEEL +1 -1
- {notionary-0.2.27.dist-info → notionary-0.3.0.dist-info/licenses}/LICENSE +9 -9
- notionary/base_notion_client.py +0 -219
- notionary/blocks/_bootstrap.py +0 -271
- notionary/blocks/audio/__init__.py +0 -11
- notionary/blocks/audio/audio_element.py +0 -158
- notionary/blocks/audio/audio_markdown_node.py +0 -24
- notionary/blocks/audio/audio_models.py +0 -10
- notionary/blocks/base_block_element.py +0 -42
- notionary/blocks/bookmark/__init__.py +0 -12
- notionary/blocks/bookmark/bookmark_element.py +0 -83
- notionary/blocks/bookmark/bookmark_markdown_node.py +0 -28
- notionary/blocks/bookmark/bookmark_models.py +0 -15
- notionary/blocks/breadcrumbs/__init__.py +0 -15
- notionary/blocks/breadcrumbs/breadcrumb_element.py +0 -39
- notionary/blocks/breadcrumbs/breadcrumb_markdown_node.py +0 -13
- notionary/blocks/breadcrumbs/breadcrumb_models.py +0 -12
- notionary/blocks/bulleted_list/__init__.py +0 -15
- notionary/blocks/bulleted_list/bulleted_list_element.py +0 -74
- notionary/blocks/bulleted_list/bulleted_list_markdown_node.py +0 -20
- notionary/blocks/bulleted_list/bulleted_list_models.py +0 -17
- notionary/blocks/callout/__init__.py +0 -12
- notionary/blocks/callout/callout_element.py +0 -99
- notionary/blocks/callout/callout_markdown_node.py +0 -19
- notionary/blocks/callout/callout_models.py +0 -33
- notionary/blocks/child_database/__init__.py +0 -14
- notionary/blocks/child_database/child_database_element.py +0 -59
- notionary/blocks/child_database/child_database_models.py +0 -12
- notionary/blocks/child_page/__init__.py +0 -9
- notionary/blocks/child_page/child_page_element.py +0 -94
- notionary/blocks/child_page/child_page_models.py +0 -12
- notionary/blocks/code/__init__.py +0 -11
- notionary/blocks/code/code_element.py +0 -149
- notionary/blocks/code/code_markdown_node.py +0 -80
- notionary/blocks/code/code_models.py +0 -94
- notionary/blocks/column/__init__.py +0 -25
- notionary/blocks/column/column_element.py +0 -65
- notionary/blocks/column/column_list_element.py +0 -52
- notionary/blocks/column/column_list_markdown_node.py +0 -34
- notionary/blocks/column/column_markdown_node.py +0 -42
- notionary/blocks/column/column_models.py +0 -26
- notionary/blocks/divider/__init__.py +0 -12
- notionary/blocks/divider/divider_element.py +0 -41
- notionary/blocks/divider/divider_markdown_node.py +0 -11
- notionary/blocks/divider/divider_models.py +0 -12
- notionary/blocks/embed/__init__.py +0 -12
- notionary/blocks/embed/embed_element.py +0 -98
- notionary/blocks/embed/embed_markdown_node.py +0 -19
- notionary/blocks/embed/embed_models.py +0 -14
- notionary/blocks/equation/__init__.py +0 -13
- notionary/blocks/equation/equation_element.py +0 -133
- notionary/blocks/equation/equation_element_markdown_node.py +0 -23
- notionary/blocks/equation/equation_models.py +0 -11
- notionary/blocks/file/__init__.py +0 -23
- notionary/blocks/file/file_element.py +0 -133
- notionary/blocks/file/file_element_markdown_node.py +0 -24
- notionary/blocks/file/file_element_models.py +0 -39
- notionary/blocks/heading/__init__.py +0 -19
- notionary/blocks/heading/heading_element.py +0 -112
- notionary/blocks/heading/heading_markdown_node.py +0 -16
- notionary/blocks/heading/heading_models.py +0 -29
- notionary/blocks/image_block/__init__.py +0 -11
- notionary/blocks/image_block/image_element.py +0 -130
- notionary/blocks/image_block/image_markdown_node.py +0 -25
- notionary/blocks/image_block/image_models.py +0 -10
- notionary/blocks/markdown/markdown_builder.py +0 -525
- notionary/blocks/markdown/markdown_document_model.py +0 -0
- notionary/blocks/markdown/markdown_node.py +0 -25
- notionary/blocks/mixins/captions/__init__.py +0 -4
- notionary/blocks/mixins/captions/caption_markdown_node_mixin.py +0 -31
- notionary/blocks/mixins/captions/caption_mixin.py +0 -92
- notionary/blocks/mixins/file_upload/__init__.py +0 -3
- notionary/blocks/mixins/file_upload/file_upload_mixin.py +0 -320
- notionary/blocks/models.py +0 -174
- notionary/blocks/numbered_list/__init__.py +0 -16
- notionary/blocks/numbered_list/numbered_list_element.py +0 -65
- notionary/blocks/numbered_list/numbered_list_markdown_node.py +0 -17
- notionary/blocks/numbered_list/numbered_list_models.py +0 -17
- notionary/blocks/paragraph/__init__.py +0 -15
- notionary/blocks/paragraph/paragraph_element.py +0 -58
- notionary/blocks/paragraph/paragraph_markdown_node.py +0 -16
- notionary/blocks/paragraph/paragraph_models.py +0 -16
- notionary/blocks/pdf/__init__.py +0 -11
- notionary/blocks/pdf/pdf_element.py +0 -146
- notionary/blocks/pdf/pdf_markdown_node.py +0 -24
- notionary/blocks/pdf/pdf_models.py +0 -11
- notionary/blocks/quote/__init__.py +0 -14
- notionary/blocks/quote/quote_element.py +0 -75
- notionary/blocks/quote/quote_markdown_node.py +0 -16
- notionary/blocks/quote/quote_models.py +0 -18
- notionary/blocks/registry/__init__.py +0 -3
- notionary/blocks/registry/block_registry.py +0 -150
- notionary/blocks/rich_text/__init__.py +0 -33
- notionary/blocks/rich_text/rich_text_models.py +0 -221
- notionary/blocks/rich_text/text_inline_formatter.py +0 -456
- notionary/blocks/syntax_prompt_builder.py +0 -137
- notionary/blocks/table/__init__.py +0 -19
- notionary/blocks/table/table_element.py +0 -225
- notionary/blocks/table/table_markdown_node.py +0 -42
- notionary/blocks/table/table_models.py +0 -28
- notionary/blocks/table_of_contents/__init__.py +0 -17
- notionary/blocks/table_of_contents/table_of_contents_element.py +0 -80
- notionary/blocks/table_of_contents/table_of_contents_markdown_node.py +0 -21
- notionary/blocks/table_of_contents/table_of_contents_models.py +0 -18
- notionary/blocks/todo/__init__.py +0 -12
- notionary/blocks/todo/todo_element.py +0 -81
- notionary/blocks/todo/todo_markdown_node.py +0 -21
- notionary/blocks/todo/todo_models.py +0 -18
- notionary/blocks/toggle/__init__.py +0 -12
- notionary/blocks/toggle/toggle_element.py +0 -112
- notionary/blocks/toggle/toggle_markdown_node.py +0 -31
- notionary/blocks/toggle/toggle_models.py +0 -17
- notionary/blocks/toggleable_heading/__init__.py +0 -11
- notionary/blocks/toggleable_heading/toggleable_heading_element.py +0 -115
- notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +0 -34
- notionary/blocks/types.py +0 -130
- notionary/blocks/video/__init__.py +0 -11
- notionary/blocks/video/video_element.py +0 -187
- notionary/blocks/video/video_element_models.py +0 -10
- notionary/blocks/video/video_markdown_node.py +0 -26
- notionary/database/__init__.py +0 -4
- notionary/database/database.py +0 -480
- notionary/database/database_filter_builder.py +0 -173
- notionary/database/database_provider.py +0 -227
- notionary/database/exceptions.py +0 -13
- notionary/database/models.py +0 -337
- notionary/database/notion_database.py +0 -487
- notionary/file_upload/__init__.py +0 -7
- notionary/page/client.py +0 -124
- notionary/page/markdown_whitespace_processor.py +0 -129
- notionary/page/models.py +0 -322
- notionary/page/notion_page.py +0 -712
- notionary/page/page_content_deleting_service.py +0 -117
- notionary/page/page_content_writer.py +0 -80
- notionary/page/property_formatter.py +0 -99
- notionary/page/reader/handler/__init__.py +0 -19
- notionary/page/reader/handler/base_block_renderer.py +0 -44
- notionary/page/reader/handler/block_processing_context.py +0 -35
- notionary/page/reader/handler/block_rendering_context.py +0 -48
- notionary/page/reader/handler/column_list_renderer.py +0 -51
- notionary/page/reader/handler/column_renderer.py +0 -60
- notionary/page/reader/handler/equation_renderer.py +0 -0
- notionary/page/reader/handler/line_renderer.py +0 -73
- notionary/page/reader/handler/numbered_list_renderer.py +0 -85
- notionary/page/reader/handler/toggle_renderer.py +0 -69
- notionary/page/reader/handler/toggleable_heading_renderer.py +0 -89
- notionary/page/reader/page_content_retriever.py +0 -81
- notionary/page/search_filter_builder.py +0 -132
- notionary/page/utils.py +0 -60
- notionary/page/writer/handler/__init__.py +0 -24
- notionary/page/writer/handler/code_handler.py +0 -72
- notionary/page/writer/handler/column_handler.py +0 -141
- notionary/page/writer/handler/column_list_handler.py +0 -139
- notionary/page/writer/handler/equation_handler.py +0 -74
- notionary/page/writer/handler/line_handler.py +0 -35
- notionary/page/writer/handler/line_processing_context.py +0 -54
- notionary/page/writer/handler/regular_line_handler.py +0 -86
- notionary/page/writer/handler/table_handler.py +0 -66
- notionary/page/writer/handler/toggle_handler.py +0 -159
- notionary/page/writer/handler/toggleable_heading_handler.py +0 -174
- notionary/page/writer/markdown_to_notion_converter.py +0 -139
- notionary/page/writer/markdown_to_notion_converter_context.py +0 -30
- notionary/page/writer/markdown_to_notion_text_length_post_processor.py +0 -0
- notionary/page/writer/notion_text_length_processor.py +0 -150
- notionary/schemas/__init__.py +0 -3
- notionary/schemas/base.py +0 -73
- notionary/shared/__init__.py +0 -3
- notionary/shared/name_to_id_resolver.py +0 -203
- notionary/telemetry/__init__.py +0 -19
- notionary/telemetry/service.py +0 -136
- notionary/telemetry/views.py +0 -73
- notionary/user/base_notion_user.py +0 -53
- notionary/user/models.py +0 -84
- notionary/user/notion_bot_user.py +0 -226
- notionary/user/notion_user.py +0 -255
- notionary/user/notion_user_manager.py +0 -101
- notionary/util/__init__.py +0 -15
- notionary/util/concurrency_limiter.py +0 -0
- notionary/util/factory_decorator.py +0 -0
- notionary/util/factory_only.py +0 -37
- notionary/util/fuzzy.py +0 -75
- notionary/util/logging_mixin.py +0 -59
- notionary/util/page_id_utils.py +0 -27
- notionary/util/singleton.py +0 -18
- notionary/util/singleton_metaclass.py +0 -22
- notionary/workspace.py +0 -105
- notionary-0.2.27.dist-info/METADATA +0 -270
- notionary-0.2.27.dist-info/RECORD +0 -202
- /notionary/{database → user}/factory.py +0 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
from typing import Annotated, Any, Literal, TypeVar
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
from notionary.blocks.rich_text.models import RichText
|
|
7
|
+
from notionary.shared.properties.type import PropertyType
|
|
8
|
+
from notionary.shared.typings import JsonDict
|
|
9
|
+
from notionary.user.schemas import PersonUserResponseDto, UserResponseDto
|
|
10
|
+
|
|
11
|
+
# ============================================================================
|
|
12
|
+
# Base Models
|
|
13
|
+
# ============================================================================
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PageProperty(BaseModel):
|
|
17
|
+
id: str
|
|
18
|
+
type: str
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class StatusOption(BaseModel):
|
|
22
|
+
id: str
|
|
23
|
+
name: str
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SelectOption(BaseModel):
|
|
27
|
+
id: str | None = None
|
|
28
|
+
name: str
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class RelationItem(BaseModel):
|
|
32
|
+
id: str
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class DateValue(BaseModel):
|
|
36
|
+
start: str
|
|
37
|
+
end: str | None = None
|
|
38
|
+
time_zone: str | None = None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# ============================================================================
|
|
42
|
+
# File Models
|
|
43
|
+
# ============================================================================
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class FileType(StrEnum):
|
|
47
|
+
EXTERNAL = "external"
|
|
48
|
+
FILE = "file"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class ExternalFile(BaseModel):
|
|
52
|
+
"""External file hosted outside of Notion."""
|
|
53
|
+
|
|
54
|
+
url: str
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class NotionFile(BaseModel):
|
|
58
|
+
"""File uploaded to Notion with expiration."""
|
|
59
|
+
|
|
60
|
+
url: str
|
|
61
|
+
expiry_time: str
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class FileObject(BaseModel):
|
|
65
|
+
"""File object can be external or uploaded to Notion."""
|
|
66
|
+
|
|
67
|
+
name: str
|
|
68
|
+
type: FileType
|
|
69
|
+
external: ExternalFile | None = None
|
|
70
|
+
file: NotionFile | None = None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# ============================================================================
|
|
74
|
+
# Formula Models
|
|
75
|
+
# ============================================================================
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class FormulaValueType(StrEnum):
|
|
79
|
+
BOOLEAN = "boolean"
|
|
80
|
+
DATE = "date"
|
|
81
|
+
NUMBER = "number"
|
|
82
|
+
STRING = "string"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class FormulaValue(BaseModel):
|
|
86
|
+
type: FormulaValueType
|
|
87
|
+
boolean: bool | None = None
|
|
88
|
+
date: DateValue | None = None
|
|
89
|
+
number: float | None = None
|
|
90
|
+
string: str | None = None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# ============================================================================
|
|
94
|
+
# Rollup Models
|
|
95
|
+
# ============================================================================
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class RollupValueType(StrEnum):
|
|
99
|
+
NUMBER = "number"
|
|
100
|
+
DATE = "date"
|
|
101
|
+
ARRAY = "array"
|
|
102
|
+
INCOMPLETE = "incomplete"
|
|
103
|
+
UNSUPPORTED = "unsupported"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class RollupValue(BaseModel):
|
|
107
|
+
type: RollupValueType
|
|
108
|
+
function: str # e.g., "sum", "count", "average", "max", "min", etc.
|
|
109
|
+
number: float | None = None
|
|
110
|
+
date: DateValue | None = None
|
|
111
|
+
array: list[Any] | None = None
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# ============================================================================
|
|
115
|
+
# Unique ID Models
|
|
116
|
+
# ============================================================================
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class UniqueIdValue(BaseModel):
|
|
120
|
+
number: int # Auto-incrementing count
|
|
121
|
+
prefix: str | None = None # Optional prefix like "RL"
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# ============================================================================
|
|
125
|
+
# Verification Models
|
|
126
|
+
# ============================================================================
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class VerificationState(StrEnum):
|
|
130
|
+
VERIFIED = "verified"
|
|
131
|
+
UNVERIFIED = "unverified"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class VerificationValue(BaseModel):
|
|
135
|
+
state: VerificationState
|
|
136
|
+
verified_by: UserResponseDto | None = None
|
|
137
|
+
date: DateValue | None = None # start = verification date, end = expiration
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# ============================================================================
|
|
141
|
+
# Page Property Classes
|
|
142
|
+
# ============================================================================
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class PageStatusProperty(PageProperty):
|
|
146
|
+
type: Literal[PropertyType.STATUS] = PropertyType.STATUS
|
|
147
|
+
status: StatusOption | None = None
|
|
148
|
+
options: list[StatusOption] = Field(default_factory=list)
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
def option_names(self) -> list[str]:
|
|
152
|
+
return [option.name for option in self.options]
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class PageRelationProperty(PageProperty):
|
|
156
|
+
type: Literal[PropertyType.RELATION] = PropertyType.RELATION
|
|
157
|
+
relation: list[RelationItem] = Field(default_factory=list)
|
|
158
|
+
has_more: bool = False
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class PageURLProperty(PageProperty):
|
|
162
|
+
type: Literal[PropertyType.URL] = PropertyType.URL
|
|
163
|
+
url: str | None = None
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class PageRichTextProperty(PageProperty):
|
|
167
|
+
type: Literal[PropertyType.RICH_TEXT] = PropertyType.RICH_TEXT
|
|
168
|
+
rich_text: list[RichText] = Field(default_factory=list)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class PageMultiSelectProperty(PageProperty):
|
|
172
|
+
type: Literal[PropertyType.MULTI_SELECT] = PropertyType.MULTI_SELECT
|
|
173
|
+
multi_select: list[SelectOption] = Field(default_factory=list)
|
|
174
|
+
options: list[SelectOption] = Field(default_factory=list)
|
|
175
|
+
|
|
176
|
+
@property
|
|
177
|
+
def option_names(self) -> list[str]:
|
|
178
|
+
return [option.name for option in self.options]
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class PageSelectProperty(PageProperty):
|
|
182
|
+
type: Literal[PropertyType.SELECT] = PropertyType.SELECT
|
|
183
|
+
select: SelectOption | None = None
|
|
184
|
+
options: list[SelectOption] = Field(default_factory=list)
|
|
185
|
+
|
|
186
|
+
@property
|
|
187
|
+
def option_names(self) -> list[str]:
|
|
188
|
+
return [option.name for option in self.options]
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class PagePeopleProperty(PageProperty):
|
|
192
|
+
type: Literal[PropertyType.PEOPLE] = PropertyType.PEOPLE
|
|
193
|
+
people: list[PersonUserResponseDto] = Field(default_factory=list)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class PageDateProperty(PageProperty):
|
|
197
|
+
type: Literal[PropertyType.DATE] = PropertyType.DATE
|
|
198
|
+
date: DateValue | None = None
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class PageTitleProperty(PageProperty):
|
|
202
|
+
type: Literal[PropertyType.TITLE] = PropertyType.TITLE
|
|
203
|
+
title: list[RichText] = Field(default_factory=list)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class PageNumberProperty(PageProperty):
|
|
207
|
+
type: Literal[PropertyType.NUMBER] = PropertyType.NUMBER
|
|
208
|
+
number: float | None = None
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class PageCheckboxProperty(PageProperty):
|
|
212
|
+
type: Literal[PropertyType.CHECKBOX] = PropertyType.CHECKBOX
|
|
213
|
+
checkbox: bool = False
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class PageEmailProperty(PageProperty):
|
|
217
|
+
type: Literal[PropertyType.EMAIL] = PropertyType.EMAIL
|
|
218
|
+
email: str | None = None
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class PagePhoneNumberProperty(PageProperty):
|
|
222
|
+
type: Literal[PropertyType.PHONE_NUMBER] = PropertyType.PHONE_NUMBER
|
|
223
|
+
phone_number: str | None = None
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class PageCreatedTimeProperty(PageProperty):
|
|
227
|
+
type: Literal[PropertyType.CREATED_TIME] = PropertyType.CREATED_TIME
|
|
228
|
+
created_time: str # ISO 8601 datetime - read-only
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class PageLastEditedTimeProperty(PageProperty):
|
|
232
|
+
type: Literal[PropertyType.LAST_EDITED_TIME] = PropertyType.LAST_EDITED_TIME
|
|
233
|
+
last_edited_time: str # ISO 8601 datetime - read-only
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class PageCreatedByProperty(PageProperty):
|
|
237
|
+
type: Literal[PropertyType.CREATED_BY] = PropertyType.CREATED_BY
|
|
238
|
+
created_by: UserResponseDto # User object - read-only
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class PageLastEditedByProperty(PageProperty):
|
|
242
|
+
type: Literal[PropertyType.LAST_EDITED_BY] = PropertyType.LAST_EDITED_BY
|
|
243
|
+
last_edited_by: UserResponseDto # User object - read-only
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
class PageFilesProperty(PageProperty):
|
|
247
|
+
type: Literal[PropertyType.FILES] = PropertyType.FILES
|
|
248
|
+
files: list[FileObject] = Field(default_factory=list)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class PageFormulaProperty(PageProperty):
|
|
252
|
+
type: Literal[PropertyType.FORMULA] = PropertyType.FORMULA
|
|
253
|
+
formula: FormulaValue
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class PageRollupProperty(PageProperty):
|
|
257
|
+
type: Literal[PropertyType.ROLLUP] = PropertyType.ROLLUP
|
|
258
|
+
rollup: RollupValue
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class PageUniqueIdProperty(PageProperty):
|
|
262
|
+
type: Literal[PropertyType.UNIQUE_ID] = PropertyType.UNIQUE_ID
|
|
263
|
+
unique_id: UniqueIdValue
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
class PageVerificationProperty(PageProperty):
|
|
267
|
+
type: Literal[PropertyType.VERIFICATION] = PropertyType.VERIFICATION
|
|
268
|
+
verification: VerificationValue
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class PageButtonProperty(PageProperty):
|
|
272
|
+
type: Literal[PropertyType.BUTTON] = PropertyType.BUTTON
|
|
273
|
+
button: JsonDict = Field(default_factory=dict)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
# ============================================================================
|
|
277
|
+
# Discriminated Union
|
|
278
|
+
# ============================================================================
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
DiscriminatedPageProperty = Annotated[
|
|
282
|
+
PageStatusProperty
|
|
283
|
+
| PageRelationProperty
|
|
284
|
+
| PageURLProperty
|
|
285
|
+
| PageRichTextProperty
|
|
286
|
+
| PageMultiSelectProperty
|
|
287
|
+
| PageSelectProperty
|
|
288
|
+
| PagePeopleProperty
|
|
289
|
+
| PageDateProperty
|
|
290
|
+
| PageTitleProperty
|
|
291
|
+
| PageNumberProperty
|
|
292
|
+
| PageCheckboxProperty
|
|
293
|
+
| PageEmailProperty
|
|
294
|
+
| PagePhoneNumberProperty
|
|
295
|
+
| PageCreatedTimeProperty
|
|
296
|
+
| PageLastEditedTimeProperty
|
|
297
|
+
| PageCreatedByProperty
|
|
298
|
+
| PageLastEditedByProperty
|
|
299
|
+
| PageFilesProperty
|
|
300
|
+
| PageFormulaProperty
|
|
301
|
+
| PageRollupProperty
|
|
302
|
+
| PageUniqueIdProperty
|
|
303
|
+
| PageVerificationProperty
|
|
304
|
+
| PageButtonProperty,
|
|
305
|
+
Field(discriminator="type"),
|
|
306
|
+
]
|
|
307
|
+
|
|
308
|
+
PagePropertyT = TypeVar("PagePropertyT", bound=PageProperty)
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from typing import TYPE_CHECKING, Never
|
|
5
|
+
|
|
6
|
+
from notionary.blocks.rich_text.rich_text_markdown_converter import convert_rich_text_to_markdown
|
|
7
|
+
from notionary.exceptions.properties import (
|
|
8
|
+
AccessPagePropertyWithoutDataSourceError,
|
|
9
|
+
PagePropertyNotFoundError,
|
|
10
|
+
PagePropertyTypeError,
|
|
11
|
+
)
|
|
12
|
+
from notionary.page.properties.client import PagePropertyHttpClient
|
|
13
|
+
from notionary.page.properties.models import (
|
|
14
|
+
PageCheckboxProperty,
|
|
15
|
+
PageCreatedTimeProperty,
|
|
16
|
+
PageDateProperty,
|
|
17
|
+
PageEmailProperty,
|
|
18
|
+
PageMultiSelectProperty,
|
|
19
|
+
PageNumberProperty,
|
|
20
|
+
PagePeopleProperty,
|
|
21
|
+
PagePhoneNumberProperty,
|
|
22
|
+
PageProperty,
|
|
23
|
+
PagePropertyT,
|
|
24
|
+
PageRelationProperty,
|
|
25
|
+
PageRichTextProperty,
|
|
26
|
+
PageSelectProperty,
|
|
27
|
+
PageStatusProperty,
|
|
28
|
+
PageTitleProperty,
|
|
29
|
+
PageURLProperty,
|
|
30
|
+
)
|
|
31
|
+
from notionary.shared.models.parent import ParentType
|
|
32
|
+
|
|
33
|
+
if TYPE_CHECKING:
|
|
34
|
+
from notionary import NotionDataSource
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class PagePropertyHandler:
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
properties: dict[str, PageProperty],
|
|
41
|
+
parent_type: ParentType,
|
|
42
|
+
page_url: str,
|
|
43
|
+
page_property_http_client: PagePropertyHttpClient,
|
|
44
|
+
parent_data_source: str,
|
|
45
|
+
) -> None:
|
|
46
|
+
self._properties = properties
|
|
47
|
+
self._parent_type = parent_type
|
|
48
|
+
self._page_url = page_url
|
|
49
|
+
self._property_http_client = page_property_http_client
|
|
50
|
+
self._parent_data_source_id = parent_data_source
|
|
51
|
+
self._parent_data_source: NotionDataSource | None = None
|
|
52
|
+
self._data_source_loaded = False
|
|
53
|
+
|
|
54
|
+
# =========================================================================
|
|
55
|
+
# Reader Methods
|
|
56
|
+
# =========================================================================
|
|
57
|
+
|
|
58
|
+
def get_value_of_status_property(self, name: str) -> str | None:
|
|
59
|
+
status_property = self._get_typed_property_or_raise(name, PageStatusProperty)
|
|
60
|
+
return status_property.status.name if status_property.status else None
|
|
61
|
+
|
|
62
|
+
def get_value_of_select_property(self, name: str) -> str | None:
|
|
63
|
+
select_property = self._get_typed_property_or_raise(name, PageSelectProperty)
|
|
64
|
+
return select_property.select.name if select_property.select else None
|
|
65
|
+
|
|
66
|
+
async def get_value_of_title_property(self, name: str) -> str:
|
|
67
|
+
title_property = self._get_typed_property_or_raise(name, PageTitleProperty)
|
|
68
|
+
return await convert_rich_text_to_markdown(title_property.title)
|
|
69
|
+
|
|
70
|
+
def get_values_of_people_property(self, property_name: str) -> list[str]:
|
|
71
|
+
people_prop = self._get_typed_property_or_raise(property_name, PagePeopleProperty)
|
|
72
|
+
return [person.name for person in people_prop.people if person.name]
|
|
73
|
+
|
|
74
|
+
def get_value_of_created_time_property(self, name: str) -> str | None:
|
|
75
|
+
created_time_property = self._get_typed_property_or_raise(name, PageCreatedTimeProperty)
|
|
76
|
+
return created_time_property.created_time
|
|
77
|
+
|
|
78
|
+
async def get_values_of_relation_property(self, name: str) -> list[str]:
|
|
79
|
+
from notionary import NotionPage
|
|
80
|
+
|
|
81
|
+
relation_property = self._get_typed_property_or_raise(name, PageRelationProperty)
|
|
82
|
+
relation_page_ids = [rel.id for rel in relation_property.relation]
|
|
83
|
+
notion_pages = [await NotionPage.from_id(page_id) for page_id in relation_page_ids]
|
|
84
|
+
return [page.title for page in notion_pages if page]
|
|
85
|
+
|
|
86
|
+
def get_values_of_multiselect_property(self, name: str) -> list[str]:
|
|
87
|
+
multiselect_property = self._get_typed_property_or_raise(name, PageMultiSelectProperty)
|
|
88
|
+
return [option.name for option in multiselect_property.multi_select]
|
|
89
|
+
|
|
90
|
+
def get_value_of_url_property(self, name: str) -> str | None:
|
|
91
|
+
url_property = self._get_typed_property_or_raise(name, PageURLProperty)
|
|
92
|
+
return url_property.url
|
|
93
|
+
|
|
94
|
+
def get_value_of_number_property(self, name: str) -> float | None:
|
|
95
|
+
number_property = self._get_typed_property_or_raise(name, PageNumberProperty)
|
|
96
|
+
return number_property.number
|
|
97
|
+
|
|
98
|
+
def get_value_of_checkbox_property(self, name: str) -> bool:
|
|
99
|
+
checkbox_property = self._get_typed_property_or_raise(name, PageCheckboxProperty)
|
|
100
|
+
return checkbox_property.checkbox
|
|
101
|
+
|
|
102
|
+
def get_value_of_date_property(self, name: str) -> str | None:
|
|
103
|
+
date_property = self._get_typed_property_or_raise(name, PageDateProperty)
|
|
104
|
+
return date_property.date.start if date_property.date else None
|
|
105
|
+
|
|
106
|
+
async def get_value_of_rich_text_property(self, name: str) -> str:
|
|
107
|
+
rich_text_property = self._get_typed_property_or_raise(name, PageRichTextProperty)
|
|
108
|
+
return await convert_rich_text_to_markdown(rich_text_property.rich_text)
|
|
109
|
+
|
|
110
|
+
def get_value_of_email_property(self, name: str) -> str | None:
|
|
111
|
+
email_property = self._get_typed_property_or_raise(name, PageEmailProperty)
|
|
112
|
+
return email_property.email
|
|
113
|
+
|
|
114
|
+
def get_value_of_phone_number_property(self, name: str) -> str | None:
|
|
115
|
+
phone_property = self._get_typed_property_or_raise(name, PagePhoneNumberProperty)
|
|
116
|
+
return phone_property.phone_number
|
|
117
|
+
|
|
118
|
+
# =========================================================================
|
|
119
|
+
# Options Getters
|
|
120
|
+
# =========================================================================
|
|
121
|
+
|
|
122
|
+
async def get_select_options_by_property_name(self, property_name: str) -> list[str]:
|
|
123
|
+
data_source = await self._get_parent_data_source_or_raise()
|
|
124
|
+
return data_source.get_select_options_by_property_name(property_name)
|
|
125
|
+
|
|
126
|
+
async def get_multi_select_options_by_property_name(self, property_name: str) -> list[str]:
|
|
127
|
+
data_source = await self._get_parent_data_source_or_raise()
|
|
128
|
+
return data_source.get_multi_select_options_by_property_name(property_name)
|
|
129
|
+
|
|
130
|
+
async def get_status_options_by_property_name(self, property_name: str) -> list[str]:
|
|
131
|
+
data_source = await self._get_parent_data_source_or_raise()
|
|
132
|
+
return data_source.get_status_options_by_property_name(property_name)
|
|
133
|
+
|
|
134
|
+
async def get_relation_options_by_property_name(self, property_name: str) -> list[str]:
|
|
135
|
+
data_source = await self._get_parent_data_source_or_raise()
|
|
136
|
+
return await data_source.get_relation_options_by_property_name(property_name)
|
|
137
|
+
|
|
138
|
+
async def get_options_for_property_by_name(self, property_name: str) -> list[str]:
|
|
139
|
+
data_source = await self._get_parent_data_source_or_raise()
|
|
140
|
+
return await data_source.get_options_for_property_by_name(property_name)
|
|
141
|
+
|
|
142
|
+
async def get_schema_description(self, property_name: str) -> str:
|
|
143
|
+
data_source = await self._get_parent_data_source_or_raise()
|
|
144
|
+
return await data_source.get_schema_description(property_name)
|
|
145
|
+
|
|
146
|
+
# =========================================================================
|
|
147
|
+
# Writer Methods
|
|
148
|
+
# =========================================================================
|
|
149
|
+
|
|
150
|
+
async def set_title_property(self, property_name: str, title: str) -> None:
|
|
151
|
+
self._get_typed_property_or_raise(property_name, PageTitleProperty)
|
|
152
|
+
updated_page = await self._property_http_client.patch_title(property_name, title)
|
|
153
|
+
self._properties = updated_page.properties
|
|
154
|
+
|
|
155
|
+
async def set_rich_text_property(self, property_name: str, text: str) -> None:
|
|
156
|
+
self._get_typed_property_or_raise(property_name, PageRichTextProperty)
|
|
157
|
+
updated_page = await self._property_http_client.patch_rich_text_property(property_name, text)
|
|
158
|
+
self._properties = updated_page.properties
|
|
159
|
+
|
|
160
|
+
async def set_url_property(self, property_name: str, url: str) -> None:
|
|
161
|
+
self._get_typed_property_or_raise(property_name, PageURLProperty)
|
|
162
|
+
updated_page = await self._property_http_client.patch_url_property(property_name, url)
|
|
163
|
+
self._properties = updated_page.properties
|
|
164
|
+
|
|
165
|
+
async def set_email_property(self, property_name: str, email: str) -> None:
|
|
166
|
+
self._get_typed_property_or_raise(property_name, PageEmailProperty)
|
|
167
|
+
updated_page = await self._property_http_client.patch_email_property(property_name, email)
|
|
168
|
+
self._properties = updated_page.properties
|
|
169
|
+
|
|
170
|
+
async def set_phone_number_property(self, property_name: str, phone_number: str) -> None:
|
|
171
|
+
self._get_typed_property_or_raise(property_name, PagePhoneNumberProperty)
|
|
172
|
+
updated_page = await self._property_http_client.patch_phone_property(property_name, phone_number)
|
|
173
|
+
self._properties = updated_page.properties
|
|
174
|
+
|
|
175
|
+
async def set_number_property(self, property_name: str, number: int | float) -> None:
|
|
176
|
+
self._get_typed_property_or_raise(property_name, PageNumberProperty)
|
|
177
|
+
updated_page = await self._property_http_client.patch_number_property(property_name, number)
|
|
178
|
+
self._properties = updated_page.properties
|
|
179
|
+
|
|
180
|
+
async def set_checkbox_property(self, property_name: str, checked: bool) -> None:
|
|
181
|
+
self._get_typed_property_or_raise(property_name, PageCheckboxProperty)
|
|
182
|
+
updated_page = await self._property_http_client.patch_checkbox_property(property_name, checked)
|
|
183
|
+
self._properties = updated_page.properties
|
|
184
|
+
|
|
185
|
+
async def set_date_property(self, property_name: str, date_value: str | dict) -> None:
|
|
186
|
+
self._get_typed_property_or_raise(property_name, PageDateProperty)
|
|
187
|
+
updated_page = await self._property_http_client.patch_date_property(property_name, date_value)
|
|
188
|
+
self._properties = updated_page.properties
|
|
189
|
+
|
|
190
|
+
async def set_select_property_by_option_name(self, property_name: str, option_name: str) -> None:
|
|
191
|
+
self._get_typed_property_or_raise(property_name, PageSelectProperty)
|
|
192
|
+
updated_page = await self._property_http_client.patch_select_property(property_name, option_name)
|
|
193
|
+
self._properties = updated_page.properties
|
|
194
|
+
|
|
195
|
+
async def set_multi_select_property_by_option_names(self, property_name: str, option_names: list[str]) -> None:
|
|
196
|
+
self._get_typed_property_or_raise(property_name, PageMultiSelectProperty)
|
|
197
|
+
updated_page = await self._property_http_client.patch_multi_select_property(property_name, option_names)
|
|
198
|
+
self._properties = updated_page.properties
|
|
199
|
+
|
|
200
|
+
async def set_status_property_by_option_name(self, property_name: str, status: str) -> None:
|
|
201
|
+
self._get_typed_property_or_raise(property_name, PageStatusProperty)
|
|
202
|
+
updated_page = await self._property_http_client.patch_status_property(property_name, status)
|
|
203
|
+
self._properties = updated_page.properties
|
|
204
|
+
|
|
205
|
+
async def set_relation_property_by_page_titles(self, property_name: str, page_titles: list[str]) -> None:
|
|
206
|
+
self._get_typed_property_or_raise(property_name, PageRelationProperty)
|
|
207
|
+
relation_ids = await self._convert_page_titles_to_ids(page_titles)
|
|
208
|
+
updated_page = await self._property_http_client.patch_relation_property(property_name, relation_ids)
|
|
209
|
+
self._properties = updated_page.properties
|
|
210
|
+
|
|
211
|
+
async def _ensure_data_source_loaded(self) -> None:
|
|
212
|
+
from notionary import NotionDataSource
|
|
213
|
+
|
|
214
|
+
if self._data_source_loaded:
|
|
215
|
+
return
|
|
216
|
+
|
|
217
|
+
self._parent_data_source = (
|
|
218
|
+
await NotionDataSource.from_id(self._parent_data_source_id) if self._parent_data_source_id else None
|
|
219
|
+
)
|
|
220
|
+
self._data_source_loaded = True
|
|
221
|
+
|
|
222
|
+
async def _get_parent_data_source_or_raise(self) -> NotionDataSource:
|
|
223
|
+
await self._ensure_data_source_loaded()
|
|
224
|
+
|
|
225
|
+
if not self._parent_data_source:
|
|
226
|
+
raise AccessPagePropertyWithoutDataSourceError(self._parent_type)
|
|
227
|
+
return self._parent_data_source
|
|
228
|
+
|
|
229
|
+
def _get_typed_property_or_raise(self, name: str, property_type: type[PagePropertyT]) -> PagePropertyT:
|
|
230
|
+
prop = self._properties.get(name)
|
|
231
|
+
|
|
232
|
+
if prop is None:
|
|
233
|
+
self._handle_prop_not_found(name)
|
|
234
|
+
|
|
235
|
+
if not isinstance(prop, property_type):
|
|
236
|
+
self._handle_incorrect_type(name, type(prop))
|
|
237
|
+
|
|
238
|
+
return prop
|
|
239
|
+
|
|
240
|
+
def _handle_prop_not_found(self, name: str) -> Never:
|
|
241
|
+
raise PagePropertyNotFoundError(
|
|
242
|
+
property_name=name,
|
|
243
|
+
page_url=self._page_url,
|
|
244
|
+
available_properties=list(self._properties.keys()),
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
def _handle_incorrect_type(self, property_name: str, actual_type: type) -> Never:
|
|
248
|
+
raise PagePropertyTypeError(
|
|
249
|
+
property_name=property_name,
|
|
250
|
+
actual_type=actual_type.__name__,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
async def _convert_page_titles_to_ids(self, page_titles: list[str]) -> list[str]:
|
|
254
|
+
from notionary import NotionPage
|
|
255
|
+
|
|
256
|
+
if not page_titles:
|
|
257
|
+
return []
|
|
258
|
+
|
|
259
|
+
pages = await asyncio.gather(*[NotionPage.from_title(title=title) for title in page_titles])
|
|
260
|
+
|
|
261
|
+
return [page.id for page in pages if page]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from pydantic import BaseModel
|
|
2
|
+
|
|
3
|
+
from notionary.page.properties.models import DiscriminatedPageProperty
|
|
4
|
+
from notionary.shared.entity.schemas import EntityResponseDto
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class NotionPageDto(EntityResponseDto):
|
|
8
|
+
archived: bool
|
|
9
|
+
properties: dict[str, DiscriminatedPageProperty]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PgePropertiesUpdateDto(BaseModel):
|
|
13
|
+
properties: dict[str, DiscriminatedPageProperty]
|