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
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
from typing import Optional
|
|
5
|
-
|
|
6
|
-
from notionary.blocks.base_block_element import BaseBlockElement
|
|
7
|
-
from notionary.blocks.syntax_prompt_builder import BlockElementMarkdownInformation
|
|
8
|
-
from notionary.blocks.models import Block, BlockCreateResult, BlockType
|
|
9
|
-
from notionary.page.page_context import get_page_context
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class ChildPageElement(BaseBlockElement):
|
|
13
|
-
"""
|
|
14
|
-
Handles conversion between Markdown page references and Notion child page blocks.
|
|
15
|
-
|
|
16
|
-
Creates new pages when converting from markdown.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
PATTERN_BRACKET = re.compile(r"^\[page:\s*(.+)\]$", re.IGNORECASE)
|
|
20
|
-
PATTERN_EMOJI = re.compile(r"^[📝📄]\s*(.+)$")
|
|
21
|
-
|
|
22
|
-
@classmethod
|
|
23
|
-
def match_notion(cls, block: Block) -> bool:
|
|
24
|
-
return block.type == BlockType.CHILD_PAGE and getattr(block, "child_page", None)
|
|
25
|
-
|
|
26
|
-
@classmethod
|
|
27
|
-
async def markdown_to_notion(cls, text: str) -> Optional[BlockCreateResult]:
|
|
28
|
-
"""
|
|
29
|
-
Convert markdown page syntax to an actual Notion page.
|
|
30
|
-
Returns None since child_page blocks are created implicitly via Pages API (not Blocks API).
|
|
31
|
-
"""
|
|
32
|
-
context = get_page_context()
|
|
33
|
-
|
|
34
|
-
text = text.strip()
|
|
35
|
-
|
|
36
|
-
match = cls.PATTERN_BRACKET.match(text)
|
|
37
|
-
if not match:
|
|
38
|
-
match = cls.PATTERN_EMOJI.match(text)
|
|
39
|
-
|
|
40
|
-
if not match:
|
|
41
|
-
return None
|
|
42
|
-
|
|
43
|
-
title = match.group(1).strip()
|
|
44
|
-
if not title:
|
|
45
|
-
return None
|
|
46
|
-
|
|
47
|
-
# Reject multiline titles
|
|
48
|
-
if "\n" in title or "\r" in title:
|
|
49
|
-
return None
|
|
50
|
-
|
|
51
|
-
try:
|
|
52
|
-
# Create the actual page using context
|
|
53
|
-
await context.page_client.create_page(
|
|
54
|
-
title=title,
|
|
55
|
-
parent_page_id=context.page_id,
|
|
56
|
-
)
|
|
57
|
-
# Return None as per BaseBlockElement convention:
|
|
58
|
-
# child_page blocks cannot be written through the Blocks API directly.
|
|
59
|
-
# Creating a page under the parent page will automatically insert a child_page block.
|
|
60
|
-
return None
|
|
61
|
-
|
|
62
|
-
except Exception as e:
|
|
63
|
-
print(f"Failed to create page '{title}': {e}")
|
|
64
|
-
return None
|
|
65
|
-
|
|
66
|
-
@classmethod
|
|
67
|
-
async def notion_to_markdown(cls, block: Block) -> Optional[str]:
|
|
68
|
-
if block.type != BlockType.CHILD_PAGE or not getattr(block, "child_page", None):
|
|
69
|
-
return None
|
|
70
|
-
|
|
71
|
-
title = block.child_page.title
|
|
72
|
-
if not title or not title.strip():
|
|
73
|
-
return None
|
|
74
|
-
|
|
75
|
-
# Use bracket syntax for output
|
|
76
|
-
return f"[page: {title.strip()}]"
|
|
77
|
-
|
|
78
|
-
@classmethod
|
|
79
|
-
def get_system_prompt_information(cls) -> Optional[BlockElementMarkdownInformation]:
|
|
80
|
-
"""Get system prompt information for child page blocks."""
|
|
81
|
-
return BlockElementMarkdownInformation(
|
|
82
|
-
block_type=cls.__name__,
|
|
83
|
-
description="Creates new sub-pages within a Notion page.",
|
|
84
|
-
syntax_examples=[
|
|
85
|
-
"[page: Meeting Notes]",
|
|
86
|
-
"[page: Ideas]",
|
|
87
|
-
"📝 Project Overview",
|
|
88
|
-
"📄 Research Log",
|
|
89
|
-
],
|
|
90
|
-
usage_guidelines=(
|
|
91
|
-
"Use to create new pages that will appear as child_page blocks in the current page. "
|
|
92
|
-
"Pages are created via the Pages API with the current page as parent."
|
|
93
|
-
),
|
|
94
|
-
)
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
from notionary.blocks.code.code_element import CodeElement
|
|
2
|
-
from notionary.blocks.code.code_markdown_node import CodeMarkdownNode
|
|
3
|
-
from notionary.blocks.code.code_models import CodeBlock, CodeLanguage, CreateCodeBlock
|
|
4
|
-
|
|
5
|
-
__all__ = [
|
|
6
|
-
"CodeElement",
|
|
7
|
-
"CodeBlock",
|
|
8
|
-
"CodeLanguage",
|
|
9
|
-
"CreateCodeBlock",
|
|
10
|
-
"CodeMarkdownNode",
|
|
11
|
-
]
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
from typing import Optional
|
|
5
|
-
|
|
6
|
-
from notionary.blocks.base_block_element import BaseBlockElement
|
|
7
|
-
from notionary.blocks.code.code_models import CodeBlock, CodeLanguage, CreateCodeBlock
|
|
8
|
-
from notionary.blocks.syntax_prompt_builder import BlockElementMarkdownInformation
|
|
9
|
-
from notionary.blocks.models import Block, BlockCreateResult, BlockType
|
|
10
|
-
from notionary.blocks.rich_text.rich_text_models import RichTextObject
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class CodeElement(BaseBlockElement):
|
|
14
|
-
"""
|
|
15
|
-
Handles conversion between Markdown code blocks and Notion code blocks.
|
|
16
|
-
Now integrated into the LineProcessor stack system.
|
|
17
|
-
|
|
18
|
-
Markdown code block syntax:
|
|
19
|
-
```language
|
|
20
|
-
[code content as child lines]
|
|
21
|
-
```
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
DEFAULT_LANGUAGE = "plain text"
|
|
25
|
-
CODE_START_PATTERN = re.compile(r"^```(\w*)\s*$")
|
|
26
|
-
CODE_START_WITH_CAPTION_PATTERN = re.compile(r"^```(\w*)\s*(?:\"([^\"]*)\")?\s*$")
|
|
27
|
-
|
|
28
|
-
@classmethod
|
|
29
|
-
def match_notion(cls, block: Block) -> bool:
|
|
30
|
-
"""Check if block is a Notion code block."""
|
|
31
|
-
return block.type == BlockType.CODE and block.code
|
|
32
|
-
|
|
33
|
-
@classmethod
|
|
34
|
-
async def markdown_to_notion(cls, text: str) -> BlockCreateResult:
|
|
35
|
-
"""Convert opening ```language to Notion code block."""
|
|
36
|
-
if not (match := cls.CODE_START_PATTERN.match(text.strip())):
|
|
37
|
-
return None
|
|
38
|
-
|
|
39
|
-
language = (match.group(1) or cls.DEFAULT_LANGUAGE).lower()
|
|
40
|
-
language = cls._normalize_language(language)
|
|
41
|
-
|
|
42
|
-
# Create empty CodeBlock - content will be added by stack processor
|
|
43
|
-
code_block = CodeBlock(rich_text=[], language=language, caption=[])
|
|
44
|
-
return CreateCodeBlock(code=code_block)
|
|
45
|
-
|
|
46
|
-
@classmethod
|
|
47
|
-
def create_from_markdown_block(
|
|
48
|
-
cls, opening_line: str, code_lines: list[str]
|
|
49
|
-
) -> BlockCreateResult:
|
|
50
|
-
"""
|
|
51
|
-
Create a complete code block from markdown components.
|
|
52
|
-
"""
|
|
53
|
-
match = cls.CODE_START_WITH_CAPTION_PATTERN.match(opening_line.strip())
|
|
54
|
-
if not match:
|
|
55
|
-
return None
|
|
56
|
-
|
|
57
|
-
language = (match.group(1) or cls.DEFAULT_LANGUAGE).lower()
|
|
58
|
-
language = cls._normalize_language(language)
|
|
59
|
-
|
|
60
|
-
caption = match.group(2) if match.group(2) else None
|
|
61
|
-
|
|
62
|
-
# Create rich text content from code lines
|
|
63
|
-
rich_text = []
|
|
64
|
-
if code_lines:
|
|
65
|
-
content = "\n".join(code_lines)
|
|
66
|
-
rich_text = [RichTextObject.for_code_block(content)]
|
|
67
|
-
|
|
68
|
-
caption_list = []
|
|
69
|
-
if caption:
|
|
70
|
-
caption_list = [RichTextObject.for_caption(caption)]
|
|
71
|
-
|
|
72
|
-
code_block = CodeBlock(
|
|
73
|
-
rich_text=rich_text, language=language, caption=caption_list
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
return CreateCodeBlock(code=code_block)
|
|
77
|
-
|
|
78
|
-
@classmethod
|
|
79
|
-
async def notion_to_markdown(cls, block: Block) -> Optional[str]:
|
|
80
|
-
"""Convert Notion code block to Markdown."""
|
|
81
|
-
if block.type != BlockType.CODE:
|
|
82
|
-
return None
|
|
83
|
-
|
|
84
|
-
if not block.code:
|
|
85
|
-
return None
|
|
86
|
-
|
|
87
|
-
language_enum = block.code.language
|
|
88
|
-
rich_text = block.code.rich_text or []
|
|
89
|
-
caption = block.code.caption or []
|
|
90
|
-
|
|
91
|
-
code_content = cls.extract_content(rich_text)
|
|
92
|
-
caption_text = cls.extract_caption(caption)
|
|
93
|
-
|
|
94
|
-
# Convert enum to string value
|
|
95
|
-
language = language_enum.value if language_enum else ""
|
|
96
|
-
|
|
97
|
-
# Handle language - convert "plain text" back to empty string for markdown
|
|
98
|
-
if language == cls.DEFAULT_LANGUAGE:
|
|
99
|
-
language = ""
|
|
100
|
-
|
|
101
|
-
# Build markdown code block
|
|
102
|
-
if language:
|
|
103
|
-
result = f"```{language}\n{code_content}\n```"
|
|
104
|
-
else:
|
|
105
|
-
result = f"```\n{code_content}\n```"
|
|
106
|
-
|
|
107
|
-
# Add caption if present
|
|
108
|
-
if caption_text:
|
|
109
|
-
result += f"\nCaption: {caption_text}"
|
|
110
|
-
|
|
111
|
-
return result
|
|
112
|
-
|
|
113
|
-
@classmethod
|
|
114
|
-
def _normalize_language(cls, language: str) -> CodeLanguage:
|
|
115
|
-
"""
|
|
116
|
-
Normalize the language string to a valid CodeLanguage enum or default.
|
|
117
|
-
"""
|
|
118
|
-
# Try to find matching enum by value
|
|
119
|
-
for lang_enum in CodeLanguage:
|
|
120
|
-
if lang_enum.value.lower() == language.lower():
|
|
121
|
-
return lang_enum
|
|
122
|
-
|
|
123
|
-
# Return default if not found
|
|
124
|
-
return CodeLanguage.PLAIN_TEXT
|
|
125
|
-
|
|
126
|
-
@staticmethod
|
|
127
|
-
def extract_content(rich_text_list: list[RichTextObject]) -> str:
|
|
128
|
-
"""Extract code content from rich_text array."""
|
|
129
|
-
return "".join(rt.plain_text for rt in rich_text_list if rt.plain_text)
|
|
130
|
-
|
|
131
|
-
@staticmethod
|
|
132
|
-
def extract_caption(caption_list: list[RichTextObject]) -> str:
|
|
133
|
-
"""Extract caption text from caption array."""
|
|
134
|
-
return "".join(rt.plain_text for rt in caption_list if rt.plain_text)
|
|
135
|
-
|
|
136
|
-
@classmethod
|
|
137
|
-
def get_system_prompt_information(cls) -> Optional[BlockElementMarkdownInformation]:
|
|
138
|
-
"""Get system prompt information for code blocks."""
|
|
139
|
-
return BlockElementMarkdownInformation(
|
|
140
|
-
block_type=cls.__name__,
|
|
141
|
-
description="Code blocks display syntax-highlighted code with optional language specification and captions",
|
|
142
|
-
syntax_examples=[
|
|
143
|
-
"```\nprint('Hello World')\n```",
|
|
144
|
-
"```python\nprint('Hello World')\n```",
|
|
145
|
-
"```python \"Example code\"\nprint('Hello World')\n```",
|
|
146
|
-
"```javascript\nconsole.log('Hello');\n```",
|
|
147
|
-
],
|
|
148
|
-
usage_guidelines="Use for displaying code snippets. Language specification enables syntax highlighting. Caption in quotes on first line provides description. Supports many programming languages.",
|
|
149
|
-
)
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
|
-
from notionary.blocks.markdown.markdown_node import MarkdownNode
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class CodeMarkdownNode(MarkdownNode):
|
|
7
|
-
"""
|
|
8
|
-
Enhanced Code node with Pydantic integration.
|
|
9
|
-
Programmatic interface for creating Notion-style Markdown code blocks.
|
|
10
|
-
Automatically handles indentation normalization for multiline strings.
|
|
11
|
-
|
|
12
|
-
Example:
|
|
13
|
-
```python "Basic usage"
|
|
14
|
-
print("Hello, world!")
|
|
15
|
-
```
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
code: str
|
|
19
|
-
language: Optional[str] = None
|
|
20
|
-
caption: Optional[str] = None
|
|
21
|
-
|
|
22
|
-
def to_markdown(self) -> str:
|
|
23
|
-
lang = self.language or ""
|
|
24
|
-
|
|
25
|
-
# Build the opening fence with optional caption
|
|
26
|
-
opening_fence = f"```{lang}"
|
|
27
|
-
if self.caption:
|
|
28
|
-
opening_fence += f' "{self.caption}"'
|
|
29
|
-
|
|
30
|
-
# Smart indentation normalization
|
|
31
|
-
normalized_code = self._normalize_indentation(self.code)
|
|
32
|
-
|
|
33
|
-
content = f"{opening_fence}\n{normalized_code}\n```"
|
|
34
|
-
return content
|
|
35
|
-
|
|
36
|
-
def _normalize_indentation(self, code: str) -> str:
|
|
37
|
-
"""Normalize indentation by removing common leading whitespace."""
|
|
38
|
-
lines = code.strip().split("\n")
|
|
39
|
-
|
|
40
|
-
if self._is_empty_or_single_line(lines):
|
|
41
|
-
return self._handle_simple_cases(lines)
|
|
42
|
-
|
|
43
|
-
min_indentation = self._find_minimum_indentation_excluding_first_line(lines)
|
|
44
|
-
return self._remove_common_indentation(lines, min_indentation)
|
|
45
|
-
|
|
46
|
-
def _is_empty_or_single_line(self, lines: list[str]) -> bool:
|
|
47
|
-
return not lines or len(lines) == 1
|
|
48
|
-
|
|
49
|
-
def _handle_simple_cases(self, lines: list[str]) -> str:
|
|
50
|
-
if not lines:
|
|
51
|
-
return ""
|
|
52
|
-
return lines[0].strip()
|
|
53
|
-
|
|
54
|
-
def _find_minimum_indentation_excluding_first_line(self, lines: list[str]) -> int:
|
|
55
|
-
non_empty_lines_after_first = [line for line in lines[1:] if line.strip()]
|
|
56
|
-
|
|
57
|
-
if not non_empty_lines_after_first:
|
|
58
|
-
return 0
|
|
59
|
-
|
|
60
|
-
return min(
|
|
61
|
-
len(line) - len(line.lstrip()) for line in non_empty_lines_after_first
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
def _remove_common_indentation(self, lines: list[str], min_indentation: int) -> str:
|
|
65
|
-
normalized_lines = [lines[0].strip()]
|
|
66
|
-
|
|
67
|
-
for line in lines[1:]:
|
|
68
|
-
normalized_line = self._normalize_single_line(line, min_indentation)
|
|
69
|
-
normalized_lines.append(normalized_line)
|
|
70
|
-
|
|
71
|
-
return "\n".join(normalized_lines)
|
|
72
|
-
|
|
73
|
-
def _normalize_single_line(self, line: str, min_indentation: int) -> str:
|
|
74
|
-
if not line.strip():
|
|
75
|
-
return ""
|
|
76
|
-
|
|
77
|
-
if len(line) > min_indentation:
|
|
78
|
-
return line[min_indentation:]
|
|
79
|
-
|
|
80
|
-
return line.strip()
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
from enum import Enum
|
|
2
|
-
from typing import Literal
|
|
3
|
-
|
|
4
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
5
|
-
|
|
6
|
-
from notionary.blocks.rich_text.rich_text_models import RichTextObject
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class CodeLanguage(str, Enum):
|
|
10
|
-
ABAP = "abap"
|
|
11
|
-
ARDUINO = "arduino"
|
|
12
|
-
BASH = "bash"
|
|
13
|
-
BASIC = "basic"
|
|
14
|
-
C = "c"
|
|
15
|
-
CLOJURE = "clojure"
|
|
16
|
-
COFFEESCRIPT = "coffeescript"
|
|
17
|
-
CPP = "c++"
|
|
18
|
-
CSHARP = "c#"
|
|
19
|
-
CSS = "css"
|
|
20
|
-
DART = "dart"
|
|
21
|
-
DIFF = "diff"
|
|
22
|
-
DOCKER = "docker"
|
|
23
|
-
ELIXIR = "elixir"
|
|
24
|
-
ELM = "elm"
|
|
25
|
-
ERLANG = "erlang"
|
|
26
|
-
FLOW = "flow"
|
|
27
|
-
FORTRAN = "fortran"
|
|
28
|
-
FSHARP = "f#"
|
|
29
|
-
GHERKIN = "gherkin"
|
|
30
|
-
GLSL = "glsl"
|
|
31
|
-
GO = "go"
|
|
32
|
-
GRAPHQL = "graphql"
|
|
33
|
-
GROOVY = "groovy"
|
|
34
|
-
HASKELL = "haskell"
|
|
35
|
-
HTML = "html"
|
|
36
|
-
JAVA = "java"
|
|
37
|
-
JAVASCRIPT = "javascript"
|
|
38
|
-
JSON = "json"
|
|
39
|
-
JULIA = "julia"
|
|
40
|
-
KOTLIN = "kotlin"
|
|
41
|
-
LATEX = "latex"
|
|
42
|
-
LESS = "less"
|
|
43
|
-
LISP = "lisp"
|
|
44
|
-
LIVESCRIPT = "livescript"
|
|
45
|
-
LUA = "lua"
|
|
46
|
-
MAKEFILE = "makefile"
|
|
47
|
-
MARKDOWN = "markdown"
|
|
48
|
-
MARKUP = "markup"
|
|
49
|
-
MATLAB = "matlab"
|
|
50
|
-
MERMAID = "mermaid"
|
|
51
|
-
NIX = "nix"
|
|
52
|
-
OBJECTIVE_C = "objective-c"
|
|
53
|
-
OCAML = "ocaml"
|
|
54
|
-
PASCAL = "pascal"
|
|
55
|
-
PERL = "perl"
|
|
56
|
-
PHP = "php"
|
|
57
|
-
PLAIN_TEXT = "plain text"
|
|
58
|
-
POWERSHELL = "powershell"
|
|
59
|
-
PROLOG = "prolog"
|
|
60
|
-
PROTOBUF = "protobuf"
|
|
61
|
-
PYTHON = "python"
|
|
62
|
-
R = "r"
|
|
63
|
-
REASON = "reason"
|
|
64
|
-
RUBY = "ruby"
|
|
65
|
-
RUST = "rust"
|
|
66
|
-
SASS = "sass"
|
|
67
|
-
SCALA = "scala"
|
|
68
|
-
SCHEME = "scheme"
|
|
69
|
-
SCSS = "scss"
|
|
70
|
-
SHELL = "shell"
|
|
71
|
-
SQL = "sql"
|
|
72
|
-
SWIFT = "swift"
|
|
73
|
-
TYPESCRIPT = "typescript"
|
|
74
|
-
VB_NET = "vb.net"
|
|
75
|
-
VERILOG = "verilog"
|
|
76
|
-
VHDL = "vhdl"
|
|
77
|
-
VISUAL_BASIC = "visual basic"
|
|
78
|
-
WEBASSEMBLY = "webassembly"
|
|
79
|
-
XML = "xml"
|
|
80
|
-
YAML = "yaml"
|
|
81
|
-
JAVA_C_CPP_CSHARP = "java/c/c++/c#"
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
class CodeBlock(BaseModel):
|
|
85
|
-
caption: list[RichTextObject] = Field(default_factory=list)
|
|
86
|
-
rich_text: list[RichTextObject]
|
|
87
|
-
language: CodeLanguage = CodeLanguage.PLAIN_TEXT
|
|
88
|
-
|
|
89
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
class CreateCodeBlock(BaseModel):
|
|
93
|
-
type: Literal["code"] = "code"
|
|
94
|
-
code: CodeBlock
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
from notionary.blocks.column.column_element import ColumnElement
|
|
2
|
-
from notionary.blocks.column.column_list_element import ColumnListElement
|
|
3
|
-
from notionary.blocks.column.column_list_markdown_node import (
|
|
4
|
-
ColumnListMarkdownNode,
|
|
5
|
-
)
|
|
6
|
-
from notionary.blocks.column.column_markdown_node import (
|
|
7
|
-
ColumnMarkdownNode,
|
|
8
|
-
)
|
|
9
|
-
from notionary.blocks.column.column_models import (
|
|
10
|
-
ColumnBlock,
|
|
11
|
-
ColumnListBlock,
|
|
12
|
-
CreateColumnBlock,
|
|
13
|
-
CreateColumnListBlock,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
__all__ = [
|
|
17
|
-
"ColumnElement",
|
|
18
|
-
"ColumnListElement",
|
|
19
|
-
"ColumnBlock",
|
|
20
|
-
"CreateColumnBlock",
|
|
21
|
-
"ColumnListBlock",
|
|
22
|
-
"CreateColumnListBlock",
|
|
23
|
-
"ColumnMarkdownNode",
|
|
24
|
-
"ColumnListMarkdownNode",
|
|
25
|
-
]
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
from typing import Optional
|
|
5
|
-
|
|
6
|
-
from notionary.blocks.base_block_element import BaseBlockElement
|
|
7
|
-
from notionary.blocks.column.column_models import ColumnBlock, CreateColumnBlock
|
|
8
|
-
from notionary.blocks.syntax_prompt_builder import BlockElementMarkdownInformation
|
|
9
|
-
from notionary.blocks.models import Block, BlockCreateResult, BlockType
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class ColumnElement(BaseBlockElement):
|
|
13
|
-
"""
|
|
14
|
-
Handles individual `::: column` blocks with optional width ratio.
|
|
15
|
-
Content is automatically added by the stack processor.
|
|
16
|
-
|
|
17
|
-
Supported syntax:
|
|
18
|
-
- `::: column` (equal width)
|
|
19
|
-
- `::: column 0.5` (50% width)
|
|
20
|
-
- `::: column 0.25` (25% width)
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
COLUMN_START = re.compile(r"^:::\s*column(?:\s+(0?\.\d+|1\.0?))?\s*$")
|
|
24
|
-
|
|
25
|
-
@classmethod
|
|
26
|
-
def match_notion(cls, block: Block) -> bool:
|
|
27
|
-
"""Check if block is a Notion column."""
|
|
28
|
-
return block.type == BlockType.COLUMN and block.column
|
|
29
|
-
|
|
30
|
-
@classmethod
|
|
31
|
-
async def markdown_to_notion(cls, text: str) -> BlockCreateResult:
|
|
32
|
-
"""Convert `::: column [ratio]` to Notion ColumnBlock."""
|
|
33
|
-
if not (match := cls.COLUMN_START.match(text.strip())):
|
|
34
|
-
return None
|
|
35
|
-
|
|
36
|
-
ratio_str = match.group(1)
|
|
37
|
-
width_ratio = None
|
|
38
|
-
|
|
39
|
-
if ratio_str:
|
|
40
|
-
try:
|
|
41
|
-
width_ratio = float(ratio_str)
|
|
42
|
-
# Validate ratio is between 0 and 1
|
|
43
|
-
if not (0 < width_ratio <= 1.0):
|
|
44
|
-
width_ratio = None # Invalid ratio, use default
|
|
45
|
-
except ValueError:
|
|
46
|
-
width_ratio = None # Invalid format, use default
|
|
47
|
-
|
|
48
|
-
column_content = ColumnBlock(width_ratio=width_ratio)
|
|
49
|
-
return CreateColumnBlock(column=column_content)
|
|
50
|
-
|
|
51
|
-
@classmethod
|
|
52
|
-
async def notion_to_markdown(cls, block: Block) -> str:
|
|
53
|
-
"""Convert Notion column to markdown."""
|
|
54
|
-
if not cls.match_notion(block):
|
|
55
|
-
return ""
|
|
56
|
-
|
|
57
|
-
if not block.column.width_ratio:
|
|
58
|
-
return "::: column"
|
|
59
|
-
|
|
60
|
-
return f"::: column {block.column.width_ratio}"
|
|
61
|
-
|
|
62
|
-
@classmethod
|
|
63
|
-
def get_system_prompt_information(cls) -> Optional[BlockElementMarkdownInformation]:
|
|
64
|
-
"""Column elements are documented via ColumnListElement - return None to avoid duplication."""
|
|
65
|
-
return None
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
import re
|
|
3
|
-
|
|
4
|
-
from notionary.blocks.base_block_element import BaseBlockElement
|
|
5
|
-
from notionary.blocks.column.column_models import ColumnListBlock, CreateColumnListBlock
|
|
6
|
-
from notionary.blocks.syntax_prompt_builder import BlockElementMarkdownInformation
|
|
7
|
-
from notionary.blocks.models import Block, BlockCreateResult
|
|
8
|
-
from notionary.blocks.types import BlockType
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class ColumnListElement(BaseBlockElement):
|
|
12
|
-
"""
|
|
13
|
-
Handles the `::: columns` container.
|
|
14
|
-
Individual columns are handled by ColumnElement.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
COLUMNS_START = re.compile(r"^:::\s*columns\s*$")
|
|
18
|
-
|
|
19
|
-
@classmethod
|
|
20
|
-
def match_markdown(cls, text: str) -> bool:
|
|
21
|
-
"""Check if text starts a columns container."""
|
|
22
|
-
return bool(cls.COLUMNS_START.match(text.strip()))
|
|
23
|
-
|
|
24
|
-
@classmethod
|
|
25
|
-
def match_notion(cls, block: Block) -> bool:
|
|
26
|
-
"""Check if block is a Notion column_list."""
|
|
27
|
-
return block.type == BlockType.COLUMN_LIST and block.column_list
|
|
28
|
-
|
|
29
|
-
@classmethod
|
|
30
|
-
async def markdown_to_notion(cls, text: str) -> BlockCreateResult:
|
|
31
|
-
"""Convert `::: columns` to Notion ColumnListBlock."""
|
|
32
|
-
if not cls.COLUMNS_START.match(text.strip()):
|
|
33
|
-
return None
|
|
34
|
-
|
|
35
|
-
# Empty ColumnListBlock - children (columns) added by stack processor
|
|
36
|
-
column_list_content = ColumnListBlock()
|
|
37
|
-
return CreateColumnListBlock(column_list=column_list_content)
|
|
38
|
-
|
|
39
|
-
@classmethod
|
|
40
|
-
@classmethod
|
|
41
|
-
def get_system_prompt_information(cls) -> Optional[BlockElementMarkdownInformation]:
|
|
42
|
-
"""Get system prompt information for column list blocks."""
|
|
43
|
-
return BlockElementMarkdownInformation(
|
|
44
|
-
block_type=cls.__name__,
|
|
45
|
-
description="Column list containers organize multiple columns in side-by-side layouts",
|
|
46
|
-
syntax_examples=[
|
|
47
|
-
"::: columns\n::: column\nContent 1\n:::\n::: column\nContent 2\n:::\n:::",
|
|
48
|
-
"::: columns\n::: column 0.6\nMain content\n:::\n::: column 0.4\nSidebar\n:::\n:::",
|
|
49
|
-
"::: columns\n::: column 0.25\nLeft\n:::\n::: column 0.5\nCenter\n:::\n::: column 0.25\nRight\n:::\n:::",
|
|
50
|
-
],
|
|
51
|
-
usage_guidelines="Use to create multi-column layouts with at least 2 columns. Column width ratios must add up to 1.0 when specified. Each column can contain any block content. Ends with :::.",
|
|
52
|
-
)
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
from notionary.blocks.column.column_markdown_node import ColumnMarkdownNode
|
|
2
|
-
from notionary.blocks.markdown.markdown_node import MarkdownNode
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class ColumnListMarkdownNode(MarkdownNode):
|
|
6
|
-
"""
|
|
7
|
-
Enhanced Column List node with Pydantic integration.
|
|
8
|
-
Programmatic interface for creating a Markdown column list container.
|
|
9
|
-
This represents the `::: columns` container that holds multiple columns.
|
|
10
|
-
|
|
11
|
-
Example:
|
|
12
|
-
::: columns
|
|
13
|
-
::: column
|
|
14
|
-
Left content
|
|
15
|
-
with nested lines
|
|
16
|
-
:::
|
|
17
|
-
|
|
18
|
-
::: column 0.3
|
|
19
|
-
Right content (30% width)
|
|
20
|
-
with nested lines
|
|
21
|
-
:::
|
|
22
|
-
:::
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
columns: list[ColumnMarkdownNode] = []
|
|
26
|
-
|
|
27
|
-
def to_markdown(self) -> str:
|
|
28
|
-
if not self.columns:
|
|
29
|
-
return "::: columns\n:::"
|
|
30
|
-
|
|
31
|
-
column_parts = [column.to_markdown() for column in self.columns]
|
|
32
|
-
columns_content = "\n\n".join(column_parts)
|
|
33
|
-
|
|
34
|
-
return f"::: columns\n{columns_content}\n:::"
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
from notionary.blocks.markdown.markdown_node import MarkdownNode
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class ColumnMarkdownNode(MarkdownNode):
|
|
6
|
-
"""
|
|
7
|
-
Enhanced Column node with Pydantic integration.
|
|
8
|
-
Programmatic interface for creating a single Markdown column block
|
|
9
|
-
with nested content and optional width ratio.
|
|
10
|
-
|
|
11
|
-
Example:
|
|
12
|
-
::: column
|
|
13
|
-
# Column Title
|
|
14
|
-
|
|
15
|
-
Some content here
|
|
16
|
-
:::
|
|
17
|
-
|
|
18
|
-
::: column 0.7
|
|
19
|
-
# Wide Column (70%)
|
|
20
|
-
|
|
21
|
-
This column takes 70% width
|
|
22
|
-
:::
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
children: list[MarkdownNode] = []
|
|
26
|
-
width_ratio: Optional[float] = None
|
|
27
|
-
|
|
28
|
-
def to_markdown(self) -> str:
|
|
29
|
-
# Start tag with optional width ratio
|
|
30
|
-
if self.width_ratio is not None:
|
|
31
|
-
start_tag = f"::: column {self.width_ratio}"
|
|
32
|
-
else:
|
|
33
|
-
start_tag = "::: column"
|
|
34
|
-
|
|
35
|
-
if not self.children:
|
|
36
|
-
return f"{start_tag}\n:::"
|
|
37
|
-
|
|
38
|
-
# Convert children to markdown
|
|
39
|
-
content_parts = [child.to_markdown() for child in self.children]
|
|
40
|
-
content_text = "\n\n".join(content_parts)
|
|
41
|
-
|
|
42
|
-
return f"{start_tag}\n{content_text}\n:::"
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import Literal, Optional
|
|
4
|
-
|
|
5
|
-
from pydantic import BaseModel, Field
|
|
6
|
-
|
|
7
|
-
from notionary.blocks.models import BlockCreateRequest
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class ColumnBlock(BaseModel):
|
|
11
|
-
width_ratio: Optional[float] = None
|
|
12
|
-
children: list[BlockCreateRequest] = Field(default_factory=list)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class CreateColumnBlock(BaseModel):
|
|
16
|
-
type: Literal["column"] = "column"
|
|
17
|
-
column: ColumnBlock
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class ColumnListBlock(BaseModel):
|
|
21
|
-
children: list[CreateColumnBlock] = Field(default_factory=list)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class CreateColumnListBlock(BaseModel):
|
|
25
|
-
type: Literal["column_list"] = "column_list"
|
|
26
|
-
column_list: ColumnListBlock
|