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
notionary/base_notion_client.py
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import os
|
|
3
|
-
from abc import ABC
|
|
4
|
-
from enum import Enum
|
|
5
|
-
from typing import Any, Dict, Optional, Union
|
|
6
|
-
|
|
7
|
-
import httpx
|
|
8
|
-
from dotenv import load_dotenv
|
|
9
|
-
|
|
10
|
-
from notionary.util import LoggingMixin
|
|
11
|
-
|
|
12
|
-
load_dotenv()
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class HttpMethod(Enum):
|
|
16
|
-
"""
|
|
17
|
-
Enumeration of supported HTTP methods for API requests.
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
GET = "get"
|
|
21
|
-
POST = "post"
|
|
22
|
-
PATCH = "patch"
|
|
23
|
-
DELETE = "delete"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class BaseNotionClient(LoggingMixin, ABC):
|
|
27
|
-
"""
|
|
28
|
-
Base client for Notion API operations.
|
|
29
|
-
Handles connection management and generic HTTP requests.
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
BASE_URL = "https://api.notion.com/v1"
|
|
33
|
-
NOTION_VERSION = "2022-06-28"
|
|
34
|
-
|
|
35
|
-
def __init__(self, token: Optional[str] = None, timeout: int = 30):
|
|
36
|
-
self.token = token or self._find_token()
|
|
37
|
-
if not self.token:
|
|
38
|
-
raise ValueError("Notion API token is required")
|
|
39
|
-
|
|
40
|
-
self.headers = {
|
|
41
|
-
"Authorization": f"Bearer {self.token}",
|
|
42
|
-
"Content-Type": "application/json",
|
|
43
|
-
"Notion-Version": self.NOTION_VERSION,
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
self.client: Optional[httpx.AsyncClient] = None
|
|
47
|
-
self.timeout = timeout
|
|
48
|
-
self._is_initialized = False
|
|
49
|
-
|
|
50
|
-
def __del__(self):
|
|
51
|
-
"""Auto-cleanup when client is destroyed."""
|
|
52
|
-
if not hasattr(self, "client") or not self.client:
|
|
53
|
-
return
|
|
54
|
-
|
|
55
|
-
try:
|
|
56
|
-
loop = asyncio.get_event_loop()
|
|
57
|
-
if not loop.is_running():
|
|
58
|
-
self.logger.warning(
|
|
59
|
-
"Event loop not running, could not auto-close NotionClient"
|
|
60
|
-
)
|
|
61
|
-
return
|
|
62
|
-
|
|
63
|
-
loop.create_task(self.close())
|
|
64
|
-
self.logger.debug("Created cleanup task for NotionClient")
|
|
65
|
-
except RuntimeError:
|
|
66
|
-
self.logger.warning("No event loop available for auto-closing NotionClient")
|
|
67
|
-
|
|
68
|
-
async def __aenter__(self):
|
|
69
|
-
"""Async context manager entry."""
|
|
70
|
-
await self.ensure_initialized()
|
|
71
|
-
return self
|
|
72
|
-
|
|
73
|
-
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
74
|
-
"""Async context manager exit."""
|
|
75
|
-
await self.close()
|
|
76
|
-
|
|
77
|
-
async def ensure_initialized(self) -> None:
|
|
78
|
-
"""
|
|
79
|
-
Ensures the HTTP client is initialized.
|
|
80
|
-
"""
|
|
81
|
-
if not self._is_initialized or not self.client:
|
|
82
|
-
self.client = httpx.AsyncClient(headers=self.headers, timeout=self.timeout)
|
|
83
|
-
self._is_initialized = True
|
|
84
|
-
self.logger.debug("NotionClient initialized")
|
|
85
|
-
|
|
86
|
-
async def close(self) -> None:
|
|
87
|
-
"""
|
|
88
|
-
Closes the HTTP client and releases resources.
|
|
89
|
-
"""
|
|
90
|
-
if not hasattr(self, "client") or not self.client:
|
|
91
|
-
return
|
|
92
|
-
|
|
93
|
-
await self.client.aclose()
|
|
94
|
-
self.client = None
|
|
95
|
-
self._is_initialized = False
|
|
96
|
-
self.logger.debug("NotionClient closed")
|
|
97
|
-
|
|
98
|
-
async def get(
|
|
99
|
-
self, endpoint: str, params: Optional[Dict[str, Any]] = None
|
|
100
|
-
) -> Optional[Dict[str, Any]]:
|
|
101
|
-
"""
|
|
102
|
-
Sends a GET request to the specified Notion API endpoint.
|
|
103
|
-
|
|
104
|
-
Args:
|
|
105
|
-
endpoint: The API endpoint (without base URL)
|
|
106
|
-
params: Query parameters to include in the request
|
|
107
|
-
"""
|
|
108
|
-
return await self._make_request(HttpMethod.GET, endpoint, params=params)
|
|
109
|
-
|
|
110
|
-
async def post(
|
|
111
|
-
self, endpoint: str, data: Optional[Dict[str, Any]] = None
|
|
112
|
-
) -> Optional[Dict[str, Any]]:
|
|
113
|
-
"""
|
|
114
|
-
Sends a POST request to the specified Notion API endpoint.
|
|
115
|
-
|
|
116
|
-
Args:
|
|
117
|
-
endpoint: The API endpoint (without base URL)
|
|
118
|
-
data: Request body data
|
|
119
|
-
"""
|
|
120
|
-
return await self._make_request(HttpMethod.POST, endpoint, data)
|
|
121
|
-
|
|
122
|
-
async def patch(
|
|
123
|
-
self, endpoint: str, data: Optional[Dict[str, Any]] = None
|
|
124
|
-
) -> Optional[Dict[str, Any]]:
|
|
125
|
-
"""
|
|
126
|
-
Sends a PATCH request to the specified Notion API endpoint.
|
|
127
|
-
|
|
128
|
-
Args:
|
|
129
|
-
endpoint: The API endpoint (without base URL)
|
|
130
|
-
data: Request body data
|
|
131
|
-
"""
|
|
132
|
-
return await self._make_request(HttpMethod.PATCH, endpoint, data)
|
|
133
|
-
|
|
134
|
-
async def delete(self, endpoint: str) -> bool:
|
|
135
|
-
"""
|
|
136
|
-
Sends a DELETE request to the specified Notion API endpoint.
|
|
137
|
-
|
|
138
|
-
Args:
|
|
139
|
-
endpoint: The API endpoint (without base URL)
|
|
140
|
-
"""
|
|
141
|
-
result = await self._make_request(HttpMethod.DELETE, endpoint)
|
|
142
|
-
return result is not None
|
|
143
|
-
|
|
144
|
-
async def _make_request(
|
|
145
|
-
self,
|
|
146
|
-
method: Union[HttpMethod, str],
|
|
147
|
-
endpoint: str,
|
|
148
|
-
data: Optional[Dict[str, Any]] = None,
|
|
149
|
-
params: Optional[Dict[str, Any]] = None,
|
|
150
|
-
) -> Optional[Dict[str, Any]]:
|
|
151
|
-
"""
|
|
152
|
-
Executes an HTTP request and returns the data or None on error.
|
|
153
|
-
|
|
154
|
-
Args:
|
|
155
|
-
method: HTTP method to use
|
|
156
|
-
endpoint: API endpoint
|
|
157
|
-
data: Request body data (for POST/PATCH)
|
|
158
|
-
params: Query parameters (for GET requests)
|
|
159
|
-
"""
|
|
160
|
-
await self.ensure_initialized()
|
|
161
|
-
|
|
162
|
-
url = f"{self.BASE_URL}/{endpoint.lstrip('/')}"
|
|
163
|
-
method_str = (
|
|
164
|
-
method.value if isinstance(method, HttpMethod) else str(method).lower()
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
try:
|
|
168
|
-
self.logger.debug("Sending %s request to %s", method_str.upper(), url)
|
|
169
|
-
|
|
170
|
-
request_kwargs = {}
|
|
171
|
-
|
|
172
|
-
# Add query parameters for GET requests
|
|
173
|
-
if params:
|
|
174
|
-
request_kwargs["params"] = params
|
|
175
|
-
|
|
176
|
-
if (
|
|
177
|
-
method_str in [HttpMethod.POST.value, HttpMethod.PATCH.value]
|
|
178
|
-
and data is not None
|
|
179
|
-
):
|
|
180
|
-
request_kwargs["json"] = data
|
|
181
|
-
|
|
182
|
-
response: httpx.Response = await getattr(self.client, method_str)(
|
|
183
|
-
url, **request_kwargs
|
|
184
|
-
)
|
|
185
|
-
|
|
186
|
-
response.raise_for_status()
|
|
187
|
-
result_data = response.json()
|
|
188
|
-
self.logger.debug("Request successful: %s", url)
|
|
189
|
-
return result_data
|
|
190
|
-
|
|
191
|
-
except httpx.HTTPStatusError as e:
|
|
192
|
-
error_msg = (
|
|
193
|
-
f"HTTP status error: {e.response.status_code} - {e.response.text}"
|
|
194
|
-
)
|
|
195
|
-
self.logger.error("Request failed (%s): %s", url, error_msg)
|
|
196
|
-
return None
|
|
197
|
-
|
|
198
|
-
except httpx.RequestError as e:
|
|
199
|
-
error_msg = f"Request error: {str(e)}"
|
|
200
|
-
self.logger.error("Request error (%s): %s", url, error_msg)
|
|
201
|
-
return None
|
|
202
|
-
|
|
203
|
-
def _find_token(self) -> Optional[str]:
|
|
204
|
-
"""
|
|
205
|
-
Finds the Notion API token from environment variables.
|
|
206
|
-
"""
|
|
207
|
-
token = next(
|
|
208
|
-
(
|
|
209
|
-
os.getenv(var)
|
|
210
|
-
for var in ("NOTION_SECRET", "NOTION_INTEGRATION_KEY", "NOTION_TOKEN")
|
|
211
|
-
if os.getenv(var)
|
|
212
|
-
),
|
|
213
|
-
None,
|
|
214
|
-
)
|
|
215
|
-
if token:
|
|
216
|
-
self.logger.debug("Found token in environment variable.")
|
|
217
|
-
return token
|
|
218
|
-
self.logger.warning("No Notion API token found in environment variables")
|
|
219
|
-
return None
|
notionary/blocks/_bootstrap.py
DELETED
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import Optional, Union
|
|
4
|
-
|
|
5
|
-
_bootstrapped = False
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def bootstrap_blocks() -> None:
|
|
9
|
-
global _bootstrapped
|
|
10
|
-
if _bootstrapped:
|
|
11
|
-
return
|
|
12
|
-
|
|
13
|
-
from notionary.blocks import (
|
|
14
|
-
bookmark,
|
|
15
|
-
breadcrumbs,
|
|
16
|
-
bulleted_list,
|
|
17
|
-
callout,
|
|
18
|
-
child_page,
|
|
19
|
-
code,
|
|
20
|
-
column,
|
|
21
|
-
divider,
|
|
22
|
-
embed,
|
|
23
|
-
equation,
|
|
24
|
-
file,
|
|
25
|
-
heading,
|
|
26
|
-
image_block,
|
|
27
|
-
models,
|
|
28
|
-
numbered_list,
|
|
29
|
-
paragraph,
|
|
30
|
-
quote,
|
|
31
|
-
table,
|
|
32
|
-
table_of_contents,
|
|
33
|
-
todo,
|
|
34
|
-
toggle,
|
|
35
|
-
toggleable_heading,
|
|
36
|
-
video,
|
|
37
|
-
child_database,
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
# Collect all exports from modules
|
|
41
|
-
ns = {}
|
|
42
|
-
for m in (
|
|
43
|
-
bookmark,
|
|
44
|
-
breadcrumbs,
|
|
45
|
-
bulleted_list,
|
|
46
|
-
callout,
|
|
47
|
-
child_page,
|
|
48
|
-
code,
|
|
49
|
-
column,
|
|
50
|
-
divider,
|
|
51
|
-
embed,
|
|
52
|
-
equation,
|
|
53
|
-
file,
|
|
54
|
-
heading,
|
|
55
|
-
image_block,
|
|
56
|
-
numbered_list,
|
|
57
|
-
paragraph,
|
|
58
|
-
quote,
|
|
59
|
-
table,
|
|
60
|
-
todo,
|
|
61
|
-
toggle,
|
|
62
|
-
video,
|
|
63
|
-
toggleable_heading,
|
|
64
|
-
table_of_contents,
|
|
65
|
-
child_database,
|
|
66
|
-
):
|
|
67
|
-
ns.update(vars(m))
|
|
68
|
-
|
|
69
|
-
# Add missing types that are needed for model rebuilding
|
|
70
|
-
# These are the types that are only defined in TYPE_CHECKING in block_models
|
|
71
|
-
from notionary.blocks.bookmark.bookmark_models import (
|
|
72
|
-
BookmarkBlock,
|
|
73
|
-
CreateBookmarkBlock,
|
|
74
|
-
)
|
|
75
|
-
from notionary.blocks.breadcrumbs.breadcrumb_models import (
|
|
76
|
-
BreadcrumbBlock,
|
|
77
|
-
CreateBreadcrumbBlock,
|
|
78
|
-
)
|
|
79
|
-
from notionary.blocks.bulleted_list.bulleted_list_models import (
|
|
80
|
-
BulletedListItemBlock,
|
|
81
|
-
CreateBulletedListItemBlock,
|
|
82
|
-
)
|
|
83
|
-
from notionary.blocks.callout.callout_models import CalloutBlock, CreateCalloutBlock
|
|
84
|
-
from notionary.blocks.child_page.child_page_models import (
|
|
85
|
-
ChildPageBlock,
|
|
86
|
-
CreateChildPageBlock,
|
|
87
|
-
)
|
|
88
|
-
from notionary.blocks.code.code_models import CodeBlock, CreateCodeBlock
|
|
89
|
-
from notionary.blocks.column.column_models import (
|
|
90
|
-
ColumnBlock,
|
|
91
|
-
ColumnListBlock,
|
|
92
|
-
CreateColumnBlock,
|
|
93
|
-
CreateColumnListBlock,
|
|
94
|
-
)
|
|
95
|
-
from notionary.blocks.divider.divider_models import CreateDividerBlock, DividerBlock
|
|
96
|
-
from notionary.blocks.embed.embed_models import CreateEmbedBlock, EmbedBlock
|
|
97
|
-
from notionary.blocks.equation.equation_models import (
|
|
98
|
-
CreateEquationBlock,
|
|
99
|
-
EquationBlock,
|
|
100
|
-
)
|
|
101
|
-
from notionary.blocks.file.file_element_models import CreateFileBlock, FileBlock
|
|
102
|
-
from notionary.blocks.heading.heading_models import (
|
|
103
|
-
CreateHeading1Block,
|
|
104
|
-
CreateHeading2Block,
|
|
105
|
-
CreateHeading3Block,
|
|
106
|
-
HeadingBlock,
|
|
107
|
-
)
|
|
108
|
-
from notionary.blocks.image_block.image_models import CreateImageBlock
|
|
109
|
-
from notionary.blocks.numbered_list.numbered_list_models import (
|
|
110
|
-
CreateNumberedListItemBlock,
|
|
111
|
-
NumberedListItemBlock,
|
|
112
|
-
)
|
|
113
|
-
from notionary.blocks.paragraph.paragraph_models import (
|
|
114
|
-
CreateParagraphBlock,
|
|
115
|
-
ParagraphBlock,
|
|
116
|
-
)
|
|
117
|
-
from notionary.blocks.pdf.pdf_models import CreatePdfBlock
|
|
118
|
-
from notionary.blocks.quote.quote_models import CreateQuoteBlock, QuoteBlock
|
|
119
|
-
from notionary.blocks.table.table_models import TableBlock, TableRowBlock
|
|
120
|
-
from notionary.blocks.table_of_contents.table_of_contents_models import (
|
|
121
|
-
CreateTableOfContentsBlock,
|
|
122
|
-
TableOfContentsBlock,
|
|
123
|
-
)
|
|
124
|
-
from notionary.blocks.todo.todo_models import CreateToDoBlock, ToDoBlock
|
|
125
|
-
from notionary.blocks.toggle.toggle_models import CreateToggleBlock, ToggleBlock
|
|
126
|
-
from notionary.blocks.types import BlockType
|
|
127
|
-
from notionary.blocks.video.video_element_models import CreateVideoBlock
|
|
128
|
-
from notionary.blocks.child_database.child_database_models import (
|
|
129
|
-
CreateChildDatabaseBlock,
|
|
130
|
-
ChildDatabaseBlock,
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
# Define the Union types that are needed for model rebuilding
|
|
134
|
-
BlockCreateRequest = Union[
|
|
135
|
-
CreateBookmarkBlock,
|
|
136
|
-
CreateBreadcrumbBlock,
|
|
137
|
-
CreateBulletedListItemBlock,
|
|
138
|
-
CreateCalloutBlock,
|
|
139
|
-
CreateChildPageBlock,
|
|
140
|
-
CreateCodeBlock,
|
|
141
|
-
CreateColumnListBlock,
|
|
142
|
-
CreateColumnBlock,
|
|
143
|
-
CreateDividerBlock,
|
|
144
|
-
CreateEmbedBlock,
|
|
145
|
-
CreateEquationBlock,
|
|
146
|
-
CreateFileBlock,
|
|
147
|
-
CreateHeading1Block,
|
|
148
|
-
CreateHeading2Block,
|
|
149
|
-
CreateHeading3Block,
|
|
150
|
-
CreateImageBlock,
|
|
151
|
-
CreateNumberedListItemBlock,
|
|
152
|
-
CreateParagraphBlock,
|
|
153
|
-
CreateQuoteBlock,
|
|
154
|
-
CreateToDoBlock,
|
|
155
|
-
CreateToggleBlock,
|
|
156
|
-
CreateVideoBlock,
|
|
157
|
-
CreateTableOfContentsBlock,
|
|
158
|
-
CreatePdfBlock,
|
|
159
|
-
CreateChildDatabaseBlock,
|
|
160
|
-
]
|
|
161
|
-
|
|
162
|
-
BlockCreateResult = Optional[BlockCreateRequest]
|
|
163
|
-
|
|
164
|
-
# Add all block types to namespace
|
|
165
|
-
ns.update(
|
|
166
|
-
{
|
|
167
|
-
"BlockType": BlockType,
|
|
168
|
-
"BookmarkBlock": BookmarkBlock,
|
|
169
|
-
"CreateBookmarkBlock": CreateBookmarkBlock,
|
|
170
|
-
"BreadcrumbBlock": BreadcrumbBlock,
|
|
171
|
-
"CreateBreadcrumbBlock": CreateBreadcrumbBlock,
|
|
172
|
-
"BulletedListItemBlock": BulletedListItemBlock,
|
|
173
|
-
"CreateBulletedListItemBlock": CreateBulletedListItemBlock,
|
|
174
|
-
"CalloutBlock": CalloutBlock,
|
|
175
|
-
"CreateCalloutBlock": CreateCalloutBlock,
|
|
176
|
-
"ChildPageBlock": ChildPageBlock,
|
|
177
|
-
"CreateChildPageBlock": CreateChildPageBlock,
|
|
178
|
-
"CodeBlock": CodeBlock,
|
|
179
|
-
"CreateCodeBlock": CreateCodeBlock,
|
|
180
|
-
"ColumnBlock": ColumnBlock,
|
|
181
|
-
"ColumnListBlock": ColumnListBlock,
|
|
182
|
-
"CreateColumnBlock": CreateColumnBlock,
|
|
183
|
-
"CreateColumnListBlock": CreateColumnListBlock,
|
|
184
|
-
"DividerBlock": DividerBlock,
|
|
185
|
-
"CreateDividerBlock": CreateDividerBlock,
|
|
186
|
-
"EmbedBlock": EmbedBlock,
|
|
187
|
-
"CreateEmbedBlock": CreateEmbedBlock,
|
|
188
|
-
"EquationBlock": EquationBlock,
|
|
189
|
-
"CreateEquationBlock": CreateEquationBlock,
|
|
190
|
-
"FileBlock": FileBlock,
|
|
191
|
-
"CreateFileBlock": CreateFileBlock,
|
|
192
|
-
"HeadingBlock": HeadingBlock,
|
|
193
|
-
"CreateHeading1Block": CreateHeading1Block,
|
|
194
|
-
"CreateHeading2Block": CreateHeading2Block,
|
|
195
|
-
"CreateHeading3Block": CreateHeading3Block,
|
|
196
|
-
"CreateImageBlock": CreateImageBlock,
|
|
197
|
-
"NumberedListItemBlock": NumberedListItemBlock,
|
|
198
|
-
"CreateNumberedListItemBlock": CreateNumberedListItemBlock,
|
|
199
|
-
"ParagraphBlock": ParagraphBlock,
|
|
200
|
-
"CreateParagraphBlock": CreateParagraphBlock,
|
|
201
|
-
"QuoteBlock": QuoteBlock,
|
|
202
|
-
"CreateQuoteBlock": CreateQuoteBlock,
|
|
203
|
-
"TableBlock": TableBlock,
|
|
204
|
-
"TableRowBlock": TableRowBlock,
|
|
205
|
-
"ToDoBlock": ToDoBlock,
|
|
206
|
-
"CreateToDoBlock": CreateToDoBlock,
|
|
207
|
-
"ToggleBlock": ToggleBlock,
|
|
208
|
-
"CreateToggleBlock": CreateToggleBlock,
|
|
209
|
-
"CreateVideoBlock": CreateVideoBlock,
|
|
210
|
-
"TableOfContentsBlock": TableOfContentsBlock,
|
|
211
|
-
"CreateTableOfContentsBlock": CreateTableOfContentsBlock,
|
|
212
|
-
"ChildDatabaseBlock": ChildDatabaseBlock,
|
|
213
|
-
# Add the Union types
|
|
214
|
-
"BlockCreateRequest": BlockCreateRequest,
|
|
215
|
-
"BlockCreateResult": BlockCreateResult,
|
|
216
|
-
}
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
# Now rebuild with complete namespace
|
|
220
|
-
models.Block.model_rebuild(_types_namespace=ns)
|
|
221
|
-
models.BlockChildrenResponse.model_rebuild(_types_namespace=ns)
|
|
222
|
-
|
|
223
|
-
# Rebuild all individual block models
|
|
224
|
-
BookmarkBlock.model_rebuild()
|
|
225
|
-
BreadcrumbBlock.model_rebuild()
|
|
226
|
-
BulletedListItemBlock.model_rebuild()
|
|
227
|
-
CalloutBlock.model_rebuild()
|
|
228
|
-
ChildPageBlock.model_rebuild()
|
|
229
|
-
CodeBlock.model_rebuild()
|
|
230
|
-
ColumnBlock.model_rebuild()
|
|
231
|
-
ColumnListBlock.model_rebuild()
|
|
232
|
-
DividerBlock.model_rebuild()
|
|
233
|
-
EmbedBlock.model_rebuild()
|
|
234
|
-
EquationBlock.model_rebuild()
|
|
235
|
-
FileBlock.model_rebuild()
|
|
236
|
-
HeadingBlock.model_rebuild()
|
|
237
|
-
NumberedListItemBlock.model_rebuild()
|
|
238
|
-
ParagraphBlock.model_rebuild()
|
|
239
|
-
QuoteBlock.model_rebuild()
|
|
240
|
-
TableBlock.model_rebuild()
|
|
241
|
-
TableRowBlock.model_rebuild()
|
|
242
|
-
ToDoBlock.model_rebuild()
|
|
243
|
-
ToggleBlock.model_rebuild()
|
|
244
|
-
TableOfContentsBlock.model_rebuild()
|
|
245
|
-
|
|
246
|
-
# Rebuild create models
|
|
247
|
-
CreateBookmarkBlock.model_rebuild()
|
|
248
|
-
CreateBreadcrumbBlock.model_rebuild()
|
|
249
|
-
CreateBulletedListItemBlock.model_rebuild()
|
|
250
|
-
CreateCalloutBlock.model_rebuild()
|
|
251
|
-
CreateChildPageBlock.model_rebuild()
|
|
252
|
-
CreateCodeBlock.model_rebuild()
|
|
253
|
-
CreateColumnListBlock.model_rebuild()
|
|
254
|
-
CreateColumnBlock.model_rebuild()
|
|
255
|
-
CreateDividerBlock.model_rebuild()
|
|
256
|
-
CreateEmbedBlock.model_rebuild()
|
|
257
|
-
CreateEquationBlock.model_rebuild()
|
|
258
|
-
CreateFileBlock.model_rebuild()
|
|
259
|
-
CreateHeading1Block.model_rebuild()
|
|
260
|
-
CreateHeading2Block.model_rebuild()
|
|
261
|
-
CreateHeading3Block.model_rebuild()
|
|
262
|
-
CreateImageBlock.model_rebuild()
|
|
263
|
-
CreateNumberedListItemBlock.model_rebuild()
|
|
264
|
-
CreateParagraphBlock.model_rebuild()
|
|
265
|
-
CreateQuoteBlock.model_rebuild()
|
|
266
|
-
CreateToDoBlock.model_rebuild()
|
|
267
|
-
CreateToggleBlock.model_rebuild()
|
|
268
|
-
CreateVideoBlock.model_rebuild()
|
|
269
|
-
CreateTableOfContentsBlock.model_rebuild()
|
|
270
|
-
|
|
271
|
-
_bootstrapped = True
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
from notionary.blocks.audio.audio_element import AudioElement
|
|
2
|
-
from notionary.blocks.audio.audio_markdown_node import (
|
|
3
|
-
AudioMarkdownNode,
|
|
4
|
-
)
|
|
5
|
-
from notionary.blocks.audio.audio_models import CreateAudioBlock
|
|
6
|
-
|
|
7
|
-
__all__ = [
|
|
8
|
-
"AudioElement",
|
|
9
|
-
"CreateAudioBlock",
|
|
10
|
-
"AudioMarkdownNode",
|
|
11
|
-
]
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from typing import Optional
|
|
6
|
-
|
|
7
|
-
from notionary.blocks.audio.audio_models import CreateAudioBlock
|
|
8
|
-
from notionary.blocks.base_block_element import BaseBlockElement
|
|
9
|
-
from notionary.blocks.file.file_element_models import (
|
|
10
|
-
ExternalFile,
|
|
11
|
-
FileBlock,
|
|
12
|
-
FileType,
|
|
13
|
-
FileUploadFile,
|
|
14
|
-
)
|
|
15
|
-
from notionary.blocks.mixins.captions import CaptionMixin
|
|
16
|
-
from notionary.blocks.mixins.file_upload.file_upload_mixin import FileUploadMixin
|
|
17
|
-
from notionary.blocks.syntax_prompt_builder import BlockElementMarkdownInformation
|
|
18
|
-
from notionary.blocks.models import Block, BlockCreateResult, BlockType
|
|
19
|
-
from notionary.util.logging_mixin import LoggingMixin
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class AudioElement(BaseBlockElement, FileUploadMixin, LoggingMixin, CaptionMixin):
|
|
23
|
-
r"""
|
|
24
|
-
Handles conversion between Markdown audio embeds and Notion audio blocks.
|
|
25
|
-
|
|
26
|
-
Supports both external URLs and local audio file uploads.
|
|
27
|
-
|
|
28
|
-
Markdown audio syntax:
|
|
29
|
-
- [audio](https://example.com/audio.mp3) - External URL
|
|
30
|
-
- [audio](./local/song.mp3) - Local audio file (will be uploaded)
|
|
31
|
-
- [audio](C:\Music\podcast.wav) - Absolute local path (will be uploaded)
|
|
32
|
-
- [audio](https://example.com/audio.mp3)(caption:Episode 1) - URL with caption
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
AUDIO_PATTERN = re.compile(r"\[audio\]\(([^)]+)\)")
|
|
36
|
-
SUPPORTED_EXTENSIONS = {".mp3", ".wav", ".ogg", ".oga", ".m4a"}
|
|
37
|
-
|
|
38
|
-
@classmethod
|
|
39
|
-
def match_notion(cls, block: Block) -> bool:
|
|
40
|
-
"""Check if this element can handle the given Notion block."""
|
|
41
|
-
return block.type == BlockType.AUDIO
|
|
42
|
-
|
|
43
|
-
@classmethod
|
|
44
|
-
async def markdown_to_notion(cls, text: str) -> Optional[BlockCreateResult]:
|
|
45
|
-
"""Convert markdown audio embed to Notion audio block."""
|
|
46
|
-
# Extract the path/URL
|
|
47
|
-
path = cls._extract_audio_path(text.strip())
|
|
48
|
-
if not path:
|
|
49
|
-
return None
|
|
50
|
-
|
|
51
|
-
# Check if it's a local file path
|
|
52
|
-
if cls._is_local_file_path(path):
|
|
53
|
-
# Verify file exists and has supported extension
|
|
54
|
-
audio_path = Path(path)
|
|
55
|
-
if not audio_path.exists():
|
|
56
|
-
cls.logger.warning(f"Audio file not found: {path}")
|
|
57
|
-
return None
|
|
58
|
-
|
|
59
|
-
if audio_path.suffix.lower() not in cls.SUPPORTED_EXTENSIONS:
|
|
60
|
-
cls.logger.warning(f"Unsupported audio format: {audio_path.suffix}")
|
|
61
|
-
return None
|
|
62
|
-
|
|
63
|
-
cls.logger.info(f"Uploading local audio file: {path}")
|
|
64
|
-
|
|
65
|
-
# Upload the local audio file
|
|
66
|
-
file_upload_id = await cls._upload_local_file(path, "audio")
|
|
67
|
-
if not file_upload_id:
|
|
68
|
-
cls.logger.error(f"Failed to upload audio file: {path}")
|
|
69
|
-
return None
|
|
70
|
-
|
|
71
|
-
cls.logger.info(
|
|
72
|
-
f"Successfully uploaded audio file with ID: {file_upload_id}"
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
# Use mixin to extract caption (if present anywhere in text)
|
|
76
|
-
caption_text = cls.extract_caption(text.strip())
|
|
77
|
-
caption_rich_text = cls.build_caption_rich_text(caption_text or "")
|
|
78
|
-
|
|
79
|
-
audio_content = FileBlock(
|
|
80
|
-
type=FileType.FILE_UPLOAD,
|
|
81
|
-
file_upload=FileUploadFile(id=file_upload_id),
|
|
82
|
-
caption=caption_rich_text,
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
return CreateAudioBlock(audio=audio_content)
|
|
86
|
-
|
|
87
|
-
else:
|
|
88
|
-
# Handle external URL - accept any URL (validation happens at API level)
|
|
89
|
-
# Use mixin to extract caption (if present anywhere in text)
|
|
90
|
-
caption_text = cls.extract_caption(text.strip())
|
|
91
|
-
caption_rich_text = cls.build_caption_rich_text(caption_text or "")
|
|
92
|
-
|
|
93
|
-
audio_content = FileBlock(
|
|
94
|
-
type=FileType.EXTERNAL,
|
|
95
|
-
external=ExternalFile(url=path),
|
|
96
|
-
caption=caption_rich_text,
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
return CreateAudioBlock(audio=audio_content)
|
|
100
|
-
|
|
101
|
-
@classmethod
|
|
102
|
-
async def notion_to_markdown(cls, block: Block) -> Optional[str]:
|
|
103
|
-
"""Convert Notion audio block to markdown audio embed."""
|
|
104
|
-
if block.type != BlockType.AUDIO or block.audio is None:
|
|
105
|
-
return None
|
|
106
|
-
|
|
107
|
-
audio = block.audio
|
|
108
|
-
url = None
|
|
109
|
-
|
|
110
|
-
# Handle both external URLs and uploaded files
|
|
111
|
-
if audio.type == FileType.EXTERNAL and audio.external is not None:
|
|
112
|
-
url = audio.external.url
|
|
113
|
-
elif audio.type == FileType.FILE_UPLOAD and audio.file_upload is not None:
|
|
114
|
-
url = audio.file_upload.url
|
|
115
|
-
|
|
116
|
-
if not url:
|
|
117
|
-
return None
|
|
118
|
-
|
|
119
|
-
result = f"[audio]({url})"
|
|
120
|
-
|
|
121
|
-
# Add caption if present
|
|
122
|
-
caption_markdown = await cls.format_caption_for_markdown(audio.caption or [])
|
|
123
|
-
if caption_markdown:
|
|
124
|
-
result += caption_markdown
|
|
125
|
-
|
|
126
|
-
return result
|
|
127
|
-
|
|
128
|
-
@classmethod
|
|
129
|
-
def get_system_prompt_information(cls) -> Optional[BlockElementMarkdownInformation]:
|
|
130
|
-
"""Get system prompt information for audio blocks."""
|
|
131
|
-
return BlockElementMarkdownInformation(
|
|
132
|
-
block_type=cls.__name__,
|
|
133
|
-
description="Audio blocks embed audio files from external URLs or local files with optional captions",
|
|
134
|
-
syntax_examples=[
|
|
135
|
-
"[audio](https://example.com/song.mp3)",
|
|
136
|
-
"[audio](./local/podcast.wav)",
|
|
137
|
-
"[audio](C:\\Music\\interview.mp3)",
|
|
138
|
-
"[audio](https://example.com/podcast.wav)(caption:Episode 1)",
|
|
139
|
-
"(caption:Background music)[audio](./song.mp3)",
|
|
140
|
-
"[audio](./interview.mp3)(caption:**Live** interview)",
|
|
141
|
-
],
|
|
142
|
-
usage_guidelines="Use for embedding audio files like music, podcasts, or sound effects. Supports both external URLs and local file uploads. Supports common audio formats (mp3, wav, ogg, m4a). Caption supports rich text formatting and is optional.",
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
@classmethod
|
|
146
|
-
def _is_likely_audio_url(cls, url: str) -> bool:
|
|
147
|
-
return any(url.lower().endswith(ext) for ext in cls.SUPPORTED_EXTENSIONS)
|
|
148
|
-
|
|
149
|
-
@classmethod
|
|
150
|
-
def _extract_audio_path(cls, text: str) -> Optional[str]:
|
|
151
|
-
"""Extract audio path/URL from text, handling caption patterns."""
|
|
152
|
-
clean_text = cls.remove_caption(text)
|
|
153
|
-
|
|
154
|
-
match = cls.AUDIO_PATTERN.search(clean_text)
|
|
155
|
-
if match:
|
|
156
|
-
return match.group(1).strip()
|
|
157
|
-
|
|
158
|
-
return None
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
|
-
from notionary.blocks.markdown.markdown_node import MarkdownNode
|
|
4
|
-
from notionary.blocks.mixins.captions import CaptionMarkdownNodeMixin
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class AudioMarkdownNode(MarkdownNode, CaptionMarkdownNodeMixin):
|
|
8
|
-
"""
|
|
9
|
-
Enhanced Audio node with Pydantic integration.
|
|
10
|
-
Programmatic interface for creating Notion-style audio blocks.
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
url: str
|
|
14
|
-
caption: Optional[str] = None
|
|
15
|
-
|
|
16
|
-
def to_markdown(self) -> str:
|
|
17
|
-
"""Return the Markdown representation.
|
|
18
|
-
|
|
19
|
-
Examples:
|
|
20
|
-
- [audio](https://example.com/song.mp3)
|
|
21
|
-
- [audio](https://example.com/song.mp3)(caption:Background music)
|
|
22
|
-
"""
|
|
23
|
-
base_markdown = f"[audio]({self.url})"
|
|
24
|
-
return self.append_caption_to_markdown(base_markdown, self.caption)
|