notionary 0.2.23__py3-none-any.whl → 0.2.25__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.
Files changed (101) hide show
  1. notionary/__init__.py +1 -1
  2. notionary/blocks/__init__.py +3 -1
  3. notionary/blocks/audio/__init__.py +0 -2
  4. notionary/blocks/audio/audio_element.py +92 -49
  5. notionary/blocks/audio/audio_markdown_node.py +4 -17
  6. notionary/blocks/bookmark/__init__.py +0 -2
  7. notionary/blocks/bookmark/bookmark_markdown_node.py +5 -21
  8. notionary/blocks/breadcrumbs/__init__.py +0 -2
  9. notionary/blocks/breadcrumbs/breadcrumb_markdown_node.py +2 -21
  10. notionary/blocks/bulleted_list/__init__.py +0 -2
  11. notionary/blocks/bulleted_list/bulleted_list_markdown_node.py +3 -17
  12. notionary/blocks/bulleted_list/bulleted_list_models.py +0 -1
  13. notionary/blocks/callout/__init__.py +0 -2
  14. notionary/blocks/callout/callout_markdown_node.py +4 -18
  15. notionary/blocks/callout/callout_models.py +3 -4
  16. notionary/blocks/code/code_markdown_node.py +5 -19
  17. notionary/blocks/column/__init__.py +0 -4
  18. notionary/blocks/column/column_list_markdown_node.py +3 -19
  19. notionary/blocks/column/column_markdown_node.py +4 -21
  20. notionary/blocks/divider/__init__.py +0 -2
  21. notionary/blocks/divider/divider_markdown_node.py +2 -16
  22. notionary/blocks/embed/__init__.py +0 -2
  23. notionary/blocks/embed/embed_markdown_node.py +4 -17
  24. notionary/blocks/equation/__init__.py +0 -1
  25. notionary/blocks/equation/equation_element_markdown_node.py +3 -15
  26. notionary/blocks/file/__init__.py +0 -2
  27. notionary/blocks/file/file_element.py +67 -46
  28. notionary/blocks/file/file_element_markdown_node.py +4 -17
  29. notionary/blocks/heading/__init__.py +0 -2
  30. notionary/blocks/heading/heading_markdown_node.py +5 -19
  31. notionary/blocks/heading/heading_models.py +3 -3
  32. notionary/blocks/image_block/__init__.py +0 -2
  33. notionary/blocks/image_block/image_element.py +66 -25
  34. notionary/blocks/image_block/image_markdown_node.py +5 -20
  35. notionary/{markdown → blocks/markdown}/markdown_builder.py +29 -233
  36. notionary/blocks/markdown/markdown_node.py +25 -0
  37. notionary/blocks/mixins/file_upload/__init__.py +3 -0
  38. notionary/blocks/mixins/file_upload/file_upload_mixin.py +320 -0
  39. notionary/blocks/numbered_list/__init__.py +0 -1
  40. notionary/blocks/numbered_list/numbered_list_markdown_node.py +3 -17
  41. notionary/blocks/numbered_list/numbered_list_models.py +3 -3
  42. notionary/blocks/paragraph/__init__.py +0 -2
  43. notionary/blocks/paragraph/paragraph_markdown_node.py +3 -13
  44. notionary/blocks/pdf/__init__.py +0 -2
  45. notionary/blocks/pdf/pdf_element.py +81 -32
  46. notionary/blocks/pdf/pdf_markdown_node.py +5 -18
  47. notionary/blocks/quote/__init__.py +0 -2
  48. notionary/blocks/quote/quote_markdown_node.py +3 -13
  49. notionary/blocks/registry/__init__.py +1 -2
  50. notionary/blocks/registry/block_registry.py +116 -61
  51. notionary/blocks/table/__init__.py +0 -2
  52. notionary/blocks/table/table_markdown_node.py +17 -16
  53. notionary/blocks/table_of_contents/__init__.py +0 -2
  54. notionary/blocks/table_of_contents/table_of_contents_element.py +27 -15
  55. notionary/blocks/table_of_contents/table_of_contents_markdown_node.py +3 -17
  56. notionary/blocks/table_of_contents/table_of_contents_models.py +2 -2
  57. notionary/blocks/todo/__init__.py +0 -2
  58. notionary/blocks/todo/todo_markdown_node.py +9 -20
  59. notionary/blocks/todo/todo_models.py +2 -3
  60. notionary/blocks/toggle/__init__.py +0 -2
  61. notionary/blocks/toggle/toggle_markdown_node.py +5 -19
  62. notionary/blocks/toggleable_heading/__init__.py +0 -2
  63. notionary/blocks/toggleable_heading/toggleable_heading_markdown_node.py +6 -23
  64. notionary/blocks/video/__init__.py +0 -2
  65. notionary/blocks/video/video_element.py +110 -34
  66. notionary/blocks/video/video_markdown_node.py +4 -15
  67. notionary/comments/client.py +1 -1
  68. notionary/file_upload/client.py +3 -2
  69. notionary/file_upload/models.py +10 -1
  70. notionary/file_upload/notion_file_upload.py +5 -5
  71. notionary/page/markdown_whitespace_processor.py +129 -0
  72. notionary/page/notion_page.py +35 -40
  73. notionary/page/page_content_deleting_service.py +1 -1
  74. notionary/page/page_content_writer.py +32 -129
  75. notionary/page/page_context.py +0 -5
  76. notionary/page/reader/handler/column_list_renderer.py +2 -2
  77. notionary/page/reader/handler/column_renderer.py +2 -2
  78. notionary/page/reader/handler/line_renderer.py +2 -2
  79. notionary/page/reader/handler/toggle_renderer.py +2 -2
  80. notionary/page/reader/handler/toggleable_heading_renderer.py +2 -2
  81. notionary/page/writer/handler/equation_handler.py +1 -1
  82. notionary/page/writer/handler/toggle_handler.py +8 -4
  83. notionary/page/writer/handler/toggleable_heading_handler.py +3 -2
  84. notionary/page/writer/markdown_to_notion_converter.py +74 -30
  85. notionary/schemas/__init__.py +3 -0
  86. notionary/schemas/base.py +73 -0
  87. notionary/shared/__init__.py +1 -3
  88. notionary-0.2.25.dist-info/METADATA +270 -0
  89. {notionary-0.2.23.dist-info → notionary-0.2.25.dist-info}/RECORD +92 -94
  90. notionary/blocks/guards.py +0 -22
  91. notionary/blocks/registry/block_registry_builder.py +0 -264
  92. notionary/markdown/makdown_document_model.py +0 -0
  93. notionary/markdown/markdown_document_model.py +0 -228
  94. notionary/markdown/markdown_node.py +0 -30
  95. notionary/models/notion_database_response.py +0 -0
  96. notionary/page/writer/markdown_to_notion_formatting_post_processor.py +0 -73
  97. notionary/page/writer/markdown_to_notion_post_processor.py +0 -0
  98. notionary-0.2.23.dist-info/METADATA +0 -235
  99. /notionary/{markdown/___init__.py → blocks/markdown/markdown_document_model.py} +0 -0
  100. {notionary-0.2.23.dist-info → notionary-0.2.25.dist-info}/LICENSE +0 -0
  101. {notionary-0.2.23.dist-info → notionary-0.2.25.dist-info}/WHEEL +0 -0
@@ -1,228 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import Literal, Optional, Union
4
-
5
- from pydantic import BaseModel, Field
6
-
7
- from notionary.blocks.bookmark.bookmark_markdown_node import BookmarkMarkdownBlockParams
8
- from notionary.blocks.bulleted_list.bulleted_list_markdown_node import (
9
- BulletedListMarkdownBlockParams,
10
- )
11
- from notionary.blocks.callout.callout_markdown_node import CalloutMarkdownBlockParams
12
- from notionary.blocks.divider.divider_markdown_node import DividerMarkdownBlockParams
13
- from notionary.blocks.embed.embed_markdown_node import EmbedMarkdownBlockParams
14
- from notionary.blocks.equation.equation_element_markdown_node import (
15
- EquationMarkdownBlockParams,
16
- )
17
- from notionary.blocks.file.file_element_markdown_node import FileMarkdownNodeParams
18
-
19
- # Import all the existing params models
20
- from notionary.blocks.heading.heading_markdown_node import HeadingMarkdownBlockParams
21
- from notionary.blocks.image_block.image_markdown_node import ImageMarkdownBlockParams
22
- from notionary.blocks.numbered_list.numbered_list_markdown_node import (
23
- NumberedListMarkdownBlockParams,
24
- )
25
- from notionary.blocks.paragraph.paragraph_markdown_node import (
26
- ParagraphMarkdownBlockParams,
27
- )
28
- from notionary.blocks.quote.quote_markdown_node import QuoteMarkdownBlockParams
29
- from notionary.blocks.table.table_markdown_node import TableMarkdownBlockParams
30
- from notionary.blocks.table_of_contents.table_of_contents_markdown_node import (
31
- TableOfContentsMarkdownBlockParams,
32
- )
33
- from notionary.blocks.todo.todo_markdown_node import TodoMarkdownBlockParams
34
- from notionary.blocks.video.video_markdown_node import VideoMarkdownBlockParams
35
-
36
-
37
- class HeadingBlock(BaseModel):
38
- type: Literal["heading"] = "heading"
39
- params: HeadingMarkdownBlockParams
40
-
41
-
42
- class ParagraphBlock(BaseModel):
43
- type: Literal["paragraph"] = "paragraph"
44
- params: ParagraphMarkdownBlockParams
45
-
46
-
47
- class QuoteBlock(BaseModel):
48
- type: Literal["quote"] = "quote"
49
- params: QuoteMarkdownBlockParams
50
-
51
-
52
- class BulletedListBlock(BaseModel):
53
- type: Literal["bulleted_list"] = "bulleted_list"
54
- params: BulletedListMarkdownBlockParams
55
-
56
-
57
- class NumberedListBlock(BaseModel):
58
- type: Literal["numbered_list"] = "numbered_list"
59
- params: NumberedListMarkdownBlockParams
60
-
61
-
62
- class TodoBlock(BaseModel):
63
- type: Literal["todo"] = "todo"
64
- params: TodoMarkdownBlockParams
65
-
66
-
67
- class CalloutBlock(BaseModel):
68
- type: Literal["callout"] = "callout"
69
- params: CalloutMarkdownBlockParams
70
-
71
-
72
- class CodeBlock(BaseModel):
73
- type: Literal["code"] = "code"
74
- params: CodeBlock
75
-
76
-
77
- class ImageBlock(BaseModel):
78
- type: Literal["image"] = "image"
79
- params: ImageMarkdownBlockParams
80
-
81
-
82
- class VideoBlock(BaseModel):
83
- type: Literal["video"] = "video"
84
- params: VideoMarkdownBlockParams
85
-
86
-
87
- class AudioBlock(BaseModel):
88
- type: Literal["audio"] = "audio"
89
- params: FileMarkdownNodeParams
90
-
91
-
92
- class FileBlock(BaseModel):
93
- type: Literal["file"] = "file"
94
- params: FileMarkdownNodeParams
95
-
96
-
97
- class PdfBlock(BaseModel):
98
- type: Literal["pdf"] = "pdf"
99
- params: FileMarkdownNodeParams
100
-
101
-
102
- class BookmarkBlock(BaseModel):
103
- type: Literal["bookmark"] = "bookmark"
104
- params: BookmarkMarkdownBlockParams
105
-
106
-
107
- class EmbedBlock(BaseModel):
108
- type: Literal["embed"] = "embed"
109
- params: EmbedMarkdownBlockParams
110
-
111
-
112
- class TableBlock(BaseModel):
113
- type: Literal["table"] = "table"
114
- params: TableMarkdownBlockParams
115
-
116
-
117
- class DividerBlock(BaseModel):
118
- type: Literal["divider"] = "divider"
119
- params: DividerMarkdownBlockParams
120
-
121
-
122
- class EquationBlock(BaseModel):
123
- type: Literal["equation"] = "equation"
124
- params: EquationMarkdownBlockParams
125
-
126
-
127
- class TableOfContentsBlock(BaseModel):
128
- type: Literal["table_of_contents"] = "table_of_contents"
129
- params: TableOfContentsMarkdownBlockParams
130
-
131
-
132
- # Special blocks for nested content
133
- class ToggleBlockParams(BaseModel):
134
- title: str
135
- children: list[MarkdownBlock] = Field(default_factory=list)
136
-
137
-
138
- class ToggleBlock(BaseModel):
139
- type: Literal["toggle"] = "toggle"
140
- params: ToggleBlockParams
141
-
142
-
143
- class ToggleableHeadingBlockParams(BaseModel):
144
- text: str
145
- level: int = Field(ge=1, le=3)
146
- children: list[MarkdownBlock] = Field(default_factory=list)
147
-
148
-
149
- class ToggleableHeadingBlock(BaseModel):
150
- type: Literal["toggleable_heading"] = "toggleable_heading"
151
- params: ToggleableHeadingBlockParams
152
-
153
-
154
- class ColumnBlockParams(BaseModel):
155
- columns: list[list[MarkdownBlock]] = Field(default_factory=list)
156
- width_ratios: Optional[list[float]] = None
157
-
158
-
159
- class ColumnBlock(BaseModel):
160
- type: Literal["columns"] = "columns"
161
- params: ColumnBlockParams
162
-
163
-
164
- # Union of all possible blocks
165
- MarkdownBlock = Union[
166
- HeadingBlock,
167
- ParagraphBlock,
168
- QuoteBlock,
169
- BulletedListBlock,
170
- NumberedListBlock,
171
- TodoBlock,
172
- CalloutBlock,
173
- CodeBlock,
174
- ImageBlock,
175
- VideoBlock,
176
- AudioBlock,
177
- FileBlock,
178
- PdfBlock,
179
- BookmarkBlock,
180
- EmbedBlock,
181
- TableBlock,
182
- DividerBlock,
183
- EquationBlock,
184
- TableOfContentsBlock,
185
- ToggleBlock,
186
- ToggleableHeadingBlock,
187
- ColumnBlock,
188
- ]
189
-
190
-
191
- # Update forward references
192
- ToggleBlockParams.model_rebuild()
193
- ToggleableHeadingBlockParams.model_rebuild()
194
- ColumnBlockParams.model_rebuild()
195
-
196
-
197
- class MarkdownDocumentModel(BaseModel):
198
- """
199
- Complete document model for generating Markdown via MarkdownBuilder.
200
- Perfect for LLM structured output!
201
-
202
- Example:
203
- {
204
- "blocks": [
205
- {
206
- "type": "heading",
207
- "params": {"text": "My Document", "level": 1}
208
- },
209
- {
210
- "type": "paragraph",
211
- "params": {"text": "Introduction text"}
212
- },
213
- {
214
- "type": "pdf",
215
- "params": {"url": "https://example.com/doc.pdf", "caption": "Important PDF"}
216
- }
217
- ]
218
- }
219
- """
220
-
221
- blocks: list[MarkdownBlock] = Field(default_factory=list)
222
-
223
- def to_markdown(self) -> str:
224
- """Convert the model directly to markdown string."""
225
- from notionary.markdown.markdown_builder import MarkdownBuilder
226
-
227
- builder = MarkdownBuilder.from_model(self)
228
- return builder.build()
@@ -1,30 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from abc import ABC, abstractmethod
4
-
5
-
6
- class MarkdownNode(ABC):
7
- """
8
- Abstract base class for all Markdown block elements.
9
- Enforces implementation of to_markdown().
10
- """
11
-
12
- @abstractmethod
13
- def to_markdown(self) -> str:
14
- """
15
- Returns the Markdown representation of the block.
16
- Must be implemented by subclasses.
17
- """
18
- pass
19
-
20
- @classmethod
21
- @abstractmethod
22
- def from_params(cls, params) -> MarkdownNode:
23
- """
24
- Creates an instance from a params object.
25
- Must be implemented by subclasses.
26
- """
27
- pass
28
-
29
- def __str__(self):
30
- return self.to_markdown()
File without changes
@@ -1,73 +0,0 @@
1
- """
2
- Post-processor for handling block formatting in Markdown to Notion conversion.
3
-
4
- Handles block formatting tasks like adding empty paragraphs before media blocks
5
- and other formatting-related post-processing.
6
- """
7
-
8
- from typing import cast
9
-
10
- from notionary.blocks.models import BlockCreateRequest
11
- from notionary.blocks.types import BlockType
12
- from notionary.blocks.paragraph.paragraph_models import (
13
- CreateParagraphBlock,
14
- ParagraphBlock,
15
- )
16
-
17
-
18
- class MarkdownToNotionFormattingPostProcessor:
19
- """Handles block formatting post-processing for Notion blocks."""
20
-
21
- BLOCKS_NEEDING_EMPTY_PARAGRAPH: set[BlockType] = {
22
- BlockType.DIVIDER,
23
- BlockType.FILE,
24
- BlockType.IMAGE,
25
- BlockType.PDF,
26
- BlockType.VIDEO,
27
- }
28
-
29
- def process(self, blocks: list[BlockCreateRequest]) -> list[BlockCreateRequest]:
30
- """Process blocks with all formatting steps."""
31
- if not blocks:
32
- return blocks
33
-
34
- return self._add_empty_paragraphs_for_media_blocks(blocks)
35
-
36
- def _add_empty_paragraphs_for_media_blocks(
37
- self, blocks: list[BlockCreateRequest]
38
- ) -> list[BlockCreateRequest]:
39
- """Add empty paragraphs before configured block types."""
40
- if not blocks:
41
- return blocks
42
-
43
- result: list[BlockCreateRequest] = []
44
-
45
- for i, block in enumerate(blocks):
46
- block_type = block.type
47
-
48
- if (
49
- block_type in self.BLOCKS_NEEDING_EMPTY_PARAGRAPH
50
- and i > 0
51
- and not self._is_empty_paragraph(result[-1] if result else None)
52
- ):
53
-
54
- # Create empty paragraph block inline
55
- empty_paragraph = CreateParagraphBlock(
56
- paragraph=ParagraphBlock(rich_text=[])
57
- )
58
- result.append(empty_paragraph)
59
-
60
- result.append(block)
61
-
62
- return result
63
-
64
- def _is_empty_paragraph(self, block: BlockCreateRequest | None) -> bool:
65
- if not block or block.type != BlockType.PARAGRAPH:
66
- return False
67
- if not isinstance(block, CreateParagraphBlock):
68
- return False
69
-
70
- para_block = cast(CreateParagraphBlock, block)
71
- paragraph: ParagraphBlock | None = para_block.paragraph
72
- if not paragraph:
73
- return False
@@ -1,235 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: notionary
3
- Version: 0.2.23
4
- Summary: Python library for programmatic Notion workspace management - databases, pages, and content with advanced Markdown support
5
- License: MIT
6
- Author: Mathis Arends
7
- Author-email: mathisarends27@gmail.com
8
- Requires-Python: >=3.9
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.9
12
- Classifier: Programming Language :: Python :: 3.10
13
- Classifier: Programming Language :: Python :: 3.11
14
- Classifier: Programming Language :: Python :: 3.12
15
- Classifier: Programming Language :: Python :: 3.13
16
- Requires-Dist: httpx (>=0.28.0)
17
- Requires-Dist: posthog (>=6.3.1,<7.0.0)
18
- Requires-Dist: pydantic (>=2.11.4)
19
- Requires-Dist: python-dotenv (>=1.1.0)
20
- Project-URL: Homepage, https://github.com/mathisarends/notionary
21
- Description-Content-Type: text/markdown
22
-
23
- <picture>
24
- <source media="(prefers-color-scheme: dark)" srcset="./static/notionary-dark.png">
25
- <source media="(prefers-color-scheme: light)" srcset="./static/notionary-light.png">
26
- <img alt="Notionary logo: dark mode shows a white logo, light mode shows a black logo." src="./static/browser-use.png" width="full">
27
- </picture>
28
-
29
- <h1 align="center">Notion API simplified for Python developers 🐍</h1>
30
-
31
- <div align="center">
32
-
33
- [![Python Version](https://img.shields.io/badge/python-3.8%2B-blue.svg)](https://www.python.org/downloads/)
34
- [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
35
- [![Documentation](https://img.shields.io/badge/docs-mathisarends.github.io-blue.svg)](https://mathisarends.github.io/notionary/)
36
-
37
- Transform complex Notion API interactions into simple, Pythonic code. Build AI agents, automate workflows, and create dynamic content with ease.
38
-
39
- </div>
40
-
41
- ---
42
-
43
- ## Why Notionary?
44
-
45
- - **Smart Discovery**: Find pages and databases by name—no more hunting for URLs or IDs
46
- - **Rich Markdown**: Convert extended Markdown (callouts, toggles, columns) directly into beautiful Notion blocks
47
- - **Async-First**: Built for modern Python with full async/await support and high performance
48
- - **AI-Ready**: Perfect foundation for AI agents that generate and manage Notion content
49
- - **Round-Trip**: Read existing content, modify it, and write it back while preserving formatting
50
-
51
- ---
52
-
53
- ## Quick Start
54
-
55
- ```bash
56
- pip install notionary
57
- ```
58
-
59
- Set up your [Notion integration](https://www.notion.so/profile/integrations) and add your token:
60
-
61
- ```bash
62
- NOTION_SECRET=your_integration_key
63
- ```
64
-
65
- ### Simple Flow: Find → Create → Update
66
-
67
- ```python
68
- import asyncio
69
- from notionary import NotionPage, NotionDatabase
70
-
71
- async def main():
72
- # Work with pages - find by name, no exact match needed!
73
- page = await NotionPage.from_page_name("Meeting Notes")
74
-
75
- # Direct Markdown - quick & intuitive
76
- await page.append_markdown("""
77
- ## Action Items
78
- - Review project proposal
79
- - Schedule team meeting
80
- - Update documentation
81
-
82
- [callout](Important meeting decisions require follow-up "💡")
83
- """)
84
-
85
- # Builder Pattern - type-safe & powerful for complex layouts
86
- await page.append_markdown(lambda builder: (
87
- builder
88
- .h2("Project Status")
89
- .callout("Project milestone reached!", "🎉")
90
- .columns(
91
- lambda col: (col
92
- .h3("Completed")
93
- .bulleted_list(["API design", "Database setup", "Authentication"])
94
- ),
95
- lambda col: (col
96
- .h3("In Progress")
97
- .bulleted_list(["Frontend UI", "Testing", "Documentation"])
98
- )
99
- )
100
- .table(
101
- headers=["Task", "Owner", "Due Date"],
102
- rows=[
103
- ["Launch prep", "Alice", "2024-03-15"],
104
- ["Marketing", "Bob", "2024-03-20"]
105
- ]
106
- )
107
- ))
108
-
109
- asyncio.run(main())
110
- ```
111
-
112
- ### Create Rich Database Entries
113
-
114
- ```python
115
- # Work with databases - connect and create styled entries
116
- db = await NotionDatabase.from_database_name("Projects")
117
-
118
- # Create new project with full styling
119
- project = await db.create_blank_page()
120
- await project.set_title("New Marketing Campaign")
121
- await project.set_emoji_icon("🚀")
122
- await project.set_random_gradient_cover()
123
-
124
- # Set database properties
125
- await project.set_property_value_by_name("Status", "Planning")
126
- await project.set_property_value_by_name("Priority", "High")
127
- await project.set_property_value_by_name("Team Lead", "sarah@company.com")
128
-
129
- # Add rich content to the new page
130
- await project.replace_content(lambda builder: (
131
- builder
132
- .h1("Campaign Overview")
133
- .callout("New marketing initiative targeting Q2 growth", "🎯")
134
- .h2("Goals & Objectives")
135
- .numbered_list([
136
- "Increase brand awareness by 25%",
137
- "Generate 500 qualified leads",
138
- "Launch in 3 target markets"
139
- ])
140
- .h2("Budget Breakdown")
141
- .table(
142
- headers=["Category", "Allocated", "Spent", "Remaining"],
143
- rows=[
144
- ["Digital Ads", "$15,000", "$3,200", "$11,800"],
145
- ["Content Creation", "$8,000", "$1,500", "$6,500"],
146
- ["Events", "$12,000", "$0", "$12,000"]
147
- ]
148
- )
149
- .divider()
150
- .toggle("Technical Requirements", lambda toggle: (
151
- toggle
152
- .paragraph("Platform specifications and integration details.")
153
- .bulleted_list([
154
- "CRM integration with Salesforce",
155
- "Analytics tracking setup",
156
- "Landing page development"
157
- ])
158
- ))
159
- ))
160
-
161
- print(f"✅ Created styled project: {project.url}")
162
- ```
163
-
164
- ### Extended Markdown Syntax
165
-
166
- Notionary supports rich formatting with callouts, toggles, multi-column layouts, tables, media embeds, and more. Use either direct markdown syntax or the type-safe builder pattern.
167
-
168
- See the complete [Block Types documentation](https://mathisarends.github.io/notionary/blocks/) for all available formatting options and syntax examples.
169
-
170
- ## What You Can Build
171
-
172
- - **AI Content Generation** - Perfect for AI agents that create structured reports and documentation
173
- - **Workflow Automation** - Update project status, sync data between databases, generate reports
174
- - **Dynamic Documentation** - Auto-generate team docs, API references, and knowledge bases
175
- - **Content Management** - Bulk page updates, template generation, and content migration
176
-
177
- ## Core Features
178
-
179
- | Feature | Description |
180
- | -------------------- | ------------------------------------------------------ |
181
- | **Smart Discovery** | Find pages/databases by name with fuzzy matching |
182
- | **Rich Markdown** | Extended syntax for callouts, toggles, columns, tables |
183
- | **Async-First** | Modern Python with full async/await support |
184
- | **Round-Trip** | Read content as markdown, edit, and write back |
185
- | **AI-Ready** | Generate system prompts for AI content creation |
186
- | **All Block Types** | Support for every Notion block type |
187
- | **Type Safety** | Full type hints for better IDE support |
188
- | **High Performance** | Efficient batch operations and caching |
189
-
190
- ## Examples & Documentation
191
-
192
- Explore comprehensive guides and real-world examples:
193
-
194
- - **[📖 Full Documentation](https://mathisarends.github.io/notionary/)** - Complete API reference and guides
195
- - **[Getting Started](https://mathisarends.github.io/notionary/get-started/)** - Quick setup and first steps
196
- - **[Page Management](https://mathisarends.github.io/notionary/page/)** - Work with page content and properties
197
- - **[Database Operations](https://mathisarends.github.io/notionary/database/)** - Query and manage databases
198
- - **[Block Types](https://mathisarends.github.io/notionary/blocks/)** - Complete formatting reference
199
-
200
- Check out the `examples/` directory for hands-on tutorials:
201
-
202
- ### Core Examples
203
-
204
- - **[Page Management](examples/page_example.py)** - Create, update, and manage pages
205
- - **[Database Operations](examples/database.py)** - Connect to and query databases
206
- - **[Workspace Discovery](examples/workspace_discovery.py)** - Explore your workspace
207
-
208
- ### Markdown Examples
209
-
210
- - **[Basic Formatting](examples/markdown/basic.py)** - Text, lists, and links
211
- - **[Callouts](examples/markdown/callout.py)** - Eye-catching information boxes
212
- - **[Toggles](examples/markdown/toggle.py)** - Collapsible content sections
213
- - **[Multi-Column](examples/markdown/columns.py)** - Side-by-side layouts
214
- - **[Tables](examples/markdown/table.py)** - Structured data presentation
215
-
216
- ## Contributing
217
-
218
- We'd love your help making Notionary even better!
219
-
220
- Whether it's fixing bugs, adding features, improving docs, or sharing examples - all contributions are welcome.
221
-
222
- See our [Contributing Guide](https://mathisarends.github.io/notionary/contributing/) to get started.
223
-
224
- ---
225
-
226
- <div align="center">
227
-
228
- **Ready to transform your Notion workflow?**
229
-
230
- [📖 Read the Docs](https://mathisarends.github.io/notionary/) • [Getting Started](https://mathisarends.github.io/notionary/get-started/) • [Examples](examples/)
231
-
232
- Built with ❤️ for the Python community
233
-
234
- </div>
235
-