notionary 0.2.27__py3-none-any.whl → 0.2.28__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/client.py +87 -215
- notionary/blocks/enums.py +167 -0
- notionary/blocks/rich_text/markdown_rich_text_converter.py +266 -0
- notionary/blocks/rich_text/models.py +164 -0
- notionary/blocks/rich_text/name_id_resolver/__init__.py +11 -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 +132 -0
- notionary/blocks/rich_text/rich_text_patterns.py +39 -0
- notionary/blocks/schemas.py +746 -0
- notionary/comments/client.py +52 -187
- notionary/comments/factory.py +40 -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 +94 -0
- notionary/data_source/properties/models.py +406 -0
- notionary/data_source/query/builder.py +429 -0
- notionary/data_source/query/resolver.py +114 -0
- notionary/data_source/query/schema.py +304 -0
- notionary/data_source/query/validator.py +73 -0
- notionary/data_source/schemas.py +27 -0
- notionary/data_source/service.py +353 -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 +169 -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 +33 -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 +205 -0
- notionary/http/models.py +49 -0
- notionary/page/blocks/client.py +1 -0
- notionary/page/content/factory.py +68 -0
- notionary/page/content/markdown/__init__.py +5 -0
- notionary/page/content/markdown/builder.py +304 -0
- notionary/page/content/markdown/nodes/__init__.py +54 -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 +18 -0
- notionary/page/content/markdown/nodes/callout.py +32 -0
- notionary/page/content/markdown/nodes/code.py +30 -0
- notionary/page/content/markdown/nodes/columns.py +51 -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 +16 -0
- notionary/page/content/markdown/nodes/image.py +23 -0
- notionary/page/content/markdown/nodes/mixins/caption.py +12 -0
- notionary/page/content/markdown/nodes/numbered_list.py +15 -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 +15 -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 +22 -0
- notionary/page/content/markdown/nodes/toggle.py +28 -0
- notionary/page/content/markdown/nodes/toggleable_heading.py +35 -0
- notionary/page/content/markdown/nodes/video.py +23 -0
- notionary/page/content/parser/context.py +49 -0
- notionary/page/content/parser/factory.py +219 -0
- notionary/page/content/parser/parsers/__init__.py +60 -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 +41 -0
- notionary/page/content/parser/parsers/callout.py +129 -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 +117 -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 +58 -0
- notionary/page/content/parser/parsers/image.py +42 -0
- notionary/page/content/parser/parsers/numbered_list.py +45 -0
- notionary/page/content/parser/parsers/paragraph.py +36 -0
- notionary/page/content/parser/parsers/pdf.py +42 -0
- notionary/page/content/parser/parsers/quote.py +65 -0
- notionary/page/content/parser/parsers/space.py +35 -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 +58 -0
- notionary/page/content/parser/parsers/toggle.py +127 -0
- notionary/page/content/parser/parsers/toggleable_heading.py +150 -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 +93 -0
- notionary/page/content/parser/post_processing/handlers/rich_text_length_truncation.py +93 -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 +9 -0
- notionary/page/content/parser/pre_processsing/handlers/column_syntax.py +80 -0
- notionary/page/content/parser/pre_processsing/handlers/port.py +7 -0
- notionary/page/content/parser/pre_processsing/handlers/whitespace.py +68 -0
- notionary/page/content/parser/pre_processsing/service.py +15 -0
- notionary/page/content/parser/service.py +69 -0
- notionary/page/content/renderer/context.py +48 -0
- notionary/page/content/renderer/factory.py +240 -0
- notionary/page/content/renderer/post_processing/handlers/__init__.py +5 -0
- notionary/page/content/renderer/post_processing/handlers/numbered_list_placeholdere.py +62 -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 +57 -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 +65 -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 +44 -0
- notionary/page/content/renderer/renderers/column_list.py +31 -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 +69 -0
- notionary/page/content/renderer/renderers/image.py +31 -0
- notionary/page/content/renderer/renderers/numbered_list.py +41 -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 +53 -0
- notionary/page/content/renderer/renderers/toggleable_heading.py +78 -0
- notionary/page/content/renderer/renderers/video.py +31 -0
- notionary/page/content/renderer/service.py +50 -0
- notionary/page/content/service.py +65 -0
- notionary/page/content/syntax/models.py +68 -0
- notionary/page/content/syntax/service.py +453 -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 +307 -0
- notionary/page/properties/service.py +257 -0
- notionary/page/schemas.py +13 -0
- notionary/page/service.py +222 -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/user/__init__.py +4 -8
- notionary/user/base.py +89 -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/async_retry.py +39 -0
- notionary/utils/date.py +51 -0
- notionary/utils/fuzzy.py +56 -0
- notionary/{util/logging_mixin.py → utils/mixins/logging.py} +4 -16
- notionary/utils/pagination.py +50 -0
- notionary/utils/singleton.py +13 -0
- notionary/utils/uuid_utils.py +20 -0
- notionary/workspace/__init__.py +3 -0
- notionary/workspace/client.py +62 -0
- notionary/workspace/query/builder.py +60 -0
- notionary/workspace/query/models.py +60 -0
- notionary/workspace/query/service.py +93 -0
- notionary/workspace/schemas.py +21 -0
- notionary/workspace/service.py +116 -0
- {notionary-0.2.27.dist-info → notionary-0.2.28.dist-info}/METADATA +54 -49
- notionary-0.2.28.dist-info/RECORD +200 -0
- {notionary-0.2.27.dist-info → notionary-0.2.28.dist-info}/WHEEL +1 -1
- {notionary-0.2.27.dist-info → notionary-0.2.28.dist-info/licenses}/LICENSE +9 -9
- notionary/base_notion_client.py +0 -219
- notionary/blocks/__init__.py +0 -5
- 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/comments/__init__.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/factory.py +0 -0
- 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/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/RECORD +0 -202
notionary/schemas/base.py
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
NotionContentSchema Base Class
|
3
|
-
=============================
|
4
|
-
|
5
|
-
Base class for all Notion structured output schemas with injected MarkdownBuilder
|
6
|
-
"""
|
7
|
-
|
8
|
-
from pydantic import BaseModel
|
9
|
-
from notionary.blocks.markdown.markdown_builder import MarkdownBuilder
|
10
|
-
|
11
|
-
|
12
|
-
class NotionContentSchema(BaseModel):
|
13
|
-
"""
|
14
|
-
Base class for all Notion content schemas.
|
15
|
-
|
16
|
-
Inherit from this and implement to_notion_content() to create
|
17
|
-
schemas that work with LLM structured output.
|
18
|
-
|
19
|
-
Example usage:
|
20
|
-
|
21
|
-
class BlogPost(NotionContentSchema):
|
22
|
-
title: str = Field(description="Catchy blog post title")
|
23
|
-
introduction: str = Field(description="Engaging opening paragraph")
|
24
|
-
main_points: List[str] = Field(description="3-5 key takeaways")
|
25
|
-
conclusion: str = Field(description="Summary and call-to-action")
|
26
|
-
|
27
|
-
def to_notion_content(self, builder: MarkdownBuilder) -> str:
|
28
|
-
return (builder
|
29
|
-
.h1(self.title)
|
30
|
-
.paragraph(self.introduction)
|
31
|
-
.h2("Key Points")
|
32
|
-
.bulleted_list(self.main_points)
|
33
|
-
.h2("Conclusion")
|
34
|
-
.paragraph(self.conclusion)
|
35
|
-
.build()
|
36
|
-
)
|
37
|
-
|
38
|
-
# Usage with LLM:
|
39
|
-
llm = ChatOpenAI(model="gpt-4o")
|
40
|
-
structured_llm = llm.with_structured_output(BlogPost)
|
41
|
-
blog = structured_llm.invoke("Write about Python async/await")
|
42
|
-
|
43
|
-
# Upload to Notion:
|
44
|
-
await blog.append_to_page("My Blog")
|
45
|
-
"""
|
46
|
-
|
47
|
-
def to_notion_content(self, builder: MarkdownBuilder) -> str:
|
48
|
-
"""
|
49
|
-
Build Notion content using the provided MarkdownBuilder.
|
50
|
-
|
51
|
-
Args:
|
52
|
-
builder: Empty MarkdownBuilder instance to build content with
|
53
|
-
|
54
|
-
Returns:
|
55
|
-
str: The final markdown string (user should call build() on the builder)
|
56
|
-
"""
|
57
|
-
raise NotImplementedError("Subclasses must implement to_notion_content()")
|
58
|
-
|
59
|
-
async def append_to_page(self, page_name: str):
|
60
|
-
"""
|
61
|
-
Upload this content directly to a Notion page.
|
62
|
-
|
63
|
-
Args:
|
64
|
-
page_name: Name of the target Notion page
|
65
|
-
"""
|
66
|
-
from notionary import NotionPage
|
67
|
-
|
68
|
-
# Create fresh builder and let subclass build content
|
69
|
-
builder = MarkdownBuilder()
|
70
|
-
markdown = self.to_notion_content(builder)
|
71
|
-
|
72
|
-
page = await NotionPage.from_page_name(page_name)
|
73
|
-
await page.append_markdown(markdown)
|
notionary/shared/__init__.py
DELETED
@@ -1,203 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from typing import Optional
|
4
|
-
|
5
|
-
from notionary.user.notion_user_manager import NotionUserManager
|
6
|
-
from notionary.util import format_uuid
|
7
|
-
from notionary.util.fuzzy import find_best_match
|
8
|
-
|
9
|
-
|
10
|
-
class NameIdResolver:
|
11
|
-
"""
|
12
|
-
Bidirectional resolver for Notion page and database names and IDs.
|
13
|
-
"""
|
14
|
-
|
15
|
-
def __init__(
|
16
|
-
self,
|
17
|
-
*,
|
18
|
-
token: Optional[str] = None,
|
19
|
-
search_limit: int = 10,
|
20
|
-
):
|
21
|
-
"""
|
22
|
-
Initialize the resolver with a Notion workspace.
|
23
|
-
"""
|
24
|
-
from notionary import NotionWorkspace
|
25
|
-
|
26
|
-
self.workspace = NotionWorkspace(token=token)
|
27
|
-
self.notion_user_manager = NotionUserManager(token=token)
|
28
|
-
self.search_limit = search_limit
|
29
|
-
|
30
|
-
async def resolve_page_id(self, name: str) -> Optional[str]:
|
31
|
-
"""
|
32
|
-
Convert a page name to its Notion page ID.
|
33
|
-
Specifically searches only pages, not databases.
|
34
|
-
"""
|
35
|
-
if not name:
|
36
|
-
return None
|
37
|
-
|
38
|
-
cleaned_name = name.strip()
|
39
|
-
|
40
|
-
# Return if already a valid Notion ID
|
41
|
-
formatted_uuid = format_uuid(cleaned_name)
|
42
|
-
if formatted_uuid:
|
43
|
-
return formatted_uuid
|
44
|
-
|
45
|
-
# Search for page by name
|
46
|
-
return await self._resolve_page_id(cleaned_name)
|
47
|
-
|
48
|
-
async def resolve_database_id(self, name: str) -> Optional[str]:
|
49
|
-
"""
|
50
|
-
Convert a database name to its Notion database ID.
|
51
|
-
Specifically searches only databases, not pages.
|
52
|
-
"""
|
53
|
-
if not name:
|
54
|
-
return None
|
55
|
-
|
56
|
-
cleaned_name = name.strip()
|
57
|
-
|
58
|
-
formatted_uuid = format_uuid(cleaned_name)
|
59
|
-
if formatted_uuid:
|
60
|
-
return formatted_uuid
|
61
|
-
|
62
|
-
return await self._resolve_database_id(cleaned_name)
|
63
|
-
|
64
|
-
async def resolve_page_name(self, page_id: str) -> Optional[str]:
|
65
|
-
"""
|
66
|
-
Convert a Notion page ID to its human-readable title.
|
67
|
-
"""
|
68
|
-
if not page_id:
|
69
|
-
return None
|
70
|
-
|
71
|
-
formatted_id = format_uuid(page_id)
|
72
|
-
if not formatted_id:
|
73
|
-
return None
|
74
|
-
|
75
|
-
try:
|
76
|
-
from notionary import NotionPage
|
77
|
-
|
78
|
-
page = await NotionPage.from_page_id(formatted_id)
|
79
|
-
return page.title if page else None
|
80
|
-
except Exception:
|
81
|
-
return None
|
82
|
-
|
83
|
-
async def resolve_database_name(self, database_id: str) -> Optional[str]:
|
84
|
-
"""
|
85
|
-
Convert a Notion database ID to its human-readable title.
|
86
|
-
"""
|
87
|
-
if not database_id:
|
88
|
-
return None
|
89
|
-
|
90
|
-
# Validate and format UUID
|
91
|
-
formatted_id = format_uuid(database_id)
|
92
|
-
if not formatted_id:
|
93
|
-
return None
|
94
|
-
|
95
|
-
try:
|
96
|
-
from notionary.database import NotionDatabase
|
97
|
-
|
98
|
-
database = await NotionDatabase.from_database_id(formatted_id)
|
99
|
-
return database.title if database else None
|
100
|
-
except Exception:
|
101
|
-
return None
|
102
|
-
|
103
|
-
async def resolve_user_id(self, name: str) -> Optional[str]:
|
104
|
-
"""
|
105
|
-
Convert a user name to its Notion user ID.
|
106
|
-
Specifically searches only users.
|
107
|
-
"""
|
108
|
-
if not name:
|
109
|
-
return None
|
110
|
-
|
111
|
-
cleaned_name = name.strip()
|
112
|
-
|
113
|
-
# Return if already a valid Notion ID
|
114
|
-
formatted_uuid = format_uuid(cleaned_name)
|
115
|
-
if formatted_uuid:
|
116
|
-
return formatted_uuid
|
117
|
-
|
118
|
-
# Search for user by name
|
119
|
-
return await self._resolve_user_id(cleaned_name)
|
120
|
-
|
121
|
-
async def resolve_user_name(self, user_id: str) -> Optional[str]:
|
122
|
-
"""
|
123
|
-
Convert a Notion user ID to its human-readable name.
|
124
|
-
|
125
|
-
Args:
|
126
|
-
user_id: Notion user ID to resolve
|
127
|
-
|
128
|
-
Returns:
|
129
|
-
User name if found, None if not found or inaccessible
|
130
|
-
"""
|
131
|
-
if not user_id:
|
132
|
-
return None
|
133
|
-
|
134
|
-
# Validate and format UUID
|
135
|
-
formatted_id = format_uuid(user_id)
|
136
|
-
if not formatted_id:
|
137
|
-
return None
|
138
|
-
|
139
|
-
try:
|
140
|
-
user = await self.notion_user_manager.get_user_by_id(formatted_id)
|
141
|
-
return user.name if user else None
|
142
|
-
except Exception:
|
143
|
-
return None
|
144
|
-
|
145
|
-
async def _resolve_user_id(self, name: str) -> Optional[str]:
|
146
|
-
"""Search for users matching the name."""
|
147
|
-
try:
|
148
|
-
users = await self.notion_user_manager.find_users_by_name(name)
|
149
|
-
|
150
|
-
if not users:
|
151
|
-
return None
|
152
|
-
|
153
|
-
# Use fuzzy matching to find best match
|
154
|
-
best_match = find_best_match(
|
155
|
-
query=name,
|
156
|
-
items=users,
|
157
|
-
text_extractor=lambda user: user.name or "",
|
158
|
-
)
|
159
|
-
|
160
|
-
return best_match.item.id if best_match else None
|
161
|
-
except Exception:
|
162
|
-
return None
|
163
|
-
|
164
|
-
async def _resolve_page_id(self, name: str) -> Optional[str]:
|
165
|
-
"""Search for pages matching the name."""
|
166
|
-
search_results = await self.workspace.search_pages(
|
167
|
-
query=name, limit=self.search_limit
|
168
|
-
)
|
169
|
-
|
170
|
-
return self._find_best_fuzzy_match(query=name, candidate_objects=search_results)
|
171
|
-
|
172
|
-
async def _resolve_database_id(self, name: str) -> Optional[str]:
|
173
|
-
"""Search for databases matching the name."""
|
174
|
-
search_results = await self.workspace.search_databases(
|
175
|
-
query=name, limit=self.search_limit
|
176
|
-
)
|
177
|
-
|
178
|
-
return self._find_best_fuzzy_match(query=name, candidate_objects=search_results)
|
179
|
-
|
180
|
-
def _find_best_fuzzy_match(
|
181
|
-
self, query: str, candidate_objects: list
|
182
|
-
) -> Optional[str]:
|
183
|
-
"""
|
184
|
-
Find the best fuzzy match among candidate objects using existing fuzzy matching logic.
|
185
|
-
|
186
|
-
Args:
|
187
|
-
query: The search query to match against
|
188
|
-
candidate_objects: Objects (pages or databases) with .id and .title attributes
|
189
|
-
|
190
|
-
Returns:
|
191
|
-
ID of best match, or None if no match meets threshold
|
192
|
-
"""
|
193
|
-
if not candidate_objects:
|
194
|
-
return None
|
195
|
-
|
196
|
-
# Use existing fuzzy matching logic
|
197
|
-
best_match = find_best_match(
|
198
|
-
query=query,
|
199
|
-
items=candidate_objects,
|
200
|
-
text_extractor=lambda obj: obj.title,
|
201
|
-
)
|
202
|
-
|
203
|
-
return best_match.item.id if best_match else None
|
notionary/telemetry/__init__.py
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
from .service import ProductTelemetry
|
2
|
-
from .views import (
|
3
|
-
BaseTelemetryEvent,
|
4
|
-
DatabaseFactoryUsedEvent,
|
5
|
-
MarkdownToNotionConversionEvent,
|
6
|
-
NotionMarkdownSyntaxPromptEvent,
|
7
|
-
NotionToMarkdownConversionEvent,
|
8
|
-
QueryOperationEvent,
|
9
|
-
)
|
10
|
-
|
11
|
-
__all__ = [
|
12
|
-
"ProductTelemetry",
|
13
|
-
"BaseTelemetryEvent",
|
14
|
-
"DatabaseFactoryUsedEvent",
|
15
|
-
"QueryOperationEvent",
|
16
|
-
"NotionMarkdownSyntaxPromptEvent",
|
17
|
-
"MarkdownToNotionConversionEvent",
|
18
|
-
"NotionToMarkdownConversionEvent",
|
19
|
-
]
|
notionary/telemetry/service.py
DELETED
@@ -1,136 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
import uuid
|
3
|
-
from pathlib import Path
|
4
|
-
|
5
|
-
from dotenv import load_dotenv
|
6
|
-
from posthog import Posthog
|
7
|
-
|
8
|
-
from notionary.telemetry.views import BaseTelemetryEvent
|
9
|
-
from notionary.util import LoggingMixin, SingletonMetaClass
|
10
|
-
|
11
|
-
load_dotenv()
|
12
|
-
|
13
|
-
POSTHOG_EVENT_SETTINGS = {
|
14
|
-
"process_person_profile": True,
|
15
|
-
}
|
16
|
-
|
17
|
-
|
18
|
-
class ProductTelemetry(LoggingMixin, metaclass=SingletonMetaClass):
|
19
|
-
"""
|
20
|
-
Anonymous telemetry for Notionary - enabled by default.
|
21
|
-
Disable via: ANONYMIZED_NOTIONARY_TELEMETRY=false
|
22
|
-
"""
|
23
|
-
|
24
|
-
USER_ID_PATH = str(Path.home() / ".cache" / "notionary" / "telemetry_user_id")
|
25
|
-
PROJECT_API_KEY = "phc_gItKOx21Tc0l07C1taD0QPpqFnbWgWjVfRjF6z24kke"
|
26
|
-
HOST = "https://eu.i.posthog.com"
|
27
|
-
UNKNOWN_USER_ID = "UNKNOWN"
|
28
|
-
|
29
|
-
_logged_init_message = False
|
30
|
-
_curr_user_id = None
|
31
|
-
|
32
|
-
def __init__(self):
|
33
|
-
# Default: enabled, disable via environment variable
|
34
|
-
telemetry_setting = os.getenv("ANONYMIZED_NOTIONARY_TELEMETRY", "true").lower()
|
35
|
-
telemetry_disabled = telemetry_setting == "false"
|
36
|
-
self.debug_logging = os.getenv("NOTIONARY_DEBUG", "false").lower() == "true"
|
37
|
-
|
38
|
-
if telemetry_disabled:
|
39
|
-
self._posthog_client = None
|
40
|
-
else:
|
41
|
-
if not self._logged_init_message:
|
42
|
-
self.logger.info(
|
43
|
-
"Anonymous telemetry enabled to improve Notionary. "
|
44
|
-
"To disable: export ANONYMIZED_NOTIONARY_TELEMETRY=false"
|
45
|
-
)
|
46
|
-
self._logged_init_message = True
|
47
|
-
|
48
|
-
self._posthog_client = Posthog(
|
49
|
-
project_api_key=self.PROJECT_API_KEY,
|
50
|
-
host=self.HOST,
|
51
|
-
disable_geoip=True,
|
52
|
-
enable_exception_autocapture=True,
|
53
|
-
)
|
54
|
-
|
55
|
-
# Silence posthog's logging unless debug mode
|
56
|
-
if not self.debug_logging:
|
57
|
-
import logging
|
58
|
-
|
59
|
-
posthog_logger = logging.getLogger("posthog")
|
60
|
-
posthog_logger.disabled = True
|
61
|
-
|
62
|
-
if self._posthog_client is None:
|
63
|
-
self.logger.debug("Telemetry disabled")
|
64
|
-
|
65
|
-
def capture(self, event: BaseTelemetryEvent) -> None:
|
66
|
-
"""
|
67
|
-
Safe event tracking that never affects library functionality
|
68
|
-
|
69
|
-
Args:
|
70
|
-
event: BaseTelemetryEvent instance to capture
|
71
|
-
"""
|
72
|
-
if self._posthog_client is None:
|
73
|
-
return
|
74
|
-
|
75
|
-
self._direct_capture(event)
|
76
|
-
|
77
|
-
def _direct_capture(self, event: BaseTelemetryEvent) -> None:
|
78
|
-
"""
|
79
|
-
Direct capture method - PostHog handles threading internally
|
80
|
-
Should not be thread blocking because posthog magically handles it
|
81
|
-
"""
|
82
|
-
if self._posthog_client is None:
|
83
|
-
return
|
84
|
-
|
85
|
-
try:
|
86
|
-
self._posthog_client.capture(
|
87
|
-
distinct_id=self.user_id,
|
88
|
-
event=event.name,
|
89
|
-
properties={
|
90
|
-
"library": "notionary",
|
91
|
-
**event.properties,
|
92
|
-
**POSTHOG_EVENT_SETTINGS,
|
93
|
-
},
|
94
|
-
)
|
95
|
-
|
96
|
-
except Exception as e:
|
97
|
-
self.logger.error(f"Failed to send telemetry event {event.name}: {e}")
|
98
|
-
|
99
|
-
def flush(self) -> None:
|
100
|
-
"""
|
101
|
-
Flush pending events - simplified without threading complexity
|
102
|
-
"""
|
103
|
-
if not self._posthog_client:
|
104
|
-
self.logger.debug("PostHog client not available, skipping flush.")
|
105
|
-
return
|
106
|
-
|
107
|
-
try:
|
108
|
-
self._posthog_client.flush()
|
109
|
-
self.logger.debug("PostHog client telemetry queue flushed.")
|
110
|
-
except Exception as e:
|
111
|
-
self.logger.error(f"Failed to flush PostHog client: {e}")
|
112
|
-
|
113
|
-
@property
|
114
|
-
def user_id(self) -> str:
|
115
|
-
"""Anonymous, persistent user ID"""
|
116
|
-
if self._curr_user_id:
|
117
|
-
return self._curr_user_id
|
118
|
-
|
119
|
-
# File access may fail due to permissions or other reasons.
|
120
|
-
# We don't want to crash so we catch all exceptions.
|
121
|
-
try:
|
122
|
-
if not os.path.exists(self.USER_ID_PATH):
|
123
|
-
os.makedirs(os.path.dirname(self.USER_ID_PATH), exist_ok=True)
|
124
|
-
with open(self.USER_ID_PATH, "w") as f:
|
125
|
-
new_user_id = str(uuid.uuid4())
|
126
|
-
f.write(new_user_id)
|
127
|
-
self._curr_user_id = new_user_id
|
128
|
-
else:
|
129
|
-
with open(self.USER_ID_PATH, "r") as f:
|
130
|
-
self._curr_user_id = f.read().strip()
|
131
|
-
|
132
|
-
return self._curr_user_id
|
133
|
-
except Exception as e:
|
134
|
-
self.logger.debug(f"Error getting user ID: {e}")
|
135
|
-
self._curr_user_id = self.UNKNOWN_USER_ID
|
136
|
-
return self._curr_user_id
|
notionary/telemetry/views.py
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
from abc import ABC, abstractmethod
|
2
|
-
from dataclasses import asdict, dataclass
|
3
|
-
from typing import Any, Optional
|
4
|
-
|
5
|
-
|
6
|
-
@dataclass
|
7
|
-
class BaseTelemetryEvent(ABC):
|
8
|
-
@property
|
9
|
-
@abstractmethod
|
10
|
-
def name(self) -> str:
|
11
|
-
pass
|
12
|
-
|
13
|
-
@property
|
14
|
-
def properties(self) -> dict[str, Any]:
|
15
|
-
return {k: v for k, v in asdict(self).items() if k != "name"}
|
16
|
-
|
17
|
-
|
18
|
-
@dataclass
|
19
|
-
class DatabaseFactoryUsedEvent(BaseTelemetryEvent):
|
20
|
-
"""Event fired when a database factory method is used"""
|
21
|
-
|
22
|
-
factory_method: str
|
23
|
-
|
24
|
-
@property
|
25
|
-
def name(self) -> str:
|
26
|
-
return "database_factory_used"
|
27
|
-
|
28
|
-
|
29
|
-
@dataclass
|
30
|
-
class QueryOperationEvent(BaseTelemetryEvent):
|
31
|
-
"""Event fired when a query operation is performed"""
|
32
|
-
|
33
|
-
query_type: str
|
34
|
-
|
35
|
-
@property
|
36
|
-
def name(self) -> str:
|
37
|
-
return "query_operation"
|
38
|
-
|
39
|
-
|
40
|
-
@dataclass
|
41
|
-
class NotionMarkdownSyntaxPromptEvent(BaseTelemetryEvent):
|
42
|
-
"""Event fired when Notion Markdown syntax is used"""
|
43
|
-
|
44
|
-
@property
|
45
|
-
def name(self) -> str:
|
46
|
-
return "notion_markdown_syntax_used"
|
47
|
-
|
48
|
-
|
49
|
-
# Tracks markdown conversion
|
50
|
-
@dataclass
|
51
|
-
class MarkdownToNotionConversionEvent(BaseTelemetryEvent):
|
52
|
-
"""Event fired when markdown is converted to Notion blocks"""
|
53
|
-
|
54
|
-
handler_element_name: Optional[str] = (
|
55
|
-
None # e.g. "HeadingElement", "ParagraphElement"
|
56
|
-
)
|
57
|
-
|
58
|
-
@property
|
59
|
-
def name(self) -> str:
|
60
|
-
return "markdown_to_notion_conversion"
|
61
|
-
|
62
|
-
|
63
|
-
@dataclass
|
64
|
-
class NotionToMarkdownConversionEvent(BaseTelemetryEvent):
|
65
|
-
"""Event fired when Notion blocks are converted to markdown"""
|
66
|
-
|
67
|
-
handler_element_name: Optional[str] = (
|
68
|
-
None # e.g. "HeadingElement", "ParagraphElement"
|
69
|
-
)
|
70
|
-
|
71
|
-
@property
|
72
|
-
def name(self) -> str:
|
73
|
-
return "notion_to_markdown_conversion"
|
@@ -1,53 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from abc import ABC
|
4
|
-
from typing import Optional
|
5
|
-
|
6
|
-
from notionary.user.client import NotionUserClient
|
7
|
-
from notionary.util import LoggingMixin
|
8
|
-
|
9
|
-
|
10
|
-
class BaseNotionUser(LoggingMixin, ABC):
|
11
|
-
"""
|
12
|
-
Base class for all Notion user types with common functionality.
|
13
|
-
"""
|
14
|
-
|
15
|
-
def __init__(
|
16
|
-
self,
|
17
|
-
user_id: str,
|
18
|
-
name: Optional[str] = None,
|
19
|
-
avatar_url: Optional[str] = None,
|
20
|
-
token: Optional[str] = None,
|
21
|
-
):
|
22
|
-
"""Initialize base user properties."""
|
23
|
-
self._user_id = user_id
|
24
|
-
self._name = name
|
25
|
-
self._avatar_url = avatar_url
|
26
|
-
self.client = NotionUserClient(token=token)
|
27
|
-
|
28
|
-
@property
|
29
|
-
def id(self) -> str:
|
30
|
-
"""Get the user ID."""
|
31
|
-
return self._user_id
|
32
|
-
|
33
|
-
@property
|
34
|
-
def name(self) -> Optional[str]:
|
35
|
-
"""Get the user name."""
|
36
|
-
return self._name
|
37
|
-
|
38
|
-
@property
|
39
|
-
def avatar_url(self) -> Optional[str]:
|
40
|
-
"""Get the avatar URL."""
|
41
|
-
return self._avatar_url
|
42
|
-
|
43
|
-
def get_display_name(self) -> str:
|
44
|
-
"""Get a display name for the user."""
|
45
|
-
return self._name or f"User {self._user_id[:8]}"
|
46
|
-
|
47
|
-
def __str__(self) -> str:
|
48
|
-
"""String representation of the user."""
|
49
|
-
return f"{self.__class__.__name__}(name='{self.get_display_name()}', id='{self._user_id[:8]}...')"
|
50
|
-
|
51
|
-
def __repr__(self) -> str:
|
52
|
-
"""Detailed string representation."""
|
53
|
-
return self.__str__()
|
notionary/user/models.py
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
from dataclasses import dataclass
|
2
|
-
from typing import Literal, Optional
|
3
|
-
|
4
|
-
from pydantic import BaseModel
|
5
|
-
|
6
|
-
|
7
|
-
class PersonUser(BaseModel):
|
8
|
-
"""Person user details"""
|
9
|
-
|
10
|
-
email: Optional[str] = None
|
11
|
-
|
12
|
-
|
13
|
-
class BotOwner(BaseModel):
|
14
|
-
"""Bot owner information - simplified structure"""
|
15
|
-
|
16
|
-
type: Literal["workspace", "user"]
|
17
|
-
workspace: Optional[bool] = None
|
18
|
-
|
19
|
-
|
20
|
-
class WorkspaceLimits(BaseModel):
|
21
|
-
"""Workspace limits for bot users"""
|
22
|
-
|
23
|
-
max_file_upload_size_in_bytes: int
|
24
|
-
|
25
|
-
|
26
|
-
class BotUser(BaseModel):
|
27
|
-
"""Bot user details"""
|
28
|
-
|
29
|
-
owner: Optional[BotOwner] = None
|
30
|
-
workspace_name: Optional[str] = None
|
31
|
-
workspace_limits: Optional[WorkspaceLimits] = None
|
32
|
-
|
33
|
-
|
34
|
-
class NotionUserResponse(BaseModel):
|
35
|
-
"""
|
36
|
-
Represents a Notion user object as returned by the Users API.
|
37
|
-
Can represent both person and bot users.
|
38
|
-
"""
|
39
|
-
|
40
|
-
object: Literal["user"]
|
41
|
-
id: str
|
42
|
-
type: Optional[Literal["person", "bot"]] = None
|
43
|
-
name: Optional[str] = None
|
44
|
-
avatar_url: Optional[str] = None
|
45
|
-
|
46
|
-
# Person-specific fields
|
47
|
-
person: Optional[PersonUser] = None
|
48
|
-
|
49
|
-
# Bot-specific fields
|
50
|
-
bot: Optional[BotUser] = None
|
51
|
-
|
52
|
-
|
53
|
-
class NotionBotUserResponse(NotionUserResponse):
|
54
|
-
"""
|
55
|
-
Specialized response for bot user (from /users/me endpoint)
|
56
|
-
"""
|
57
|
-
|
58
|
-
# Bot users should have these fields, but they can still be None
|
59
|
-
type: Literal["bot"]
|
60
|
-
bot: Optional[BotUser] = None
|
61
|
-
|
62
|
-
|
63
|
-
class NotionUsersListResponse(BaseModel):
|
64
|
-
"""
|
65
|
-
Response model for paginated users list from /v1/users endpoint.
|
66
|
-
Follows Notion's standard pagination pattern.
|
67
|
-
"""
|
68
|
-
|
69
|
-
object: Literal["list"]
|
70
|
-
results: list[NotionUserResponse]
|
71
|
-
next_cursor: Optional[str] = None
|
72
|
-
has_more: bool
|
73
|
-
type: Literal["user"]
|
74
|
-
user: dict = {}
|
75
|
-
|
76
|
-
|
77
|
-
@dataclass
|
78
|
-
class WorkspaceInfo:
|
79
|
-
"""Dataclass to hold workspace information for bot users."""
|
80
|
-
|
81
|
-
name: Optional[str] = None
|
82
|
-
limits: Optional[WorkspaceLimits] = None
|
83
|
-
owner_type: Optional[str] = None
|
84
|
-
is_workspace_owned: bool = False
|