notionary 0.2.13__py3-none-any.whl → 0.2.15__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 (83) hide show
  1. notionary/__init__.py +3 -16
  2. notionary/{notion_client.py → base_notion_client.py} +92 -98
  3. notionary/blocks/__init__.py +61 -0
  4. notionary/{elements → blocks}/audio_element.py +6 -3
  5. notionary/{elements → blocks}/bookmark_element.py +3 -5
  6. notionary/{elements → blocks}/bulleted_list_element.py +5 -6
  7. notionary/{elements → blocks}/callout_element.py +4 -6
  8. notionary/{elements → blocks}/code_block_element.py +4 -5
  9. notionary/{elements → blocks}/column_element.py +3 -5
  10. notionary/{elements → blocks}/divider_element.py +3 -5
  11. notionary/{elements → blocks}/embed_element.py +4 -5
  12. notionary/{elements → blocks}/heading_element.py +4 -7
  13. notionary/{elements → blocks}/image_element.py +4 -5
  14. notionary/{elements → blocks}/mention_element.py +3 -6
  15. notionary/blocks/notion_block_client.py +26 -0
  16. notionary/{elements → blocks}/notion_block_element.py +2 -3
  17. notionary/{elements → blocks}/numbered_list_element.py +4 -6
  18. notionary/{elements → blocks}/paragraph_element.py +4 -6
  19. notionary/{prompting/element_prompt_content.py → blocks/prompts/element_prompt_builder.py} +1 -40
  20. notionary/blocks/prompts/element_prompt_content.py +41 -0
  21. notionary/{elements → blocks}/qoute_element.py +4 -5
  22. notionary/{elements → blocks}/registry/block_registry.py +4 -26
  23. notionary/{elements → blocks}/registry/block_registry_builder.py +26 -25
  24. notionary/{elements → blocks}/table_element.py +5 -6
  25. notionary/{elements → blocks}/text_inline_formatter.py +1 -4
  26. notionary/{elements → blocks}/todo_element.py +5 -6
  27. notionary/{elements → blocks}/toggle_element.py +3 -5
  28. notionary/{elements → blocks}/toggleable_heading_element.py +4 -6
  29. notionary/{elements → blocks}/video_element.py +4 -5
  30. notionary/database/__init__.py +0 -0
  31. notionary/database/client.py +132 -0
  32. notionary/database/database_exceptions.py +13 -0
  33. notionary/database/factory.py +0 -0
  34. notionary/database/filter_builder.py +175 -0
  35. notionary/database/notion_database.py +340 -127
  36. notionary/database/notion_database_provider.py +230 -0
  37. notionary/elements/__init__.py +0 -0
  38. notionary/models/notion_database_response.py +294 -13
  39. notionary/models/notion_page_response.py +9 -31
  40. notionary/models/search_response.py +0 -0
  41. notionary/page/__init__.py +0 -0
  42. notionary/page/client.py +110 -0
  43. notionary/page/content/page_content_retriever.py +5 -20
  44. notionary/page/content/page_content_writer.py +3 -4
  45. notionary/page/formatting/markdown_to_notion_converter.py +1 -3
  46. notionary/{prompting → page}/markdown_syntax_prompt_generator.py +1 -2
  47. notionary/page/notion_page.py +354 -317
  48. notionary/page/notion_to_markdown_converter.py +1 -4
  49. notionary/page/properites/property_value_extractor.py +0 -64
  50. notionary/page/{properites/property_formatter.py → property_formatter.py} +7 -4
  51. notionary/page/search_filter_builder.py +131 -0
  52. notionary/page/utils.py +60 -0
  53. notionary/util/__init__.py +12 -3
  54. notionary/util/factory_decorator.py +33 -0
  55. notionary/util/fuzzy_matcher.py +82 -0
  56. notionary/util/page_id_utils.py +0 -21
  57. notionary/util/singleton_metaclass.py +22 -0
  58. notionary/workspace.py +69 -0
  59. notionary-0.2.15.dist-info/METADATA +223 -0
  60. notionary-0.2.15.dist-info/RECORD +68 -0
  61. {notionary-0.2.13.dist-info → notionary-0.2.15.dist-info}/WHEEL +1 -2
  62. notionary/cli/main.py +0 -347
  63. notionary/cli/onboarding.py +0 -116
  64. notionary/database/database_discovery.py +0 -142
  65. notionary/database/notion_database_factory.py +0 -190
  66. notionary/exceptions/database_exceptions.py +0 -76
  67. notionary/exceptions/page_creation_exception.py +0 -9
  68. notionary/page/metadata/metadata_editor.py +0 -150
  69. notionary/page/metadata/notion_icon_manager.py +0 -77
  70. notionary/page/metadata/notion_page_cover_manager.py +0 -56
  71. notionary/page/notion_page_factory.py +0 -328
  72. notionary/page/properites/database_property_service.py +0 -302
  73. notionary/page/properites/page_property_manager.py +0 -152
  74. notionary/page/relations/notion_page_relation_manager.py +0 -350
  75. notionary/page/relations/notion_page_title_resolver.py +0 -104
  76. notionary/page/relations/page_database_relation.py +0 -68
  77. notionary/util/warn_direct_constructor_usage.py +0 -54
  78. notionary-0.2.13.dist-info/METADATA +0 -273
  79. notionary-0.2.13.dist-info/RECORD +0 -67
  80. notionary-0.2.13.dist-info/entry_points.txt +0 -2
  81. notionary-0.2.13.dist-info/top_level.txt +0 -1
  82. /notionary/util/{singleton.py → singleton_decorator.py} +0 -0
  83. {notionary-0.2.13.dist-info/licenses → notionary-0.2.15.dist-info}/LICENSE +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,68 @@
1
+ notionary/__init__.py,sha256=4eO6Jx57VRR_Ejo9w7IJeET8SZOvxFl_1lOB39o39No,250
2
+ notionary/base_notion_client.py,sha256=bqQu9uEdDmZhMAGGv6e_B8mBLOAWLWjoP8s9L6UaQks,6714
3
+ notionary/blocks/__init__.py,sha256=MFBxK3zZ28tV_u8XT20Q6HY39KENCfJDfDflLTYVt4E,2019
4
+ notionary/blocks/audio_element.py,sha256=rQbWz8akbobci8CFvnFuuHoDNJCG7mcuSXdB8hHjqLU,5355
5
+ notionary/blocks/bookmark_element.py,sha256=gW6uKCkuWFpHEzq-g1CbvKvma6hyTMUH2XMczI0U-5M,8080
6
+ notionary/blocks/bulleted_list_element.py,sha256=Uv_ohhF0MTwQ29w_RUX91NFuz57Dtr4vQpV8seRAgy0,2599
7
+ notionary/blocks/callout_element.py,sha256=Cya-1HIRBiCiyMgQq6PqXU4_iGj2O3qAPirhtC2QrTY,4446
8
+ notionary/blocks/code_block_element.py,sha256=w0AN5m1qEFEEMDZ5dicCUhh4RwQpjByzDW3PuHgvgt0,7466
9
+ notionary/blocks/column_element.py,sha256=qzbrTcWWOhGts2fAWHTwQUW8Ca6yoQEMZol9ZxUDCCI,12669
10
+ notionary/blocks/divider_element.py,sha256=eCX2OupttnjGUaIaF59RhULKqh8R6d8KPnpctMMaXJs,2267
11
+ notionary/blocks/embed_element.py,sha256=MFHh3ZFNntvaJ1NiEs0bzpbmJTRm0Axqdtf5oputbi0,4516
12
+ notionary/blocks/heading_element.py,sha256=aALMpclbPTvKfJOICJdgP0y-y7w5jhv7rUQl04TQpeg,3051
13
+ notionary/blocks/image_element.py,sha256=SEZ31_uDBRy6_lpn8E_GMX5uzI7-c-pJB9idUGZiTrE,4695
14
+ notionary/blocks/mention_element.py,sha256=G04nnc54YzUP8qu_aAx4-z56fspVrqCc4IHqSw4C5fk,8122
15
+ notionary/blocks/notion_block_client.py,sha256=mLkJ9mbfTZB7oml2hjXxxmr9XUCfM3u_8xjwKDi77oA,911
16
+ notionary/blocks/notion_block_element.py,sha256=r27KYICQvdmOg3AyzHE6ouWjX8WuJmX1bERCgkBdaGE,1263
17
+ notionary/blocks/numbered_list_element.py,sha256=BL_mui9vJ0usOFbRrNZRP_IY8QLG3vGFRYiPPsq_OJw,2596
18
+ notionary/blocks/paragraph_element.py,sha256=-zCwJOanOVjv07DRArD13yRYaxfL8sCob6oN3PKvzNc,3188
19
+ notionary/blocks/prompts/element_prompt_builder.py,sha256=rYMKPmpEFyk26JFZlwcTzMHATpvHnn4Dn284vewFog0,2953
20
+ notionary/blocks/prompts/element_prompt_content.py,sha256=ItnhGwKsHGnnY9E_LGgZZeTCT9ZfnkJY8xad4wFViWk,1567
21
+ notionary/blocks/qoute_element.py,sha256=pkeT6N7PZrepIod8WLrY1DMe2DW6fM98Y4zXiiACenw,6059
22
+ notionary/blocks/registry/block_registry.py,sha256=hEBa8PdFn1CeevFBqKbcFX7yuBjulwGASUMKoHRsm9s,4305
23
+ notionary/blocks/registry/block_registry_builder.py,sha256=FA_0WOajaeVaqdphNh8EyN0p_7ItzFqEufYa6YVBLeY,8731
24
+ notionary/blocks/table_element.py,sha256=DzXbSVm3KwTfnLF2cp765gj-VC50zWvj_0RU_WcQDJw,11184
25
+ notionary/blocks/text_inline_formatter.py,sha256=aKnaR1LvmbBkRdJVId8xtMkrbw1xaw6e4ZLUH97XLfU,8583
26
+ notionary/blocks/todo_element.py,sha256=6ndhgGJNiy7eb-Ll--Va7zEqQySxFAFYpzY4PWJbGUQ,4059
27
+ notionary/blocks/toggle_element.py,sha256=2gofKL4ndVkRxkuH-iYVx0YFUc649gpQQbZtwh2BpY8,11017
28
+ notionary/blocks/toggleable_heading_element.py,sha256=fkXvKtgCg6PuHqrHq7LupmqzpasJ1IyVf2RBLYTiVIo,9893
29
+ notionary/blocks/video_element.py,sha256=C19XxFRyAUEbhhC9xvhAAGN8YBYP6ON1vm_x7b_gUrY,5664
30
+ notionary/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ notionary/database/client.py,sha256=ZcfydeYlpgGJt6wV1ib33KeXUiL-cGNJ1qraQZ4RVRc,4775
32
+ notionary/database/database_exceptions.py,sha256=jwFdxoIQHLO3mO3p5t890--1FjbTX60fNyqBAe-sszo,452
33
+ notionary/database/factory.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ notionary/database/filter_builder.py,sha256=4EJnWUF73l5oi-HnvMu-mI1OncLzEs2o2mr_xG75quk,6315
35
+ notionary/database/models/page_result.py,sha256=Vmm5_oYpYAkIIJVoTd1ZZGloeC3cmFLMYP255mAmtaw,233
36
+ notionary/database/notion_database.py,sha256=7_BdQUbXjdSHgK9heV3aIWLHdr5jPtofsY3_LHo2ZKs,15317
37
+ notionary/database/notion_database_provider.py,sha256=-cw94OdvjX3aFeWxIf1eD4dLcRaDC6ni6DBTqO0JPaY,9065
38
+ notionary/elements/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ notionary/models/notion_block_response.py,sha256=gzL4C6K9QPcaMS6NbAZaRceSEnMbNwYBVVzxysza5VU,6002
40
+ notionary/models/notion_database_response.py,sha256=3kvADIP1dSxgITSK4n8Ex3QpF8n_Lxnu_IXbPVGcq4o,7648
41
+ notionary/models/notion_page_response.py,sha256=7ZwDYhlyK-avix_joQpGuNQZopjlQFI8jS3nvNNumoc,1544
42
+ notionary/models/search_response.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
+ notionary/page/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
+ notionary/page/client.py,sha256=XQ72lOEwn-gO8fmhKSKHqSHs3hRmoKH0TkJ3TtblcAg,4030
45
+ notionary/page/content/notion_page_content_chunker.py,sha256=kWJnV9GLU5YLgSVPKOjwMBbG_CMAmVRkuDtwJYb_UAA,3316
46
+ notionary/page/content/page_content_retriever.py,sha256=iNazSf0uv_gi0J816-SZn4Lw4qbAxRHG90k9Jy_qw2Q,1587
47
+ notionary/page/content/page_content_writer.py,sha256=VVvK-Z8NvyIhi7Crcm9mZQuuD_L72NsqSQg9gf33Zwk,7369
48
+ notionary/page/formatting/markdown_to_notion_converter.py,sha256=9RyGON8VrJv6XifdQdOt5zKgKT3irc974zcbGDBhmLY,17328
49
+ notionary/page/formatting/spacer_rules.py,sha256=j2RHvdXT3HxXPVBEuCtulyy9cPxsEcOmj71pJqV-D3M,15677
50
+ notionary/page/markdown_syntax_prompt_generator.py,sha256=uHCPNV9aQi3GzLVimyUKwza29hfxu6DTMVIa_QevJbk,4987
51
+ notionary/page/notion_page.py,sha256=G639FNg8eIvQ9t3-Aa3W0vtmxHOhwCnuFICLFKUA4KE,19142
52
+ notionary/page/notion_to_markdown_converter.py,sha256=_MJWWwsBvgZ3a8tLZ23ZCIA_G9Qfvt2JG1FqVTlRxHs,6308
53
+ notionary/page/properites/property_value_extractor.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
+ notionary/page/property_formatter.py,sha256=_978ViH83gfcr-XtDscWTfyBI2srGW2hzC-gzgp5NR8,3788
55
+ notionary/page/search_filter_builder.py,sha256=wZpW_KHmPXql3sNIyQd9EzZ2-ERy2i0vYNdoLkoBUfc,4597
56
+ notionary/page/utils.py,sha256=2nfBrWeczBdPH13R3q8dKP4OY4MwEdfKbcs2UJ9kg1o,2041
57
+ notionary/util/__init__.py,sha256=EzAmP2uEFfazWapb41BY9kAua1ZEiuLRPaBMtw_cOYg,358
58
+ notionary/util/factory_decorator.py,sha256=3SD63EPxXMmKQ8iF7sF88xUFMG8dy14L2DJZ7XdcYm4,1110
59
+ notionary/util/fuzzy_matcher.py,sha256=RYR86hMTp8lrWl3PeOa3RpDpzh04HJ30qrIlrq6_qDo,2442
60
+ notionary/util/logging_mixin.py,sha256=d5sRSmUtgQeuckdNBkO025IXPGe4oOb-7ueVAIP8amU,1846
61
+ notionary/util/page_id_utils.py,sha256=AA00kRO-g3Cc50tf_XW_tb5RBuPKLuBxRa0D8LYhLXg,736
62
+ notionary/util/singleton_decorator.py,sha256=CKAvykndwPRZsA3n3MAY_XdCR59MBjjKP0vtm2BcvF0,428
63
+ notionary/util/singleton_metaclass.py,sha256=uNeHiqS6TwhljvG1RE4NflIp2HyMuMmrCg2xI-vxmHE,809
64
+ notionary/workspace.py,sha256=kW9fbVUSECivlvABBwnks2nALfk09V6g6Oc2Eq_pK5U,2511
65
+ notionary-0.2.15.dist-info/LICENSE,sha256=zOm3cRT1qD49eg7vgw95MI79rpUAZa1kRBFwL2FkAr8,1120
66
+ notionary-0.2.15.dist-info/METADATA,sha256=rFzkz08VRrwANPLLkbDTrfG5vhR7opqj35ApvYQd0kA,6784
67
+ notionary-0.2.15.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
68
+ notionary-0.2.15.dist-info/RECORD,,
@@ -1,5 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: poetry-core 2.1.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
-
notionary/cli/main.py DELETED
@@ -1,347 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Notionary CLI - Integration Key Setup
4
- """
5
-
6
- import click
7
- import os
8
- import platform
9
- import asyncio
10
- import logging
11
- from pathlib import Path
12
- from dotenv import load_dotenv
13
- from rich.console import Console
14
- from rich.panel import Panel
15
- from rich.prompt import Prompt, Confirm
16
- from rich.table import Table
17
- from rich import box
18
- from rich.progress import Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
19
- from notionary.notion_client import NotionClient
20
- from notionary.database.database_discovery import DatabaseDiscovery
21
-
22
- # Disable logging for CLI usage
23
- def disable_notionary_logging():
24
- """Disable logging for notionary modules when used in CLI"""
25
- # Option 1: Set to WARNING level (recommended for CLI)
26
- logging.getLogger('notionary').setLevel(logging.WARNING)
27
- logging.getLogger('DatabaseDiscovery').setLevel(logging.WARNING)
28
- logging.getLogger('NotionClient').setLevel(logging.WARNING)
29
-
30
- def enable_verbose_logging():
31
- """Enable verbose logging for debugging (use with --verbose flag)"""
32
- logging.getLogger('notionary').setLevel(logging.DEBUG)
33
- logging.getLogger('DatabaseDiscovery').setLevel(logging.DEBUG)
34
- logging.getLogger('NotionClient').setLevel(logging.DEBUG)
35
-
36
- # Initialize logging configuration for CLI
37
- disable_notionary_logging()
38
-
39
- console = Console()
40
-
41
- def get_paste_tips():
42
- """Get platform-specific paste tips"""
43
- system = platform.system().lower()
44
-
45
- if system == "darwin": # macOS
46
- return [
47
- "• Terminal: [cyan]Cmd+V[/cyan]",
48
- "• iTerm2: [cyan]Cmd+V[/cyan]",
49
- ]
50
- elif system == "windows":
51
- return [
52
- "• PowerShell: [cyan]Right-click[/cyan] or [cyan]Shift+Insert[/cyan]",
53
- "• cmd: [cyan]Right-click[/cyan]",
54
- ]
55
- else: # Linux and others
56
- return [
57
- "• Terminal: [cyan]Ctrl+Shift+V[/cyan] or [cyan]Right-click[/cyan]",
58
- "• Some terminals: [cyan]Shift+Insert[/cyan]",
59
- ]
60
-
61
- def show_paste_tips():
62
- """Show platform-specific paste tips"""
63
- console.print("\n[bold yellow]💡 Paste Tips:[/bold yellow]")
64
- for tip in get_paste_tips():
65
- console.print(tip)
66
- console.print()
67
-
68
- def get_notion_secret() -> str:
69
- """Get NOTION_SECRET using the same logic as NotionClient"""
70
- load_dotenv()
71
- return os.getenv("NOTION_SECRET", "")
72
-
73
- async def fetch_notion_databases_with_progress():
74
- """Fetch databases using DatabaseDiscovery with progress animation"""
75
- try:
76
- # Initialize NotionClient and DatabaseDiscovery
77
- client = NotionClient()
78
- discovery = DatabaseDiscovery(client)
79
-
80
- # Create progress display with custom spinner
81
- with Progress(
82
- SpinnerColumn(spinner_name="dots12", style="cyan"),
83
- TextColumn("[bold blue]Discovering databases..."),
84
- TimeElapsedColumn(),
85
- console=console,
86
- transient=True
87
- ) as progress:
88
- # Add progress task
89
- task = progress.add_task("Fetching...", total=None)
90
-
91
- # Fetch databases
92
- databases = await discovery._discover(page_size=50)
93
-
94
- # Update progress to show completion
95
- progress.update(task, description=f"[bold green]Found {len(databases)} databases!")
96
-
97
- # Brief pause to show completion
98
- await asyncio.sleep(0.5)
99
-
100
- return {"databases": databases, "success": True}
101
-
102
- except Exception as e:
103
- return {"error": str(e), "success": False}
104
-
105
- def show_databases_overview(api_key: str):
106
- """Show available databases with nice formatting"""
107
- console.print("\n[bold blue]🔍 Connecting to Notion...[/bold blue]")
108
-
109
- # Run async function in sync context
110
- try:
111
- result = asyncio.run(fetch_notion_databases_with_progress())
112
- except Exception as e:
113
- console.print(Panel.fit(
114
- f"[bold red]❌ Unexpected error[/bold red]\n\n"
115
- f"[red]{str(e)}[/red]\n\n"
116
- "[yellow]Please check:[/yellow]\n"
117
- "• Your internet connection\n"
118
- "• Your integration key validity\n"
119
- "• Try running the command again",
120
- title="Connection Error"
121
- ))
122
- return
123
-
124
- if not result["success"]:
125
- console.print(Panel.fit(
126
- f"[bold red]❌ Could not fetch databases[/bold red]\n\n"
127
- f"[red]{result['error']}[/red]\n\n"
128
- "[yellow]Common issues:[/yellow]\n"
129
- "• Check your integration key\n"
130
- "• Make sure your integration has access to databases\n"
131
- "• Visit your integration settings to grant access",
132
- title="Connection Error"
133
- ))
134
- return
135
-
136
- databases = result["databases"]
137
-
138
- if not databases:
139
- console.print(Panel.fit(
140
- "[bold yellow]⚠️ No databases found[/bold yellow]\n\n"
141
- "Your integration key is valid, but no databases are accessible.\n\n"
142
- "[bold blue]To grant access:[/bold blue]\n"
143
- "1. Go to any Notion database\n"
144
- "2. Click the '...' menu (top right)\n"
145
- "3. Go to 'Add connections'\n"
146
- "4. Find and select your integration\n\n"
147
- "[cyan]https://www.notion.so/help/add-and-manage-connections-with-the-api[/cyan]",
148
- title="No Databases Available"
149
- ))
150
- return
151
-
152
- # Create beautiful table
153
- table = Table(
154
- title=f"📊 Available Databases ({len(databases)} found)",
155
- box=box.ROUNDED,
156
- title_style="bold green",
157
- header_style="bold cyan"
158
- )
159
-
160
- table.add_column("#", style="dim", justify="right", width=3)
161
- table.add_column("Database Name", style="bold white", min_width=25)
162
- table.add_column("ID", style="dim cyan", min_width=36)
163
-
164
- for i, (title, db_id) in enumerate(databases, 1):
165
- table.add_row(
166
- str(i),
167
- title or "Untitled Database",
168
- db_id
169
- )
170
-
171
- console.print("\n")
172
- console.print(table)
173
-
174
- # Success message with next steps
175
- console.print(Panel.fit(
176
- "[bold green]🎉 Setup Complete![/bold green]\n\n"
177
- f"Found [bold cyan]{len(databases)}[/bold cyan] accessible database(s).\n"
178
- "You can now use notionary in your Python code!\n\n"
179
- "[bold yellow]💡 Tip:[/bold yellow] Run [cyan]notionary db[/cyan] anytime to see this overview again.",
180
- title="Ready to Go!"
181
- ))
182
-
183
- @click.group()
184
- @click.version_option() # Automatische Version aus setup.py
185
- @click.option('--verbose', '-v', is_flag=True, help='Enable verbose logging')
186
- def main(verbose):
187
- """
188
- Notionary CLI - Notion API Integration
189
- """
190
- if verbose:
191
- enable_verbose_logging()
192
- console.print("[dim]Verbose logging enabled[/dim]")
193
- pass
194
-
195
- @main.command()
196
- def init():
197
- """
198
- Setup your Notion Integration Key
199
- """
200
- # Check if key already exists
201
- existing_key = get_notion_secret()
202
-
203
- if existing_key:
204
- console.print(Panel.fit(
205
- "[bold green]✅ You're all set![/bold green]\n"
206
- f"Your Notion Integration Key is already configured.\n"
207
- f"Key: [dim]{existing_key[:8]}...[/dim]",
208
- title="Already Configured"
209
- ))
210
-
211
- # Option to reconfigure or show databases
212
- choice = Prompt.ask(
213
- "\n[yellow]What would you like to do?[/yellow]",
214
- choices=["show", "update", "exit"],
215
- default="show"
216
- )
217
-
218
- if choice == "show":
219
- show_databases_overview(existing_key)
220
- elif choice == "update":
221
- setup_new_key()
222
- else:
223
- console.print("\n[blue]Happy coding! 🚀[/blue]")
224
- else:
225
- # No key found, start setup
226
- console.print(Panel.fit(
227
- "[bold green]🚀 Notionary Setup[/bold green]\n"
228
- "Enter your Notion Integration Key to get started...\n\n"
229
- "[bold blue]🔗 Create an Integration Key or get an existing one:[/bold blue]\n"
230
- "[cyan]https://www.notion.so/profile/integrations[/cyan]",
231
- title="Initialization"
232
- ))
233
- setup_new_key()
234
-
235
- @main.command()
236
- def db() -> None:
237
- """
238
- Show available Notion databases
239
- """
240
- existing_key = get_notion_secret()
241
-
242
- if not existing_key:
243
- console.print(Panel.fit(
244
- "[bold red]❌ No Integration Key found![/bold red]\n\n"
245
- "Please run [cyan]notionary init[/cyan] first to set up your key.",
246
- title="Not Configured"
247
- ))
248
- return
249
-
250
- show_databases_overview(existing_key)
251
-
252
- def setup_new_key():
253
- """Handle the key setup process"""
254
- try:
255
- # Show Integration Key creation link
256
- console.print("\n[bold blue]🔗 Create an Integration Key:[/bold blue]")
257
- console.print("[cyan]https://www.notion.so/profile/integrations[/cyan]")
258
- console.print()
259
-
260
- # Get integration key
261
- integration_key = Prompt.ask(
262
- "[bold cyan]Notion Integration Key[/bold cyan]"
263
- )
264
-
265
- # Input validation
266
- if not integration_key or not integration_key.strip():
267
- console.print("[bold red]❌ Integration Key cannot be empty![/bold red]")
268
- return
269
-
270
- # Trim whitespace
271
- integration_key = integration_key.strip()
272
-
273
- # Check for common paste issues
274
- if integration_key in ["^V", "^v", "^C", "^c"]:
275
- console.print("[bold red]❌ Paste didn't work! Try:[/bold red]")
276
- show_paste_tips()
277
- return
278
-
279
- # Show masked feedback that paste worked
280
- masked_key = "•" * len(integration_key)
281
- console.print(f"[dim]Received: {masked_key} ({len(integration_key)} characters)[/dim]")
282
-
283
- # Basic validation for Notion keys
284
- if not integration_key.startswith('ntn_') or len(integration_key) < 30:
285
- console.print("[bold yellow]⚠️ Warning: This doesn't look like a valid Notion Integration Key[/bold yellow]")
286
- console.print("[dim]Notion keys usually start with 'ntn_' and are about 50+ characters long[/dim]")
287
- if not Confirm.ask("Continue anyway?"):
288
- return
289
-
290
- # Save the key
291
- if save_integration_key(integration_key):
292
- # Show databases overview after successful setup
293
- show_databases_overview(integration_key)
294
-
295
- except KeyboardInterrupt:
296
- console.print("\n[yellow]Setup cancelled.[/yellow]")
297
- except Exception as e:
298
- console.print(f"\n[bold red]❌ Error during setup: {e}[/bold red]")
299
- raise click.Abort()
300
-
301
- def save_integration_key(integration_key: str) -> bool:
302
- """Save the integration key to .env file"""
303
- try:
304
- # .env Datei im aktuellen Verzeichnis erstellen/aktualisieren
305
- env_file = Path.cwd() / ".env"
306
-
307
- # Bestehende .env lesen falls vorhanden
308
- existing_lines = []
309
- if env_file.exists():
310
- with open(env_file, 'r', encoding='utf-8') as f:
311
- existing_lines = [line.rstrip() for line in f.readlines()]
312
-
313
- # NOTION_SECRET Zeile hinzufügen/ersetzen
314
- updated_lines = []
315
- notion_secret_found = False
316
-
317
- for line in existing_lines:
318
- if line.startswith('NOTION_SECRET='):
319
- updated_lines.append(f'NOTION_SECRET={integration_key}')
320
- notion_secret_found = True
321
- else:
322
- updated_lines.append(line)
323
-
324
- # Falls NOTION_SECRET noch nicht existiert, hinzufügen
325
- if not notion_secret_found:
326
- updated_lines.append(f'NOTION_SECRET={integration_key}')
327
-
328
- # .env Datei schreiben
329
- with open(env_file, 'w', encoding='utf-8') as f:
330
- f.write('\n'.join(updated_lines) + '\n')
331
-
332
- # Verification
333
- written_key = get_notion_secret()
334
- if written_key == integration_key:
335
- console.print("\n[bold green]✅ Integration Key saved and verified![/bold green]")
336
- console.print(f"[dim]Configuration: {env_file}[/dim]")
337
- return True
338
- else:
339
- console.print("\n[bold red]❌ Error: Key verification failed![/bold red]")
340
- return False
341
-
342
- except Exception as e:
343
- console.print(f"\n[bold red]❌ Error saving key: {e}[/bold red]")
344
- return False
345
-
346
- if __name__ == '__main__':
347
- main()