notionary 0.2.14__tar.gz → 0.2.15__tar.gz

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 (80) hide show
  1. notionary-0.2.15/PKG-INFO +223 -0
  2. notionary-0.2.15/README.md +201 -0
  3. {notionary-0.2.14 → notionary-0.2.15}/notionary/database/notion_database.py +19 -19
  4. {notionary-0.2.14 → notionary-0.2.15}/notionary/database/notion_database_provider.py +6 -6
  5. {notionary-0.2.14 → notionary-0.2.15}/notionary/page/notion_page.py +1 -1
  6. notionary-0.2.15/pyproject.toml +27 -0
  7. notionary-0.2.14/PKG-INFO +0 -276
  8. notionary-0.2.14/README.md +0 -245
  9. notionary-0.2.14/notionary/cli/main.py +0 -376
  10. notionary-0.2.14/notionary/cli/onboarding.py +0 -117
  11. notionary-0.2.14/notionary.egg-info/PKG-INFO +0 -276
  12. notionary-0.2.14/notionary.egg-info/SOURCES.txt +0 -75
  13. notionary-0.2.14/notionary.egg-info/dependency_links.txt +0 -1
  14. notionary-0.2.14/notionary.egg-info/entry_points.txt +0 -2
  15. notionary-0.2.14/notionary.egg-info/requires.txt +0 -8
  16. notionary-0.2.14/notionary.egg-info/top_level.txt +0 -1
  17. notionary-0.2.14/setup.cfg +0 -4
  18. notionary-0.2.14/setup.py +0 -33
  19. {notionary-0.2.14 → notionary-0.2.15}/LICENSE +0 -0
  20. {notionary-0.2.14 → notionary-0.2.15}/notionary/__init__.py +0 -0
  21. {notionary-0.2.14 → notionary-0.2.15}/notionary/base_notion_client.py +0 -0
  22. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/__init__.py +0 -0
  23. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/audio_element.py +0 -0
  24. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/bookmark_element.py +0 -0
  25. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/bulleted_list_element.py +0 -0
  26. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/callout_element.py +0 -0
  27. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/code_block_element.py +0 -0
  28. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/column_element.py +0 -0
  29. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/divider_element.py +0 -0
  30. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/embed_element.py +0 -0
  31. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/heading_element.py +0 -0
  32. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/image_element.py +0 -0
  33. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/mention_element.py +0 -0
  34. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/notion_block_client.py +0 -0
  35. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/notion_block_element.py +0 -0
  36. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/numbered_list_element.py +0 -0
  37. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/paragraph_element.py +0 -0
  38. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/prompts/element_prompt_builder.py +0 -0
  39. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/prompts/element_prompt_content.py +0 -0
  40. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/qoute_element.py +0 -0
  41. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/registry/block_registry.py +0 -0
  42. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/registry/block_registry_builder.py +0 -0
  43. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/table_element.py +0 -0
  44. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/text_inline_formatter.py +0 -0
  45. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/todo_element.py +0 -0
  46. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/toggle_element.py +0 -0
  47. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/toggleable_heading_element.py +0 -0
  48. {notionary-0.2.14 → notionary-0.2.15}/notionary/blocks/video_element.py +0 -0
  49. {notionary-0.2.14 → notionary-0.2.15}/notionary/database/__init__.py +0 -0
  50. {notionary-0.2.14 → notionary-0.2.15}/notionary/database/client.py +0 -0
  51. {notionary-0.2.14 → notionary-0.2.15}/notionary/database/database_exceptions.py +0 -0
  52. {notionary-0.2.14 → notionary-0.2.15}/notionary/database/factory.py +0 -0
  53. {notionary-0.2.14 → notionary-0.2.15}/notionary/database/filter_builder.py +0 -0
  54. {notionary-0.2.14 → notionary-0.2.15}/notionary/database/models/page_result.py +0 -0
  55. {notionary-0.2.14 → notionary-0.2.15}/notionary/elements/__init__.py +0 -0
  56. {notionary-0.2.14 → notionary-0.2.15}/notionary/models/notion_block_response.py +0 -0
  57. {notionary-0.2.14 → notionary-0.2.15}/notionary/models/notion_database_response.py +0 -0
  58. {notionary-0.2.14 → notionary-0.2.15}/notionary/models/notion_page_response.py +0 -0
  59. {notionary-0.2.14 → notionary-0.2.15}/notionary/models/search_response.py +0 -0
  60. {notionary-0.2.14 → notionary-0.2.15}/notionary/page/__init__.py +0 -0
  61. {notionary-0.2.14 → notionary-0.2.15}/notionary/page/client.py +0 -0
  62. {notionary-0.2.14 → notionary-0.2.15}/notionary/page/content/notion_page_content_chunker.py +0 -0
  63. {notionary-0.2.14 → notionary-0.2.15}/notionary/page/content/page_content_retriever.py +0 -0
  64. {notionary-0.2.14 → notionary-0.2.15}/notionary/page/content/page_content_writer.py +0 -0
  65. {notionary-0.2.14 → notionary-0.2.15}/notionary/page/formatting/markdown_to_notion_converter.py +0 -0
  66. {notionary-0.2.14 → notionary-0.2.15}/notionary/page/formatting/spacer_rules.py +0 -0
  67. {notionary-0.2.14 → notionary-0.2.15}/notionary/page/markdown_syntax_prompt_generator.py +0 -0
  68. {notionary-0.2.14 → notionary-0.2.15}/notionary/page/notion_to_markdown_converter.py +0 -0
  69. {notionary-0.2.14 → notionary-0.2.15}/notionary/page/properites/property_value_extractor.py +0 -0
  70. {notionary-0.2.14 → notionary-0.2.15}/notionary/page/property_formatter.py +0 -0
  71. {notionary-0.2.14 → notionary-0.2.15}/notionary/page/search_filter_builder.py +0 -0
  72. {notionary-0.2.14 → notionary-0.2.15}/notionary/page/utils.py +0 -0
  73. {notionary-0.2.14 → notionary-0.2.15}/notionary/util/__init__.py +0 -0
  74. {notionary-0.2.14 → notionary-0.2.15}/notionary/util/factory_decorator.py +0 -0
  75. {notionary-0.2.14 → notionary-0.2.15}/notionary/util/fuzzy_matcher.py +0 -0
  76. {notionary-0.2.14 → notionary-0.2.15}/notionary/util/logging_mixin.py +0 -0
  77. {notionary-0.2.14 → notionary-0.2.15}/notionary/util/page_id_utils.py +0 -0
  78. {notionary-0.2.14 → notionary-0.2.15}/notionary/util/singleton_decorator.py +0 -0
  79. {notionary-0.2.14 → notionary-0.2.15}/notionary/util/singleton_metaclass.py +0 -0
  80. {notionary-0.2.14 → notionary-0.2.15}/notionary/workspace.py +0 -0
@@ -0,0 +1,223 @@
1
+ Metadata-Version: 2.3
2
+ Name: notionary
3
+ Version: 0.2.15
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: pydantic (>=2.11.4)
18
+ Requires-Dist: python-dotenv (>=1.1.0)
19
+ Project-URL: Homepage, https://github.com/mathisarends/notionary
20
+ Description-Content-Type: text/markdown
21
+
22
+ <picture>
23
+ <source media="(prefers-color-scheme: dark)" srcset="./static/notionary-dark.png">
24
+ <source media="(prefers-color-scheme: light)" srcset="./static/notionary-light.png">
25
+ <img alt="Notionary logo: dark mode shows a white logo, light mode shows a black logo." src="./static/browser-use.png" width="full">
26
+ </picture>
27
+
28
+ <h1 align="center">Notion API simplified for Python developers 🐍</h1>
29
+
30
+ [![Python Version](https://img.shields.io/badge/python-3.8%2B-blue.svg)](https://www.python.org/downloads/)
31
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
32
+
33
+ - **Object-Oriented Design**: Clean, intuitive classes for Pages, Databases, and Workspaces with full CRUD operations
34
+ - **Rich Markdown to Notion**: Convert extended Markdown (callouts, toggles, columns) directly into beautiful Notion blocks
35
+ - **Smart Discovery**: Find pages and databases by name with fuzzy matching - no more hunting for URLs
36
+ - **Async-First Architecture**: Built for modern Python with full async/await support and high performance
37
+ - **AI-Ready Integration**: Generate LLM system prompts and let AI agents create Notion content seamlessly
38
+
39
+ ---
40
+
41
+ # Quick start
42
+ ```bash
43
+ pip install notionary
44
+ ```
45
+
46
+ - Set up your Notion integration (notion.so/profile/integrations)
47
+ - Add your integration key in your `.env` file.
48
+
49
+ ```bash
50
+ NOTION_SECRET=YOUR_INTEGRATION_KEY
51
+ ```
52
+
53
+ ### Creating and Managing Pages 🚀
54
+ ```python
55
+ from notionary import NotionPage
56
+
57
+ async def main():
58
+ # Simpy find an existing page by its title
59
+ page = await NotionPage.from_page_name("My Test Page")
60
+
61
+ # Add rich content with custom Markdown
62
+ content = """
63
+ # 🚀 Generated with Notionary
64
+
65
+ !> [💡] This page was created programmatically!
66
+
67
+ ## Features
68
+ - **Rich** Markdown support
69
+ - Database integration
70
+ - AI-ready content generation
71
+
72
+ +++ Click to see more details
73
+ | Notionary makes it easy to create beautiful Notion pages
74
+ | directly from Python code with intuitive Markdown syntax.
75
+ """
76
+
77
+ await page.replace_content(content)
78
+ print(f"✅ Page updated: {page.url}")
79
+
80
+ asyncio.run(main())
81
+ ```
82
+
83
+ ---
84
+
85
+ ### Working with Databases 🔥
86
+
87
+ ```python
88
+ import asyncio
89
+ from notionary import NotionDatabase
90
+
91
+ async def main():
92
+ # Connect to database by name (fuzzy matching)
93
+ db = await NotionDatabase.from_database_name("Projects")
94
+
95
+ # Create a new page with properties
96
+ page = await db.create_blank_page()
97
+ await page.set_title("🆕 New Project Entry")
98
+ await page.set_property_value_by_name("Status", "In Progress")
99
+ await page.set_property_value_by_name("Priority", "High")
100
+
101
+ # find pages created in the last 7 days
102
+ count = 0
103
+ async for page in db.iter_pages_with_filter(
104
+ db.create_filter().with_created_last_n_days(7)
105
+ ):
106
+ count += 1
107
+ print(f"{count:2d}. {page.emoji_icon or '📄'} {page.title}")
108
+
109
+ asyncio.run(main())
110
+ ```
111
+
112
+ ## Custom Markdown Syntax
113
+
114
+ Notionary extends standard Markdown with special syntax to support Notion-specific features:
115
+
116
+ ### Text Formatting
117
+
118
+ - Standard: `**bold**`, `*italic*`, `~~strikethrough~~`, `` `code` ``
119
+ - Links: `[text](url)`
120
+ - Quotes: `> This is a quote`
121
+ - Divider: `---`
122
+
123
+ ### Callouts
124
+
125
+ ```markdown
126
+ !> [💡] This is a default callout with the light bulb emoji
127
+ !> [🔔] This is a notification with a bell emoji
128
+ !> [⚠️] Warning: This is an important note
129
+ ```
130
+
131
+ ### Toggles
132
+
133
+ ```markdown
134
+ +++ How to use Notionary
135
+ | 1. Initialize with NotionPage
136
+ | 2. Update metadata with set_title(), set_emoji_icon(), etc.
137
+ | 3. Add content with replace_content() or append_markdown()
138
+ ```
139
+
140
+ ### Multi-Column Layout
141
+
142
+ ```markdown
143
+ ::: columns
144
+ ::: column
145
+
146
+ ## Left Column
147
+
148
+ - Item 1
149
+ - Item 2
150
+ - Item 3
151
+ :::
152
+ ::: column
153
+
154
+ ## Right Column
155
+
156
+ This text appears in the second column. Multi-column layouts are perfect for:
157
+
158
+ - Comparing features
159
+ - Creating side-by-side content
160
+ - Improving readability of wide content
161
+ :::
162
+ :::
163
+ ```
164
+
165
+ ### Code Blocks
166
+
167
+ ```python
168
+ def hello_world():
169
+ print("Hello from Notionary!")
170
+ ```
171
+
172
+ ### To-do Lists
173
+
174
+ ```markdown
175
+ - [ ] Define project scope
176
+ - [x] Create timeline
177
+ - [ ] Assign resources
178
+ ```
179
+
180
+ ### Tables
181
+
182
+ ```markdown
183
+ | Feature | Status | Priority |
184
+ | --------------- | ----------- | -------- |
185
+ | API Integration | Complete | High |
186
+ | Documentation | In Progress | Medium |
187
+ ```
188
+
189
+ ### More Elements
190
+
191
+ ```markdown
192
+ ![Caption](https://example.com/image.jpg)
193
+ @[Caption](https://youtube.com/watch?v=...)
194
+ [bookmark](https://example.com "Title" "Description")
195
+ ```
196
+
197
+ ## Examples
198
+
199
+ Explore the `examples/` directory for comprehensive guides:
200
+
201
+ ### 🚀 Core Examples
202
+ - [**Page Management**](examples/page_example.py) - Create, update, and manage Notion pages
203
+ - [**Page Operations**](examples/page.py) - Advanced page manipulation and content handling
204
+ - [**Database Operations**](examples/database.py) - Connect to and manage Notion databases
205
+ - [**Database Iteration**](examples/database_iteration.py) - Query and filter database entries
206
+ - [**Workspace Discovery**](examples/workspace_discovery.py) - Explore and discover your Notion workspace
207
+
208
+ ### 📝 Markdown Examples
209
+ - [**Basic Formatting**](examples/markdown/basic.py) - Text formatting, lists, and basic elements
210
+ - [**Callouts**](examples/markdown/callout.py) - Create beautiful callout blocks with icons
211
+ - [**Toggles**](examples/markdown/toggle.py) - Collapsible content sections
212
+ - [**Multi-Column Layouts**](examples/markdown/columns.py) - Side-by-side content arrangement
213
+ - [**Code Blocks**](examples/markdown/code.py) - Syntax-highlighted code examples
214
+ - [**Tables**](examples/markdown/table.py) - Structured data presentation
215
+ - [**Media Embeds**](examples/markdown/embed.py) - Images, videos, and rich media
216
+ - [**Audio Content**](examples/markdown/audio.py) - Audio file integration
217
+
218
+ Each example is self-contained and demonstrates specific features with practical use cases.
219
+
220
+ ## Contributing
221
+
222
+ Contributions welcome — feel free to submit a pull request!
223
+
@@ -0,0 +1,201 @@
1
+ <picture>
2
+ <source media="(prefers-color-scheme: dark)" srcset="./static/notionary-dark.png">
3
+ <source media="(prefers-color-scheme: light)" srcset="./static/notionary-light.png">
4
+ <img alt="Notionary logo: dark mode shows a white logo, light mode shows a black logo." src="./static/browser-use.png" width="full">
5
+ </picture>
6
+
7
+ <h1 align="center">Notion API simplified for Python developers 🐍</h1>
8
+
9
+ [![Python Version](https://img.shields.io/badge/python-3.8%2B-blue.svg)](https://www.python.org/downloads/)
10
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
11
+
12
+ - **Object-Oriented Design**: Clean, intuitive classes for Pages, Databases, and Workspaces with full CRUD operations
13
+ - **Rich Markdown to Notion**: Convert extended Markdown (callouts, toggles, columns) directly into beautiful Notion blocks
14
+ - **Smart Discovery**: Find pages and databases by name with fuzzy matching - no more hunting for URLs
15
+ - **Async-First Architecture**: Built for modern Python with full async/await support and high performance
16
+ - **AI-Ready Integration**: Generate LLM system prompts and let AI agents create Notion content seamlessly
17
+
18
+ ---
19
+
20
+ # Quick start
21
+ ```bash
22
+ pip install notionary
23
+ ```
24
+
25
+ - Set up your Notion integration (notion.so/profile/integrations)
26
+ - Add your integration key in your `.env` file.
27
+
28
+ ```bash
29
+ NOTION_SECRET=YOUR_INTEGRATION_KEY
30
+ ```
31
+
32
+ ### Creating and Managing Pages 🚀
33
+ ```python
34
+ from notionary import NotionPage
35
+
36
+ async def main():
37
+ # Simpy find an existing page by its title
38
+ page = await NotionPage.from_page_name("My Test Page")
39
+
40
+ # Add rich content with custom Markdown
41
+ content = """
42
+ # 🚀 Generated with Notionary
43
+
44
+ !> [💡] This page was created programmatically!
45
+
46
+ ## Features
47
+ - **Rich** Markdown support
48
+ - Database integration
49
+ - AI-ready content generation
50
+
51
+ +++ Click to see more details
52
+ | Notionary makes it easy to create beautiful Notion pages
53
+ | directly from Python code with intuitive Markdown syntax.
54
+ """
55
+
56
+ await page.replace_content(content)
57
+ print(f"✅ Page updated: {page.url}")
58
+
59
+ asyncio.run(main())
60
+ ```
61
+
62
+ ---
63
+
64
+ ### Working with Databases 🔥
65
+
66
+ ```python
67
+ import asyncio
68
+ from notionary import NotionDatabase
69
+
70
+ async def main():
71
+ # Connect to database by name (fuzzy matching)
72
+ db = await NotionDatabase.from_database_name("Projects")
73
+
74
+ # Create a new page with properties
75
+ page = await db.create_blank_page()
76
+ await page.set_title("🆕 New Project Entry")
77
+ await page.set_property_value_by_name("Status", "In Progress")
78
+ await page.set_property_value_by_name("Priority", "High")
79
+
80
+ # find pages created in the last 7 days
81
+ count = 0
82
+ async for page in db.iter_pages_with_filter(
83
+ db.create_filter().with_created_last_n_days(7)
84
+ ):
85
+ count += 1
86
+ print(f"{count:2d}. {page.emoji_icon or '📄'} {page.title}")
87
+
88
+ asyncio.run(main())
89
+ ```
90
+
91
+ ## Custom Markdown Syntax
92
+
93
+ Notionary extends standard Markdown with special syntax to support Notion-specific features:
94
+
95
+ ### Text Formatting
96
+
97
+ - Standard: `**bold**`, `*italic*`, `~~strikethrough~~`, `` `code` ``
98
+ - Links: `[text](url)`
99
+ - Quotes: `> This is a quote`
100
+ - Divider: `---`
101
+
102
+ ### Callouts
103
+
104
+ ```markdown
105
+ !> [💡] This is a default callout with the light bulb emoji
106
+ !> [🔔] This is a notification with a bell emoji
107
+ !> [⚠️] Warning: This is an important note
108
+ ```
109
+
110
+ ### Toggles
111
+
112
+ ```markdown
113
+ +++ How to use Notionary
114
+ | 1. Initialize with NotionPage
115
+ | 2. Update metadata with set_title(), set_emoji_icon(), etc.
116
+ | 3. Add content with replace_content() or append_markdown()
117
+ ```
118
+
119
+ ### Multi-Column Layout
120
+
121
+ ```markdown
122
+ ::: columns
123
+ ::: column
124
+
125
+ ## Left Column
126
+
127
+ - Item 1
128
+ - Item 2
129
+ - Item 3
130
+ :::
131
+ ::: column
132
+
133
+ ## Right Column
134
+
135
+ This text appears in the second column. Multi-column layouts are perfect for:
136
+
137
+ - Comparing features
138
+ - Creating side-by-side content
139
+ - Improving readability of wide content
140
+ :::
141
+ :::
142
+ ```
143
+
144
+ ### Code Blocks
145
+
146
+ ```python
147
+ def hello_world():
148
+ print("Hello from Notionary!")
149
+ ```
150
+
151
+ ### To-do Lists
152
+
153
+ ```markdown
154
+ - [ ] Define project scope
155
+ - [x] Create timeline
156
+ - [ ] Assign resources
157
+ ```
158
+
159
+ ### Tables
160
+
161
+ ```markdown
162
+ | Feature | Status | Priority |
163
+ | --------------- | ----------- | -------- |
164
+ | API Integration | Complete | High |
165
+ | Documentation | In Progress | Medium |
166
+ ```
167
+
168
+ ### More Elements
169
+
170
+ ```markdown
171
+ ![Caption](https://example.com/image.jpg)
172
+ @[Caption](https://youtube.com/watch?v=...)
173
+ [bookmark](https://example.com "Title" "Description")
174
+ ```
175
+
176
+ ## Examples
177
+
178
+ Explore the `examples/` directory for comprehensive guides:
179
+
180
+ ### 🚀 Core Examples
181
+ - [**Page Management**](examples/page_example.py) - Create, update, and manage Notion pages
182
+ - [**Page Operations**](examples/page.py) - Advanced page manipulation and content handling
183
+ - [**Database Operations**](examples/database.py) - Connect to and manage Notion databases
184
+ - [**Database Iteration**](examples/database_iteration.py) - Query and filter database entries
185
+ - [**Workspace Discovery**](examples/workspace_discovery.py) - Explore and discover your Notion workspace
186
+
187
+ ### 📝 Markdown Examples
188
+ - [**Basic Formatting**](examples/markdown/basic.py) - Text formatting, lists, and basic elements
189
+ - [**Callouts**](examples/markdown/callout.py) - Create beautiful callout blocks with icons
190
+ - [**Toggles**](examples/markdown/toggle.py) - Collapsible content sections
191
+ - [**Multi-Column Layouts**](examples/markdown/columns.py) - Side-by-side content arrangement
192
+ - [**Code Blocks**](examples/markdown/code.py) - Syntax-highlighted code examples
193
+ - [**Tables**](examples/markdown/table.py) - Structured data presentation
194
+ - [**Media Embeds**](examples/markdown/embed.py) - Images, videos, and rich media
195
+ - [**Audio Content**](examples/markdown/audio.py) - Audio file integration
196
+
197
+ Each example is self-contained and demonstrates specific features with practical use cases.
198
+
199
+ ## Contributing
200
+
201
+ Contributions welcome — feel free to submit a pull request!
@@ -26,7 +26,7 @@ class NotionDatabase(LoggingMixin):
26
26
  @factory_only("from_database_id", "from_database_name")
27
27
  def __init__(
28
28
  self,
29
- database_id: str,
29
+ id: str,
30
30
  title: str,
31
31
  url: str,
32
32
  emoji_icon: Optional[str] = None,
@@ -36,7 +36,7 @@ class NotionDatabase(LoggingMixin):
36
36
  """
37
37
  Initialize the minimal database manager.
38
38
  """
39
- self._database_id = database_id
39
+ self._id = id
40
40
  self._title = title
41
41
  self._url = url
42
42
  self._emoji_icon = emoji_icon
@@ -46,13 +46,13 @@ class NotionDatabase(LoggingMixin):
46
46
 
47
47
  @classmethod
48
48
  async def from_database_id(
49
- cls, database_id: str, token: Optional[str] = None
49
+ cls, id: str, token: Optional[str] = None
50
50
  ) -> NotionDatabase:
51
51
  """
52
52
  Create a NotionDatabase from a database ID using NotionDatabaseProvider.
53
53
  """
54
54
  provider = cls.get_database_provider()
55
- return await provider.get_database_by_id(database_id, token)
55
+ return await provider.get_database_by_id(id, token)
56
56
 
57
57
  @classmethod
58
58
  async def from_database_name(
@@ -68,9 +68,9 @@ class NotionDatabase(LoggingMixin):
68
68
  return await provider.get_database_by_name(database_name, token, min_similarity)
69
69
 
70
70
  @property
71
- def database_id(self) -> str:
71
+ def id(self) -> str:
72
72
  """Get the database ID (readonly)."""
73
- return self._database_id
73
+ return self._id
74
74
 
75
75
  @property
76
76
  def title(self) -> str:
@@ -109,7 +109,7 @@ class NotionDatabase(LoggingMixin):
109
109
  """
110
110
  try:
111
111
  create_page_response: NotionPageResponse = await self.client.create_page(
112
- parent_database_id=self.database_id
112
+ parent_database_id=self.id
113
113
  )
114
114
 
115
115
  return await NotionPage.from_page_id(page_id=create_page_response.id)
@@ -124,13 +124,13 @@ class NotionDatabase(LoggingMixin):
124
124
  """
125
125
  try:
126
126
  result = await self.client.update_database_title(
127
- database_id=self.database_id, title=new_title
127
+ database_id=self.id, title=new_title
128
128
  )
129
129
 
130
130
  self._title = result.title[0].plain_text
131
131
  self.logger.info(f"Successfully updated database title to: {new_title}")
132
132
  self.database_provider.invalidate_database_cache(
133
- database_id=self.database_id
133
+ database_id=self.id
134
134
  )
135
135
  return True
136
136
 
@@ -144,13 +144,13 @@ class NotionDatabase(LoggingMixin):
144
144
  """
145
145
  try:
146
146
  result = await self.client.update_database_emoji(
147
- database_id=self.database_id, emoji=new_emoji
147
+ database_id=self.id, emoji=new_emoji
148
148
  )
149
149
 
150
150
  self._emoji_icon = result.icon.emoji if result.icon else None
151
151
  self.logger.info(f"Successfully updated database emoji to: {new_emoji}")
152
152
  self.database_provider.invalidate_database_cache(
153
- database_id=self.database_id
153
+ database_id=self.id
154
154
  )
155
155
  return True
156
156
 
@@ -164,12 +164,12 @@ class NotionDatabase(LoggingMixin):
164
164
  """
165
165
  try:
166
166
  result = await self.client.update_database_cover_image(
167
- database_id=self.database_id, image_url=image_url
167
+ database_id=self.id, image_url=image_url
168
168
  )
169
169
 
170
170
  if result.cover and result.cover.external:
171
171
  self.database_provider.invalidate_database_cache(
172
- database_id=self.database_id
172
+ database_id=self.id
173
173
  )
174
174
  return result.cover.external.url
175
175
  return None
@@ -193,12 +193,12 @@ class NotionDatabase(LoggingMixin):
193
193
  """
194
194
  try:
195
195
  result = await self.client.update_database_external_icon(
196
- database_id=self.database_id, icon_url=external_icon_url
196
+ database_id=self.id, icon_url=external_icon_url
197
197
  )
198
198
 
199
199
  if result.icon and result.icon.external:
200
200
  self.database_provider.invalidate_database_cache(
201
- database_id=self.database_id
201
+ database_id=self.id
202
202
  )
203
203
  return result.icon.external.url
204
204
  return None
@@ -244,7 +244,7 @@ class NotionDatabase(LoggingMixin):
244
244
  """
245
245
  search_results: NotionQueryDatabaseResponse = (
246
246
  await self.client.query_database_by_title(
247
- database_id=self.database_id, page_title=page_title
247
+ database_id=self.id, page_title=page_title
248
248
  )
249
249
  )
250
250
 
@@ -296,7 +296,7 @@ class NotionDatabase(LoggingMixin):
296
296
  except Exception as e:
297
297
  self.logger.error(
298
298
  "Error fetching last_edited_time for database %s: %s",
299
- self.database_id,
299
+ self.id,
300
300
  str(e),
301
301
  )
302
302
  return None
@@ -345,7 +345,7 @@ class NotionDatabase(LoggingMixin):
345
345
  current_body["start_cursor"] = start_cursor
346
346
 
347
347
  result = await self.client.query_database(
348
- database_id=self.database_id, query_data=current_body
348
+ database_id=self.id, query_data=current_body
349
349
  )
350
350
 
351
351
  if not result or not result.results:
@@ -368,7 +368,7 @@ class NotionDatabase(LoggingMixin):
368
368
  emoji_icon = cls._extract_emoji_icon(db_response)
369
369
 
370
370
  instance = cls(
371
- database_id=db_response.id,
371
+ id=db_response.id,
372
372
  title=title,
373
373
  url=db_response.url,
374
374
  emoji_icon=emoji_icon,
@@ -55,10 +55,10 @@ class NotionDatabaseProvider(LoggingMixin, metaclass=SingletonMetaClass):
55
55
  database_name, token, min_similarity
56
56
  )
57
57
 
58
- id_cache_key = self._create_id_cache_key(database.database_id)
58
+ id_cache_key = self._create_id_cache_key(database.id)
59
59
  if not force_refresh and id_cache_key in self._database_cache:
60
60
  self.logger.debug(
61
- f"Found existing cached database by ID: {database.database_id}"
61
+ f"Found existing cached database by ID: {database.id}"
62
62
  )
63
63
  existing_database = self._database_cache[id_cache_key]
64
64
 
@@ -67,7 +67,7 @@ class NotionDatabaseProvider(LoggingMixin, metaclass=SingletonMetaClass):
67
67
 
68
68
  self._cache_database(database, token, database_name)
69
69
  self.logger.debug(
70
- f"Cached database: {database.title} (ID: {database.database_id})"
70
+ f"Cached database: {database.title} (ID: {database.id})"
71
71
  )
72
72
 
73
73
  return database
@@ -96,7 +96,7 @@ class NotionDatabaseProvider(LoggingMixin, metaclass=SingletonMetaClass):
96
96
  name_keys_to_remove = [
97
97
  cache_key
98
98
  for cache_key, cached_db in self._database_cache.items()
99
- if (cache_key.startswith("name:") and cached_db.database_id == database_id)
99
+ if (cache_key.startswith("name:") and cached_db.id == database_id)
100
100
  ]
101
101
 
102
102
  for name_key in name_keys_to_remove:
@@ -173,7 +173,7 @@ class NotionDatabaseProvider(LoggingMixin, metaclass=SingletonMetaClass):
173
173
  ) -> None:
174
174
  """Cache a database by both ID and name (if provided)."""
175
175
  # Always cache by ID
176
- id_cache_key = self._create_id_cache_key(database.database_id)
176
+ id_cache_key = self._create_id_cache_key(database.id)
177
177
  self._database_cache[id_cache_key] = database
178
178
 
179
179
  if original_name:
@@ -199,7 +199,7 @@ class NotionDatabaseProvider(LoggingMixin, metaclass=SingletonMetaClass):
199
199
  emoji_icon = self._extract_emoji_icon(db_response)
200
200
 
201
201
  instance = NotionDatabase(
202
- database_id=db_response.id,
202
+ id=db_response.id,
203
203
  title=title,
204
204
  url=db_response.url,
205
205
  emoji_icon=emoji_icon,
@@ -501,7 +501,7 @@ class NotionPage(LoggingMixin):
501
501
 
502
502
  parent_database = (
503
503
  await NotionDatabase.from_database_id(
504
- database_id=parent_database_id, token=token
504
+ id=parent_database_id, token=token
505
505
  )
506
506
  if parent_database_id
507
507
  else None
@@ -0,0 +1,27 @@
1
+ [project]
2
+ name = "notionary"
3
+ version = "0.2.15"
4
+ description = "Python library for programmatic Notion workspace management - databases, pages, and content with advanced Markdown support"
5
+ readme = "README.md"
6
+ requires-python = ">=3.9"
7
+ authors = [
8
+ { name = "Mathis Arends", email = "mathisarends27@gmail.com" }
9
+ ]
10
+ license = { text = "MIT" }
11
+ dependencies = [
12
+ "httpx>=0.28.0",
13
+ "python-dotenv>=1.1.0",
14
+ "pydantic>=2.11.4",
15
+ ]
16
+
17
+ [project.urls]
18
+ Homepage = "https://github.com/mathisarends/notionary"
19
+
20
+ [build-system]
21
+ requires = ["poetry-core"]
22
+ build-backend = "poetry.core.masonry.api"
23
+
24
+ [tool.poetry.group.dev.dependencies]
25
+ mkdocs = "^1.6.1"
26
+ mkdocs-material = "^9.6.15"
27
+