notionary 0.1.6__py3-none-any.whl → 0.1.8__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/core/database/notion_database_manager.py +146 -232
- notionary/core/database/notion_database_manager_factory.py +9 -52
- notionary/core/database/notion_database_schema.py +1 -314
- notionary/core/notion_client.py +2 -10
- notionary/core/page/{page_content_manager.py → content/page_content_manager.py} +10 -6
- notionary/core/page/metadata/metadata_editor.py +109 -0
- notionary/core/page/metadata/notion_icon_manager.py +46 -0
- notionary/core/page/{meta_data/metadata_editor.py → metadata/notion_page_cover_manager.py} +20 -30
- notionary/core/page/notion_page_manager.py +218 -59
- notionary/core/page/properites/database_property_service.py +330 -0
- notionary/core/page/properites/page_property_manager.py +146 -0
- notionary/core/page/{property_formatter.py → properites/property_formatter.py} +19 -20
- notionary/core/page/properites/property_operation_result.py +103 -0
- notionary/core/page/properites/property_value_extractor.py +46 -0
- notionary/core/page/relations/notion_page_relation_manager.py +364 -0
- notionary/core/page/relations/notion_page_title_resolver.py +43 -0
- notionary/core/page/relations/page_database_relation.py +70 -0
- notionary/core/page/relations/relation_operation_result.py +135 -0
- notionary/util/page_id_utils.py +44 -0
- {notionary-0.1.6.dist-info → notionary-0.1.8.dist-info}/METADATA +1 -1
- {notionary-0.1.6.dist-info → notionary-0.1.8.dist-info}/RECORD +24 -18
- notionary/core/database/database_query_service.py +0 -73
- notionary/core/database/database_schema_service.py +0 -57
- notionary/core/database/notion_database_writer.py +0 -390
- notionary/core/database/page_service.py +0 -161
- notionary/util/uuid_utils.py +0 -24
- {notionary-0.1.6.dist-info → notionary-0.1.8.dist-info}/WHEEL +0 -0
- {notionary-0.1.6.dist-info → notionary-0.1.8.dist-info}/licenses/LICENSE +0 -0
- {notionary-0.1.6.dist-info → notionary-0.1.8.dist-info}/top_level.txt +0 -0
@@ -1,244 +1,83 @@
|
|
1
|
-
from typing import Any, AsyncGenerator, Dict, List, Optional
|
1
|
+
from typing import Any, AsyncGenerator, Dict, List, Optional
|
2
2
|
|
3
|
-
from notionary.core.database.database_info_service import DatabaseInfoService
|
4
|
-
from notionary.core.database.database_query_service import DatabaseQueryService
|
5
|
-
from notionary.core.database.database_schema_service import DatabaseSchemaService
|
6
|
-
from notionary.core.database.models.page_result import PageResult
|
7
|
-
from notionary.core.database.page_service import DatabasePageService
|
8
3
|
from notionary.core.notion_client import NotionClient
|
9
|
-
from notionary.core.database.notion_database_schema import NotionDatabaseSchema
|
10
|
-
from notionary.core.database.notion_database_writer import DatabaseWritter
|
11
4
|
from notionary.core.page.notion_page_manager import NotionPageManager
|
12
|
-
from notionary.exceptions.database_exceptions import (
|
13
|
-
DatabaseInitializationError,
|
14
|
-
PropertyError,
|
15
|
-
)
|
16
5
|
from notionary.util.logging_mixin import LoggingMixin
|
17
|
-
from notionary.util.
|
6
|
+
from notionary.util.page_id_utils import format_uuid
|
18
7
|
|
19
8
|
|
20
9
|
class NotionDatabaseManager(LoggingMixin):
|
21
10
|
"""
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
Note:
|
26
|
-
It is recommended to create instances of this class using the NotionDatabaseFactory
|
27
|
-
instead of directly calling the constructor.
|
11
|
+
Minimal manager for Notion databases.
|
12
|
+
Focused exclusively on creating basic pages and retrieving page managers
|
13
|
+
for further page operations.
|
28
14
|
"""
|
29
15
|
|
30
16
|
def __init__(self, database_id: str, token: Optional[str] = None):
|
31
17
|
"""
|
32
|
-
Initialize the
|
33
|
-
|
34
|
-
Note:
|
35
|
-
It's recommended to use NotionDatabaseFactory to create instances of this class
|
36
|
-
rather than using this constructor directly.
|
18
|
+
Initialize the minimal database manager.
|
37
19
|
|
38
20
|
Args:
|
39
|
-
database_id:
|
40
|
-
token: Optional Notion API token
|
21
|
+
database_id: ID of the Notion database
|
22
|
+
token: Optional Notion API token
|
41
23
|
"""
|
42
24
|
self.database_id = format_uuid(database_id) or database_id
|
43
25
|
self._client = NotionClient(token=token)
|
44
|
-
self._schema = NotionDatabaseSchema(self.database_id, self._client)
|
45
|
-
self._writer = DatabaseWritter(self._client, self._schema)
|
46
|
-
self._initialized = False
|
47
|
-
|
48
|
-
self._info_service = DatabaseInfoService(self._client, self.database_id)
|
49
|
-
self._page_service = DatabasePageService(
|
50
|
-
self._client, self._schema, self._writer
|
51
|
-
)
|
52
|
-
self._query_service = DatabaseQueryService(self._schema)
|
53
|
-
self._schema_service = DatabaseSchemaService(self._schema)
|
54
26
|
|
55
|
-
@property
|
56
|
-
def title(self) -> Optional[str]:
|
57
|
-
"""Get the database title."""
|
58
|
-
return self._info_service.title
|
59
|
-
|
60
|
-
async def initialize(self) -> bool:
|
61
|
-
"""
|
62
|
-
Initialize the database facade by loading the schema.
|
63
|
-
|
64
|
-
This method needs to be called after creating a new instance via the constructor.
|
65
|
-
When using NotionDatabaseFactory, this is called automatically.
|
66
|
-
"""
|
67
|
-
try:
|
68
|
-
success = await self._schema.load()
|
69
|
-
if not success:
|
70
|
-
self.logger.error(
|
71
|
-
"Failed to load schema for database %s", self.database_id
|
72
|
-
)
|
73
|
-
return False
|
74
|
-
|
75
|
-
await self._info_service.load_title()
|
76
|
-
self.logger.debug("Loaded database title: %s", self.title)
|
77
|
-
|
78
|
-
self._initialized = True
|
79
|
-
return True
|
80
|
-
except Exception as e:
|
81
|
-
self.logger.error("Error initializing database: %s", str(e))
|
82
|
-
return False
|
83
|
-
|
84
|
-
async def _ensure_initialized(self) -> None:
|
85
|
-
"""
|
86
|
-
Ensure the database manager is initialized before use.
|
87
|
-
|
88
|
-
Raises:
|
89
|
-
DatabaseInitializationError: If the database isn't initialized
|
90
|
-
"""
|
91
|
-
if not self._initialized:
|
92
|
-
raise DatabaseInitializationError(
|
93
|
-
self.database_id,
|
94
|
-
"Database manager not initialized. Call initialize() first.",
|
95
|
-
)
|
96
27
|
|
97
|
-
async def
|
28
|
+
async def create_blank_page(self) -> Optional[str]:
|
98
29
|
"""
|
99
|
-
|
100
|
-
|
30
|
+
Create a new blank page in the database with minimal properties.
|
31
|
+
|
101
32
|
Returns:
|
102
|
-
The
|
33
|
+
Optional[str]: The ID of the created page, or None if creation failed
|
103
34
|
"""
|
104
|
-
await self._ensure_initialized()
|
105
|
-
|
106
|
-
if self.title:
|
107
|
-
return self.title
|
108
|
-
|
109
35
|
try:
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
"""
|
117
|
-
Get all property types for the database.
|
118
|
-
|
119
|
-
Returns:
|
120
|
-
Dictionary mapping property names to their types
|
121
|
-
"""
|
122
|
-
await self._ensure_initialized()
|
123
|
-
return await self._schema_service.get_property_types()
|
124
|
-
|
125
|
-
async def get_select_options(self, property_name: str) -> List[Dict[str, str]]:
|
126
|
-
"""
|
127
|
-
Get options for a select, multi-select, or status property.
|
128
|
-
|
129
|
-
Args:
|
130
|
-
property_name: Name of the property
|
131
|
-
|
132
|
-
Returns:
|
133
|
-
List of select options with name, id, and color (if available)
|
134
|
-
"""
|
135
|
-
await self._ensure_initialized()
|
136
|
-
return await self._schema_service.get_select_options(property_name)
|
137
|
-
|
138
|
-
async def get_relation_options(
|
139
|
-
self, property_name: str, limit: int = 100
|
140
|
-
) -> List[Dict[str, str]]:
|
141
|
-
"""
|
142
|
-
Get available options for a relation property.
|
143
|
-
|
144
|
-
Args:
|
145
|
-
property_name: Name of the relation property
|
146
|
-
limit: Maximum number of options to retrieve
|
147
|
-
|
148
|
-
Returns:
|
149
|
-
List of relation options with id and title
|
150
|
-
"""
|
151
|
-
await self._ensure_initialized()
|
152
|
-
return await self._schema_service.get_relation_options(property_name, limit)
|
153
|
-
|
154
|
-
async def create_page(
|
155
|
-
self,
|
156
|
-
properties: Dict[str, Any],
|
157
|
-
relations: Optional[Dict[str, Union[str, List[str]]]] = None,
|
158
|
-
) -> PageResult:
|
159
|
-
"""
|
160
|
-
Create a new page in the database.
|
161
|
-
|
162
|
-
Args:
|
163
|
-
properties: Dictionary of property names and values
|
164
|
-
relations: Optional dictionary of relation property names and titles
|
165
|
-
|
166
|
-
Returns:
|
167
|
-
Result object with success status and page information
|
168
|
-
"""
|
169
|
-
await self._ensure_initialized()
|
170
|
-
|
171
|
-
result = await self._page_service.create_page(
|
172
|
-
self.database_id, properties, relations
|
173
|
-
)
|
174
|
-
|
175
|
-
if result["success"]:
|
176
|
-
self.logger.info(
|
177
|
-
"Created page %s in database %s",
|
178
|
-
result.get("page_id", ""),
|
179
|
-
self.database_id,
|
180
|
-
)
|
181
|
-
else:
|
182
|
-
self.logger.warning("Page creation failed: %s", result.get("message", ""))
|
183
|
-
|
184
|
-
return result
|
185
|
-
|
186
|
-
async def update_page(
|
187
|
-
self,
|
188
|
-
page_id: str,
|
189
|
-
properties: Optional[Dict[str, Any]] = None,
|
190
|
-
relations: Optional[Dict[str, Union[str, List[str]]]] = None,
|
191
|
-
) -> PageResult:
|
192
|
-
"""
|
193
|
-
Update an existing page.
|
194
|
-
|
195
|
-
Args:
|
196
|
-
page_id: The ID of the page to update
|
197
|
-
properties: Dictionary of property names and values to update
|
198
|
-
relations: Optional dictionary of relation property names and titles
|
199
|
-
|
200
|
-
Returns:
|
201
|
-
Result object with success status and message
|
202
|
-
"""
|
203
|
-
await self._ensure_initialized()
|
204
|
-
|
205
|
-
self.logger.debug("Updating page %s", page_id)
|
206
|
-
|
207
|
-
result = await self._page_service.update_page(page_id, properties, relations)
|
208
|
-
|
209
|
-
if result["success"]:
|
210
|
-
self.logger.info("Successfully updated page %s", result.get("page_id", ""))
|
211
|
-
else:
|
212
|
-
self.logger.error(
|
213
|
-
"Error updating page %s: %s", page_id, result.get("message", "")
|
36
|
+
response = await self._client.post(
|
37
|
+
"pages",
|
38
|
+
{
|
39
|
+
"parent": {"database_id": self.database_id},
|
40
|
+
"properties": {}
|
41
|
+
}
|
214
42
|
)
|
43
|
+
|
44
|
+
if response and "id" in response:
|
45
|
+
page_id = response["id"]
|
46
|
+
self.logger.info("Created blank page %s in database %s", page_id, self.database_id)
|
47
|
+
return page_id
|
48
|
+
|
49
|
+
self.logger.warning("Page creation failed: invalid response")
|
50
|
+
return None
|
51
|
+
|
52
|
+
except Exception as e:
|
53
|
+
self.logger.error("Error creating blank page: %s", str(e))
|
54
|
+
return None
|
215
55
|
|
216
|
-
|
217
|
-
|
218
|
-
async def delete_page(self, page_id: str) -> PageResult:
|
56
|
+
async def get_page_manager(self, page_id: str) -> Optional[NotionPageManager]:
|
219
57
|
"""
|
220
|
-
|
58
|
+
Get a NotionPageManager for a specific page.
|
221
59
|
|
222
60
|
Args:
|
223
|
-
page_id: The ID of the page
|
61
|
+
page_id: The ID of the page
|
224
62
|
|
225
63
|
Returns:
|
226
|
-
|
64
|
+
NotionPageManager instance or None if the page wasn't found
|
227
65
|
"""
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
66
|
+
self.logger.debug("Getting page manager for page %s", page_id)
|
67
|
+
|
68
|
+
try:
|
69
|
+
# Check if the page exists
|
70
|
+
page_data = await self._client.get_page(page_id)
|
71
|
+
|
72
|
+
if not page_data:
|
73
|
+
self.logger.error("Page %s not found", page_id)
|
74
|
+
return None
|
75
|
+
|
76
|
+
return NotionPageManager(page_id=page_id)
|
77
|
+
|
78
|
+
except Exception as e:
|
79
|
+
self.logger.error("Error getting page manager: %s", str(e))
|
80
|
+
return None
|
242
81
|
|
243
82
|
async def get_pages(
|
244
83
|
self,
|
@@ -257,8 +96,6 @@ class NotionDatabaseManager(LoggingMixin):
|
|
257
96
|
Returns:
|
258
97
|
List of NotionPageManager instances for each page
|
259
98
|
"""
|
260
|
-
await self._ensure_initialized()
|
261
|
-
|
262
99
|
self.logger.debug(
|
263
100
|
"Getting up to %d pages with filter: %s, sorts: %s",
|
264
101
|
limit,
|
@@ -266,9 +103,19 @@ class NotionDatabaseManager(LoggingMixin):
|
|
266
103
|
sorts,
|
267
104
|
)
|
268
105
|
|
269
|
-
pages =
|
270
|
-
|
271
|
-
|
106
|
+
pages: List[NotionPageManager] = []
|
107
|
+
count = 0
|
108
|
+
|
109
|
+
async for page in self.iter_pages(
|
110
|
+
page_size=min(limit, 100),
|
111
|
+
filter_conditions=filter_conditions,
|
112
|
+
sorts=sorts,
|
113
|
+
):
|
114
|
+
pages.append(page)
|
115
|
+
count += 1
|
116
|
+
|
117
|
+
if count >= limit:
|
118
|
+
break
|
272
119
|
|
273
120
|
self.logger.debug(
|
274
121
|
"Retrieved %d pages from database %s", len(pages), self.database_id
|
@@ -283,6 +130,7 @@ class NotionDatabaseManager(LoggingMixin):
|
|
283
130
|
) -> AsyncGenerator[NotionPageManager, None]:
|
284
131
|
"""
|
285
132
|
Asynchronous generator that yields pages from the database.
|
133
|
+
Directly queries the Notion API without using the schema.
|
286
134
|
|
287
135
|
Args:
|
288
136
|
page_size: Number of pages to fetch per request
|
@@ -292,8 +140,6 @@ class NotionDatabaseManager(LoggingMixin):
|
|
292
140
|
Yields:
|
293
141
|
NotionPageManager instances for each page
|
294
142
|
"""
|
295
|
-
await self._ensure_initialized()
|
296
|
-
|
297
143
|
self.logger.debug(
|
298
144
|
"Iterating pages with page_size: %d, filter: %s, sorts: %s",
|
299
145
|
page_size,
|
@@ -301,32 +147,100 @@ class NotionDatabaseManager(LoggingMixin):
|
|
301
147
|
sorts,
|
302
148
|
)
|
303
149
|
|
304
|
-
|
305
|
-
|
306
|
-
):
|
307
|
-
yield page_manager
|
150
|
+
start_cursor: Optional[str] = None
|
151
|
+
has_more = True
|
308
152
|
|
309
|
-
|
153
|
+
# Prepare the query body
|
154
|
+
body: Dict[str, Any] = {"page_size": page_size}
|
155
|
+
|
156
|
+
if filter_conditions:
|
157
|
+
body["filter"] = filter_conditions
|
158
|
+
|
159
|
+
if sorts:
|
160
|
+
body["sorts"] = sorts
|
161
|
+
|
162
|
+
while has_more:
|
163
|
+
current_body = body.copy()
|
164
|
+
if start_cursor:
|
165
|
+
current_body["start_cursor"] = start_cursor
|
166
|
+
|
167
|
+
result = await self._client.post(
|
168
|
+
f"databases/{self.database_id}/query", data=current_body
|
169
|
+
)
|
170
|
+
|
171
|
+
if not result or "results" not in result:
|
172
|
+
return
|
173
|
+
|
174
|
+
for page in result["results"]:
|
175
|
+
page_id: str = page.get("id", "")
|
176
|
+
title = self._extract_page_title(page)
|
177
|
+
|
178
|
+
page_url = f"https://notion.so/{page_id.replace('-', '')}"
|
179
|
+
|
180
|
+
notion_page_manager = NotionPageManager(page_id=page_id, title=title, url=page_url)
|
181
|
+
yield notion_page_manager
|
182
|
+
|
183
|
+
# Update pagination parameters
|
184
|
+
has_more = result.get("has_more", False)
|
185
|
+
start_cursor = result.get("next_cursor") if has_more else None
|
186
|
+
|
187
|
+
def _extract_page_title(self, page: Dict[str, Any]) -> str:
|
310
188
|
"""
|
311
|
-
|
189
|
+
Extracts the title from a Notion page object.
|
312
190
|
|
313
191
|
Args:
|
314
|
-
|
192
|
+
page: The Notion page object
|
315
193
|
|
316
194
|
Returns:
|
317
|
-
|
195
|
+
The extracted title as a string, or an empty string if no title found
|
318
196
|
"""
|
319
|
-
|
197
|
+
properties = page.get("properties", {})
|
198
|
+
if not properties:
|
199
|
+
return ""
|
320
200
|
|
321
|
-
|
201
|
+
for prop_value in properties.values():
|
202
|
+
if prop_value.get("type") != "title":
|
203
|
+
continue
|
204
|
+
|
205
|
+
title_array = prop_value.get("title", [])
|
206
|
+
if not title_array:
|
207
|
+
continue
|
322
208
|
|
323
|
-
|
209
|
+
return title_array[0].get("plain_text", "")
|
210
|
+
|
211
|
+
return ""
|
212
|
+
|
213
|
+
async def delete_page(self, page_id: str) -> Dict[str, Any]:
|
214
|
+
"""
|
215
|
+
Delete (archive) a page.
|
324
216
|
|
325
|
-
|
326
|
-
|
217
|
+
Args:
|
218
|
+
page_id: The ID of the page to delete
|
327
219
|
|
328
|
-
|
220
|
+
Returns:
|
221
|
+
Dict with success status, message, and page_id when successful
|
222
|
+
"""
|
223
|
+
try:
|
224
|
+
formatted_page_id = format_uuid(page_id) or page_id
|
225
|
+
|
226
|
+
# Archive the page (Notion's way of deleting)
|
227
|
+
data = {"archived": True}
|
228
|
+
|
229
|
+
result = await self._client.patch(f"pages/{formatted_page_id}", data)
|
230
|
+
if not result:
|
231
|
+
self.logger.error("Error deleting page %s", formatted_page_id)
|
232
|
+
return {
|
233
|
+
"success": False,
|
234
|
+
"message": f"Failed to delete page {formatted_page_id}",
|
235
|
+
}
|
236
|
+
|
237
|
+
self.logger.info("Page %s successfully deleted (archived)", formatted_page_id)
|
238
|
+
return {"success": True, "page_id": formatted_page_id}
|
239
|
+
|
240
|
+
except Exception as e:
|
241
|
+
self.logger.error("Error in delete_page: %s", str(e))
|
242
|
+
return {"success": False, "message": f"Error: {str(e)}"}
|
329
243
|
|
330
244
|
async def close(self) -> None:
|
331
245
|
"""Close the client connection."""
|
332
|
-
await self._client.close()
|
246
|
+
await self._client.close()
|
@@ -12,7 +12,7 @@ from notionary.exceptions.database_exceptions import (
|
|
12
12
|
NotionDatabaseException,
|
13
13
|
)
|
14
14
|
from notionary.util.logging_mixin import LoggingMixin
|
15
|
-
from notionary.util.
|
15
|
+
from notionary.util.page_id_utils import format_uuid
|
16
16
|
|
17
17
|
|
18
18
|
class NotionDatabaseFactory(LoggingMixin):
|
@@ -44,21 +44,11 @@ class NotionDatabaseFactory(LoggingMixin):
|
|
44
44
|
|
45
45
|
try:
|
46
46
|
formatted_id = format_uuid(database_id) or database_id
|
47
|
-
|
47
|
+
|
48
48
|
manager = NotionDatabaseManager(formatted_id, token)
|
49
|
+
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
if not success:
|
53
|
-
error_msg = (
|
54
|
-
f"Failed to initialize database manager for ID: {formatted_id}"
|
55
|
-
)
|
56
|
-
logger.error(error_msg)
|
57
|
-
raise DatabaseInitializationError(formatted_id, error_msg)
|
58
|
-
|
59
|
-
logger.info(
|
60
|
-
lambda: f"Successfully created database manager for ID: {formatted_id}"
|
61
|
-
)
|
51
|
+
logger.info("Successfully created database manager for ID: %s", formatted_id)
|
62
52
|
return manager
|
63
53
|
|
64
54
|
except DatabaseInitializationError:
|
@@ -88,7 +78,7 @@ class NotionDatabaseFactory(LoggingMixin):
|
|
88
78
|
An initialized NotionDatabaseManager instance
|
89
79
|
"""
|
90
80
|
logger = cls.class_logger()
|
91
|
-
logger.debug(
|
81
|
+
logger.debug("Searching for database with name: %s", database_name)
|
92
82
|
|
93
83
|
client = NotionClient(token=token)
|
94
84
|
|
@@ -116,11 +106,8 @@ class NotionDatabaseFactory(LoggingMixin):
|
|
116
106
|
logger.warning(error_msg)
|
117
107
|
raise DatabaseNotFoundException(database_name, error_msg)
|
118
108
|
|
119
|
-
logger.debug(
|
120
|
-
lambda: f"Found {len(databases)} databases, searching for best match"
|
121
|
-
)
|
109
|
+
logger.debug("Found %d databases, searching for best match", len(databases))
|
122
110
|
|
123
|
-
# Find best match using fuzzy matching
|
124
111
|
best_match = None
|
125
112
|
best_score = 0
|
126
113
|
|
@@ -135,7 +122,6 @@ class NotionDatabaseFactory(LoggingMixin):
|
|
135
122
|
best_score = score
|
136
123
|
best_match = db
|
137
124
|
|
138
|
-
# Use a minimum threshold for match quality (0.6 = 60% similarity)
|
139
125
|
if best_score < 0.6 or not best_match:
|
140
126
|
error_msg = f"No good database name match found for '{database_name}'. Best match had score {best_score:.2f}"
|
141
127
|
logger.warning(error_msg)
|
@@ -150,23 +136,11 @@ class NotionDatabaseFactory(LoggingMixin):
|
|
150
136
|
|
151
137
|
matched_name = cls._extract_title_from_database(best_match)
|
152
138
|
|
153
|
-
logger.info(
|
154
|
-
lambda: f"Found matching database: '{matched_name}' (ID: {database_id}) with score: {best_score:.2f}"
|
155
|
-
)
|
139
|
+
logger.info("Found matching database: '%s' (ID: %s) with score: %.2f", matched_name, database_id, best_score)
|
156
140
|
|
157
141
|
manager = NotionDatabaseManager(database_id, token)
|
158
|
-
success = await manager.initialize()
|
159
142
|
|
160
|
-
|
161
|
-
error_msg = (
|
162
|
-
f"Failed to initialize database manager for database {database_id}"
|
163
|
-
)
|
164
|
-
logger.error(error_msg)
|
165
|
-
raise DatabaseInitializationError(database_id, error_msg)
|
166
|
-
|
167
|
-
logger.info(
|
168
|
-
lambda: f"Successfully created database manager for '{matched_name}'"
|
169
|
-
)
|
143
|
+
logger.info(f"Successfully created database manager for '{matched_name}'")
|
170
144
|
await client.close()
|
171
145
|
return manager
|
172
146
|
|
@@ -183,22 +157,11 @@ class NotionDatabaseFactory(LoggingMixin):
|
|
183
157
|
def _extract_title_from_database(cls, database: Dict[str, Any]) -> str:
|
184
158
|
"""
|
185
159
|
Extract the title from a database object.
|
186
|
-
|
187
|
-
Args:
|
188
|
-
database: A database object from the Notion API
|
189
|
-
|
190
|
-
Returns:
|
191
|
-
The extracted title or "Untitled" if no title is found
|
192
|
-
|
193
|
-
Raises:
|
194
|
-
DatabaseParsingError: If there's an error parsing the database title
|
195
160
|
"""
|
196
161
|
try:
|
197
|
-
# Check for title in the root object
|
198
162
|
if "title" in database:
|
199
163
|
return cls._extract_text_from_rich_text(database["title"])
|
200
164
|
|
201
|
-
# Check for title in properties
|
202
165
|
if "properties" in database and "title" in database["properties"]:
|
203
166
|
title_prop = database["properties"]["title"]
|
204
167
|
if "title" in title_prop:
|
@@ -215,12 +178,6 @@ class NotionDatabaseFactory(LoggingMixin):
|
|
215
178
|
def _extract_text_from_rich_text(cls, rich_text: List[Dict[str, Any]]) -> str:
|
216
179
|
"""
|
217
180
|
Extract plain text from a rich text array.
|
218
|
-
|
219
|
-
Args:
|
220
|
-
rich_text: A list of rich text objects from Notion API
|
221
|
-
|
222
|
-
Returns:
|
223
|
-
The concatenated plain text content
|
224
181
|
"""
|
225
182
|
if not rich_text:
|
226
183
|
return ""
|
@@ -230,4 +187,4 @@ class NotionDatabaseFactory(LoggingMixin):
|
|
230
187
|
if "plain_text" in text_obj:
|
231
188
|
text_parts.append(text_obj["plain_text"])
|
232
189
|
|
233
|
-
return "".join(text_parts)
|
190
|
+
return "".join(text_parts)
|