notionary 0.1.29__py3-none-any.whl → 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- notionary/__init__.py +5 -5
- notionary/database/notion_database.py +50 -59
- notionary/database/notion_database_factory.py +16 -20
- notionary/elements/audio_element.py +1 -1
- notionary/elements/bookmark_element.py +1 -1
- notionary/elements/bulleted_list_element.py +2 -8
- notionary/elements/callout_element.py +1 -1
- notionary/elements/code_block_element.py +1 -1
- notionary/elements/divider_element.py +1 -1
- notionary/elements/embed_element.py +1 -1
- notionary/elements/heading_element.py +2 -8
- notionary/elements/image_element.py +1 -1
- notionary/elements/mention_element.py +1 -1
- notionary/elements/notion_block_element.py +1 -1
- notionary/elements/numbered_list_element.py +2 -7
- notionary/elements/paragraph_element.py +1 -1
- notionary/elements/qoute_element.py +1 -1
- notionary/elements/registry/{block_element_registry.py → block_registry.py} +70 -26
- notionary/elements/registry/{block_element_registry_builder.py → block_registry_builder.py} +48 -32
- notionary/elements/table_element.py +1 -1
- notionary/elements/text_inline_formatter.py +13 -9
- notionary/elements/todo_element.py +1 -1
- notionary/elements/toggle_element.py +1 -1
- notionary/elements/toggleable_heading_element.py +1 -1
- notionary/elements/video_element.py +1 -1
- notionary/models/notion_block_response.py +264 -0
- notionary/models/notion_database_response.py +63 -0
- notionary/models/notion_page_response.py +100 -0
- notionary/notion_client.py +38 -5
- notionary/page/content/page_content_retriever.py +68 -0
- notionary/page/content/page_content_writer.py +103 -0
- notionary/page/markdown_to_notion_converter.py +5 -5
- notionary/page/metadata/metadata_editor.py +91 -63
- notionary/page/metadata/notion_icon_manager.py +55 -28
- notionary/page/metadata/notion_page_cover_manager.py +23 -20
- notionary/page/notion_page.py +223 -218
- notionary/page/notion_page_factory.py +102 -151
- notionary/page/notion_to_markdown_converter.py +5 -5
- notionary/page/properites/database_property_service.py +11 -55
- notionary/page/properites/page_property_manager.py +44 -67
- notionary/page/properites/property_value_extractor.py +3 -3
- notionary/page/relations/notion_page_relation_manager.py +165 -213
- notionary/page/relations/notion_page_title_resolver.py +59 -41
- notionary/page/relations/page_database_relation.py +7 -9
- notionary/{elements/prompts → prompting}/element_prompt_content.py +19 -4
- notionary/prompting/markdown_syntax_prompt_generator.py +92 -0
- notionary/util/logging_mixin.py +17 -8
- notionary/util/warn_direct_constructor_usage.py +54 -0
- {notionary-0.1.29.dist-info → notionary-0.2.1.dist-info}/METADATA +2 -1
- notionary-0.2.1.dist-info/RECORD +60 -0
- {notionary-0.1.29.dist-info → notionary-0.2.1.dist-info}/WHEEL +1 -1
- notionary/database/database_info_service.py +0 -43
- notionary/elements/prompts/synthax_prompt_builder.py +0 -150
- notionary/page/content/page_content_manager.py +0 -211
- notionary/page/properites/property_operation_result.py +0 -116
- notionary/page/relations/relation_operation_result.py +0 -144
- notionary-0.1.29.dist-info/RECORD +0 -58
- {notionary-0.1.29.dist-info → notionary-0.2.1.dist-info}/licenses/LICENSE +0 -0
- {notionary-0.1.29.dist-info → notionary-0.2.1.dist-info}/top_level.txt +0 -0
@@ -1,16 +1,14 @@
|
|
1
|
+
import asyncio
|
1
2
|
from typing import Any, Dict, List, Optional
|
3
|
+
from notionary.models.notion_page_response import DatabaseParent, NotionPageResponse
|
2
4
|
from notionary.notion_client import NotionClient
|
3
5
|
from notionary.page.relations.notion_page_title_resolver import (
|
4
6
|
NotionPageTitleResolver,
|
5
7
|
)
|
6
|
-
from notionary.page.relations.relation_operation_result import (
|
7
|
-
RelationOperationResult,
|
8
|
-
)
|
9
8
|
from notionary.util.logging_mixin import LoggingMixin
|
10
|
-
from notionary.util.page_id_utils import is_valid_uuid
|
11
9
|
|
12
10
|
|
13
|
-
class
|
11
|
+
class NotionPageRelationManager(LoggingMixin):
|
14
12
|
"""
|
15
13
|
Manager for relation properties of a Notion page.
|
16
14
|
Manages links between pages and loads available relation options.
|
@@ -21,11 +19,6 @@ class NotionRelationManager(LoggingMixin):
|
|
21
19
|
):
|
22
20
|
"""
|
23
21
|
Initializes the relation manager.
|
24
|
-
|
25
|
-
Args:
|
26
|
-
page_id: ID of the Notion page
|
27
|
-
client: NotionClient instance
|
28
|
-
database_id: Optional, ID of the database the page belongs to (loaded if needed)
|
29
22
|
"""
|
30
23
|
self._page_id = page_id
|
31
24
|
self._client = client
|
@@ -34,44 +27,6 @@ class NotionRelationManager(LoggingMixin):
|
|
34
27
|
|
35
28
|
self._page_title_resolver = NotionPageTitleResolver(client=client)
|
36
29
|
|
37
|
-
async def _get_page_properties(self, force_refresh: bool = False) -> Dict[str, Any]:
|
38
|
-
"""
|
39
|
-
Loads the properties of the page.
|
40
|
-
|
41
|
-
Args:
|
42
|
-
force_refresh: If True, a fresh API call will be made
|
43
|
-
|
44
|
-
Returns:
|
45
|
-
Dict[str, Any]: The properties of the page
|
46
|
-
"""
|
47
|
-
if self._page_properties is None or force_refresh:
|
48
|
-
page_data = await self._client.get_page(self._page_id)
|
49
|
-
if page_data and "properties" in page_data:
|
50
|
-
self._page_properties = page_data["properties"]
|
51
|
-
else:
|
52
|
-
self._page_properties = {}
|
53
|
-
|
54
|
-
return self._page_properties
|
55
|
-
|
56
|
-
async def _ensure_database_id(self) -> Optional[str]:
|
57
|
-
"""
|
58
|
-
Ensures the database_id is available. Loads it if necessary.
|
59
|
-
|
60
|
-
Returns:
|
61
|
-
Optional[str]: The database ID or None
|
62
|
-
"""
|
63
|
-
if self._database_id:
|
64
|
-
return self._database_id
|
65
|
-
|
66
|
-
page_data = await self._client.get_page(self._page_id)
|
67
|
-
if page_data and "parent" in page_data:
|
68
|
-
parent = page_data["parent"]
|
69
|
-
if parent.get("type") == "database_id":
|
70
|
-
self._database_id = parent.get("database_id")
|
71
|
-
return self._database_id
|
72
|
-
|
73
|
-
return None
|
74
|
-
|
75
30
|
async def get_relation_property_ids(self) -> List[str]:
|
76
31
|
"""
|
77
32
|
Returns a list of all relation property names.
|
@@ -123,43 +78,6 @@ class NotionRelationManager(LoggingMixin):
|
|
123
78
|
|
124
79
|
return titles
|
125
80
|
|
126
|
-
async def get_relation_details(
|
127
|
-
self, property_name: str
|
128
|
-
) -> Optional[Dict[str, Any]]:
|
129
|
-
"""
|
130
|
-
Returns details about the relation property, including the linked database.
|
131
|
-
|
132
|
-
Args:
|
133
|
-
property_name: Name of the relation property
|
134
|
-
|
135
|
-
Returns:
|
136
|
-
Optional[Dict[str, Any]]: Relation details or None
|
137
|
-
"""
|
138
|
-
database_id = await self._ensure_database_id()
|
139
|
-
if not database_id:
|
140
|
-
return None
|
141
|
-
|
142
|
-
try:
|
143
|
-
database = await self._client.get(f"databases/{database_id}")
|
144
|
-
if not database or "properties" not in database:
|
145
|
-
return None
|
146
|
-
|
147
|
-
properties = database["properties"]
|
148
|
-
|
149
|
-
if property_name not in properties:
|
150
|
-
return None
|
151
|
-
|
152
|
-
prop_data = properties[property_name]
|
153
|
-
|
154
|
-
if prop_data.get("type") != "relation":
|
155
|
-
return None
|
156
|
-
|
157
|
-
return prop_data.get("relation", {})
|
158
|
-
|
159
|
-
except Exception as e:
|
160
|
-
self.logger.error("Error retrieving relation details: %s", str(e))
|
161
|
-
return None
|
162
|
-
|
163
81
|
async def get_relation_database_id(self, property_name: str) -> Optional[str]:
|
164
82
|
"""
|
165
83
|
Returns the ID of the linked database for a relation property.
|
@@ -170,7 +88,7 @@ class NotionRelationManager(LoggingMixin):
|
|
170
88
|
Returns:
|
171
89
|
Optional[str]: ID of the linked database or None
|
172
90
|
"""
|
173
|
-
relation_details = await self.
|
91
|
+
relation_details = await self._get_relation_details(property_name)
|
174
92
|
|
175
93
|
if not relation_details:
|
176
94
|
return None
|
@@ -179,16 +97,16 @@ class NotionRelationManager(LoggingMixin):
|
|
179
97
|
|
180
98
|
async def get_relation_options(
|
181
99
|
self, property_name: str, limit: int = 100
|
182
|
-
) -> List[
|
100
|
+
) -> List[str]:
|
183
101
|
"""
|
184
|
-
Returns available options for a relation property.
|
102
|
+
Returns available title options for a relation property.
|
185
103
|
|
186
104
|
Args:
|
187
105
|
property_name: Name of the relation property
|
188
106
|
limit: Maximum number of options to return
|
189
107
|
|
190
108
|
Returns:
|
191
|
-
List[
|
109
|
+
List[str]: List of page titles that can be used for this relation
|
192
110
|
"""
|
193
111
|
related_db_id = await self.get_relation_database_id(property_name)
|
194
112
|
|
@@ -206,193 +124,227 @@ class NotionRelationManager(LoggingMixin):
|
|
206
124
|
if not query_result or "results" not in query_result:
|
207
125
|
return []
|
208
126
|
|
209
|
-
|
127
|
+
titles = []
|
210
128
|
for page in query_result["results"]:
|
211
|
-
page_id = page.get("id")
|
212
129
|
title = self._extract_title_from_page(page)
|
130
|
+
if title:
|
131
|
+
titles.append(title)
|
213
132
|
|
214
|
-
|
215
|
-
options.append({"id": page_id, "name": title})
|
216
|
-
|
217
|
-
return options
|
133
|
+
return titles
|
218
134
|
except Exception as e:
|
219
135
|
self.logger.error("Error retrieving relation options: %s", str(e))
|
220
136
|
return []
|
221
137
|
|
222
|
-
def
|
138
|
+
async def set_relation_values_by_page_titles(
|
139
|
+
self, property_name: str, page_titles: List[str]
|
140
|
+
) -> List[str]:
|
223
141
|
"""
|
224
|
-
|
142
|
+
Sets relation values based on page titles, replacing any existing relations.
|
225
143
|
|
226
144
|
Args:
|
227
|
-
|
145
|
+
property_name: Name of the relation property
|
146
|
+
page_titles: List of page titles to set as relations
|
228
147
|
|
229
148
|
Returns:
|
230
|
-
|
149
|
+
List[str]: List of page titles that were successfully set as relations
|
231
150
|
"""
|
232
|
-
|
233
|
-
|
151
|
+
self.logger.info(
|
152
|
+
"Setting %d relation(s) for property '%s'",
|
153
|
+
len(page_titles),
|
154
|
+
property_name,
|
155
|
+
)
|
234
156
|
|
235
|
-
|
157
|
+
resolution_results = await asyncio.gather(
|
158
|
+
*(
|
159
|
+
self._page_title_resolver.get_page_id_by_title(title)
|
160
|
+
for title in page_titles
|
161
|
+
)
|
162
|
+
)
|
236
163
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
return "".join(
|
241
|
-
[text_obj.get("plain_text", "") for text_obj in title_parts]
|
242
|
-
)
|
164
|
+
found_pages = []
|
165
|
+
page_ids = []
|
166
|
+
not_found_pages = []
|
243
167
|
|
244
|
-
|
168
|
+
for title, page_id in zip(page_titles, resolution_results):
|
169
|
+
if page_id:
|
170
|
+
found_pages.append(title)
|
171
|
+
page_ids.append(page_id)
|
172
|
+
self.logger.debug("Found page ID %s for title '%s'", page_id, title)
|
173
|
+
else:
|
174
|
+
not_found_pages.append(title)
|
175
|
+
self.logger.warning("No page found with title '%s'", title)
|
245
176
|
|
246
|
-
|
247
|
-
|
177
|
+
self.logger.debug("Page IDs being sent to API: %s", page_ids)
|
178
|
+
|
179
|
+
if not page_ids:
|
180
|
+
self.logger.warning(
|
181
|
+
"No valid page IDs found for any of the titles, no changes applied"
|
182
|
+
)
|
183
|
+
return []
|
184
|
+
|
185
|
+
api_response = await self._set_relations_by_page_ids(property_name, page_ids)
|
186
|
+
|
187
|
+
if not api_response:
|
188
|
+
self.logger.error(
|
189
|
+
"Failed to set relations for '%s' (API error)", property_name
|
190
|
+
)
|
191
|
+
return []
|
192
|
+
|
193
|
+
if not_found_pages:
|
194
|
+
not_found_str = "', '".join(not_found_pages)
|
195
|
+
self.logger.info(
|
196
|
+
"Set %d relation(s) for '%s', but couldn't find pages: '%s'",
|
197
|
+
len(page_ids),
|
198
|
+
property_name,
|
199
|
+
not_found_str,
|
200
|
+
)
|
201
|
+
else:
|
202
|
+
self.logger.info(
|
203
|
+
"Successfully set all %d relation(s) for '%s'",
|
204
|
+
len(page_ids),
|
205
|
+
property_name,
|
206
|
+
)
|
207
|
+
|
208
|
+
return found_pages
|
209
|
+
|
210
|
+
async def get_all_relations(self) -> Dict[str, List[str]]:
|
211
|
+
"""
|
212
|
+
Returns all relation properties and their values.
|
213
|
+
|
214
|
+
Returns:
|
215
|
+
Dict[str, List[str]]: Dictionary of property names and their values
|
216
|
+
"""
|
217
|
+
relation_properties = await self.get_relation_property_ids()
|
218
|
+
|
219
|
+
if not relation_properties:
|
220
|
+
return {}
|
221
|
+
|
222
|
+
result = {}
|
223
|
+
for prop_name in relation_properties:
|
224
|
+
result[prop_name] = await self.get_relation_values(prop_name)
|
225
|
+
|
226
|
+
return result
|
227
|
+
|
228
|
+
async def _get_relation_details(
|
229
|
+
self, property_name: str
|
248
230
|
) -> Optional[Dict[str, Any]]:
|
249
231
|
"""
|
250
|
-
|
232
|
+
Returns details about the relation property, including the linked database.
|
251
233
|
|
252
234
|
Args:
|
253
235
|
property_name: Name of the relation property
|
254
|
-
page_ids: List of page IDs to add
|
255
236
|
|
256
237
|
Returns:
|
257
|
-
|
238
|
+
The "relation" field of the property, or None if not found or not of type "relation".
|
258
239
|
"""
|
259
|
-
|
240
|
+
database_id = await self._ensure_database_id()
|
241
|
+
if not database_id:
|
242
|
+
return None
|
260
243
|
|
261
|
-
|
244
|
+
try:
|
245
|
+
database = await self._client.get_database(database_id)
|
262
246
|
|
263
|
-
|
247
|
+
prop_data = database.properties.get(property_name)
|
248
|
+
if not prop_data:
|
249
|
+
return None
|
264
250
|
|
265
|
-
|
266
|
-
|
267
|
-
f"pages/{self._page_id}",
|
268
|
-
{"properties": {property_name: relation_payload}},
|
269
|
-
)
|
251
|
+
if prop_data.get("type") != "relation":
|
252
|
+
return None
|
270
253
|
|
271
|
-
|
254
|
+
return prop_data.get("relation")
|
272
255
|
|
273
|
-
return result
|
274
256
|
except Exception as e:
|
275
|
-
self.logger.error("Error
|
257
|
+
self.logger.error("Error retrieving relation details: %s", str(e))
|
276
258
|
return None
|
277
259
|
|
278
|
-
async def
|
279
|
-
self, property_name: str, page_titles: List[str]
|
280
|
-
) -> RelationOperationResult:
|
260
|
+
async def _get_page_properties(self, force_refresh: bool = False) -> Dict[str, Any]:
|
281
261
|
"""
|
282
|
-
|
262
|
+
Loads the properties of the page.
|
283
263
|
|
284
264
|
Args:
|
285
|
-
|
286
|
-
page_titles: List of page titles to link
|
265
|
+
force_refresh: If True, a new API call will be made.
|
287
266
|
|
288
267
|
Returns:
|
289
|
-
|
268
|
+
Dict[str, Any]: The properties of the page.
|
290
269
|
"""
|
291
|
-
|
292
|
-
|
293
|
-
|
270
|
+
if self._page_properties is None or force_refresh:
|
271
|
+
page_data = await self._client.get_page(self._page_id)
|
272
|
+
if page_data:
|
273
|
+
self._page_properties = page_data.properties or {}
|
274
|
+
else:
|
275
|
+
self._page_properties = {}
|
294
276
|
|
295
|
-
self.
|
296
|
-
"Attempting to add %d relation(s) to property '%s'",
|
297
|
-
len(page_titles),
|
298
|
-
property_name,
|
299
|
-
)
|
277
|
+
return self._page_properties
|
300
278
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
found_pages.append(page)
|
305
|
-
self.logger.debug("Using page ID directly: %s", page)
|
306
|
-
else:
|
307
|
-
page_id = await self._page_title_resolver.get_page_id_by_title(page)
|
308
|
-
if page_id:
|
309
|
-
page_ids.append(page_id)
|
310
|
-
found_pages.append(page)
|
311
|
-
self.logger.debug("Found page ID %s for title '%s'", page_id, page)
|
312
|
-
else:
|
313
|
-
not_found_pages.append(page)
|
314
|
-
self.logger.warning("No page found with title '%s'", page)
|
279
|
+
async def _ensure_database_id(self) -> Optional[str]:
|
280
|
+
"""
|
281
|
+
Ensures the database_id is available. Loads it if necessary.
|
315
282
|
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
return
|
321
|
-
property_name, not_found_pages
|
322
|
-
)
|
283
|
+
Returns:
|
284
|
+
Optional[str]: The database ID or None
|
285
|
+
"""
|
286
|
+
if self._database_id:
|
287
|
+
return self._database_id
|
323
288
|
|
324
|
-
|
289
|
+
page_data = await self._client.get_page(self._page_id)
|
325
290
|
|
326
|
-
if
|
327
|
-
|
328
|
-
property_name=property_name,
|
329
|
-
found_pages=found_pages,
|
330
|
-
not_found_pages=not_found_pages,
|
331
|
-
page_ids_added=page_ids,
|
332
|
-
api_response=api_response,
|
333
|
-
)
|
291
|
+
if not page_data or not page_data.parent:
|
292
|
+
return None
|
334
293
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
"Added %d relation(s) to '%s', but couldn't find pages: '%s'",
|
339
|
-
len(page_ids),
|
340
|
-
property_name,
|
341
|
-
not_found_str,
|
342
|
-
)
|
343
|
-
else:
|
344
|
-
self.logger.info(
|
345
|
-
"Successfully added all %d relation(s) to '%s'",
|
346
|
-
len(page_ids),
|
347
|
-
property_name,
|
348
|
-
)
|
294
|
+
if isinstance(page_data.parent, DatabaseParent):
|
295
|
+
self._database_id = page_data.parent.database_id
|
296
|
+
return self._database_id
|
349
297
|
|
350
|
-
|
298
|
+
return None
|
351
299
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
found_pages=found_pages,
|
356
|
-
page_ids_added=page_ids,
|
357
|
-
)
|
300
|
+
def _extract_title_from_page(self, page: Dict[str, Any]) -> Optional[str]:
|
301
|
+
"""
|
302
|
+
Extracts the title from a page object.
|
358
303
|
|
359
|
-
|
304
|
+
Args:
|
305
|
+
page: The page object from the Notion API
|
306
|
+
|
307
|
+
Returns:
|
308
|
+
Optional[str]: The page title or None
|
309
|
+
"""
|
310
|
+
if "properties" not in page:
|
311
|
+
return None
|
312
|
+
|
313
|
+
properties = page["properties"]
|
314
|
+
|
315
|
+
for prop_data in properties.values():
|
316
|
+
if prop_data.get("type") == "title" and "title" in prop_data:
|
317
|
+
title_parts = prop_data["title"]
|
318
|
+
return "".join(
|
319
|
+
[text_obj.get("plain_text", "") for text_obj in title_parts]
|
320
|
+
)
|
321
|
+
|
322
|
+
return None
|
323
|
+
|
324
|
+
async def _set_relations_by_page_ids(
|
360
325
|
self, property_name: str, page_ids: List[str]
|
361
|
-
) -> Optional[
|
326
|
+
) -> Optional[NotionPageResponse]:
|
362
327
|
"""
|
363
|
-
|
328
|
+
Adds one or more relations.
|
364
329
|
|
365
330
|
Args:
|
366
331
|
property_name: Name of the relation property
|
367
|
-
page_ids: List of page IDs to
|
332
|
+
page_ids: List of page IDs to add
|
368
333
|
|
369
334
|
Returns:
|
370
|
-
Optional[
|
335
|
+
Optional[NotionPageResponse]: API response or None on error
|
371
336
|
"""
|
372
337
|
relation_payload = {"relation": [{"id": page_id} for page_id in page_ids]}
|
373
338
|
|
374
339
|
try:
|
375
|
-
|
376
|
-
|
340
|
+
page_response: NotionPageResponse = await self._client.patch_page(
|
341
|
+
self._page_id,
|
377
342
|
{"properties": {property_name: relation_payload}},
|
378
343
|
)
|
379
344
|
|
380
345
|
self._page_properties = None
|
381
346
|
|
382
|
-
return
|
347
|
+
return page_response
|
383
348
|
except Exception as e:
|
384
|
-
self.logger.error("Error
|
349
|
+
self.logger.error("Error adding relation: %s", str(e))
|
385
350
|
return None
|
386
|
-
|
387
|
-
async def get_all_relations(self) -> Dict[str, List[str]]:
|
388
|
-
"""Returns all relation properties and their values."""
|
389
|
-
relation_properties = await self.get_relation_property_ids()
|
390
|
-
|
391
|
-
if not relation_properties:
|
392
|
-
return {}
|
393
|
-
|
394
|
-
result = {}
|
395
|
-
for prop_name in relation_properties:
|
396
|
-
result[prop_name] = await self.get_relation_values(prop_name)
|
397
|
-
|
398
|
-
return result
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Optional
|
1
|
+
from typing import Optional, Dict, Any, List
|
2
2
|
from notionary.notion_client import NotionClient
|
3
3
|
from notionary.util.logging_mixin import LoggingMixin
|
4
4
|
|
@@ -17,39 +17,25 @@ class NotionPageTitleResolver(LoggingMixin):
|
|
17
17
|
{"query": title, "filter": {"value": "page", "property": "object"}},
|
18
18
|
)
|
19
19
|
|
20
|
-
|
21
|
-
properties = result.get("properties", {})
|
22
|
-
if not properties:
|
23
|
-
continue
|
24
|
-
|
25
|
-
for prop_value in properties.values():
|
26
|
-
if prop_value.get("type") != "title":
|
27
|
-
continue
|
28
|
-
|
29
|
-
title_texts = prop_value.get("title", [])
|
30
|
-
if not title_texts:
|
31
|
-
continue
|
20
|
+
results = search_results.get("results", [])
|
32
21
|
|
33
|
-
|
34
|
-
|
35
|
-
|
22
|
+
if not results:
|
23
|
+
self.logger.debug(f"No page found with title '{title}'")
|
24
|
+
return None
|
36
25
|
|
37
|
-
|
38
|
-
|
26
|
+
# Durchsuche die Ergebnisse nach dem passenden Titel
|
27
|
+
for result in results:
|
28
|
+
properties = result.get("properties", {})
|
29
|
+
page_title = self._extract_page_title_from_properties(properties)
|
39
30
|
|
40
|
-
|
41
|
-
|
42
|
-
"Found page: '%s' with ID: %s",
|
43
|
-
page_title,
|
44
|
-
result.get("id"),
|
45
|
-
)
|
46
|
-
return result.get("id")
|
31
|
+
if page_title == title:
|
32
|
+
return result.get("id")
|
47
33
|
|
48
|
-
self.logger.debug("No page found with title '
|
34
|
+
self.logger.debug(f"No matching page found with title '{title}'")
|
49
35
|
return None
|
50
36
|
|
51
37
|
except Exception as e:
|
52
|
-
self.logger.error("Error while searching for page '
|
38
|
+
self.logger.error(f"Error while searching for page '{title}': {e}")
|
53
39
|
return None
|
54
40
|
|
55
41
|
async def get_title_by_page_id(self, page_id: str) -> Optional[str]:
|
@@ -63,24 +49,56 @@ class NotionPageTitleResolver(LoggingMixin):
|
|
63
49
|
The title of the page, or None if not found.
|
64
50
|
"""
|
65
51
|
try:
|
66
|
-
page = await self._client.
|
67
|
-
|
52
|
+
page = await self._client.get_page(page_id)
|
53
|
+
return self._extract_page_title_from_properties(page.properties)
|
68
54
|
|
69
|
-
|
70
|
-
|
71
|
-
|
55
|
+
except Exception as e:
|
56
|
+
self.logger.error(f"Error retrieving title for page ID '{page_id}': {e}")
|
57
|
+
return None
|
58
|
+
|
59
|
+
async def get_page_titles_by_ids(self, page_ids: List[str]) -> Dict[str, str]:
|
60
|
+
"""
|
61
|
+
Retrieves titles for multiple page IDs at once.
|
62
|
+
|
63
|
+
Args:
|
64
|
+
page_ids: List of page IDs to get titles for
|
65
|
+
|
66
|
+
Returns:
|
67
|
+
Dictionary mapping page IDs to their titles
|
68
|
+
"""
|
69
|
+
result = {}
|
70
|
+
for page_id in page_ids:
|
71
|
+
title = await self.get_title_by_page_id(page_id)
|
72
|
+
if title:
|
73
|
+
result[page_id] = title
|
74
|
+
return result
|
75
|
+
|
76
|
+
def _extract_page_title_from_properties(self, properties: Dict[str, Any]) -> str:
|
77
|
+
"""
|
78
|
+
Extract title from properties dictionary.
|
72
79
|
|
73
|
-
|
74
|
-
|
80
|
+
Args:
|
81
|
+
properties: The properties dictionary from a Notion page
|
82
|
+
|
83
|
+
Returns:
|
84
|
+
str: The extracted title or "Untitled" if not found
|
85
|
+
"""
|
86
|
+
try:
|
87
|
+
for prop_value in properties.values():
|
88
|
+
if not isinstance(prop_value, dict):
|
75
89
|
continue
|
76
90
|
|
77
|
-
|
78
|
-
|
79
|
-
return title
|
91
|
+
if prop_value.get("type") != "title":
|
92
|
+
continue
|
80
93
|
|
81
|
-
|
82
|
-
|
94
|
+
title_array = prop_value.get("title", [])
|
95
|
+
if not title_array:
|
96
|
+
continue
|
83
97
|
|
98
|
+
for text_obj in title_array:
|
99
|
+
if "plain_text" in text_obj:
|
100
|
+
return text_obj["plain_text"]
|
84
101
|
except Exception as e:
|
85
|
-
self.logger.error("Error
|
86
|
-
|
102
|
+
self.logger.error(f"Error extracting page title from properties: {e}")
|
103
|
+
|
104
|
+
return "Untitled"
|
@@ -1,4 +1,5 @@
|
|
1
1
|
from typing import Dict, Optional, Any
|
2
|
+
from notionary.models.notion_page_response import DatabaseParent, NotionPageResponse
|
2
3
|
from notionary.notion_client import NotionClient
|
3
4
|
from notionary.util.logging_mixin import LoggingMixin
|
4
5
|
|
@@ -23,7 +24,7 @@ class PageDatabaseRelation(LoggingMixin):
|
|
23
24
|
self._database_schema = None
|
24
25
|
self._page_data = None
|
25
26
|
|
26
|
-
async def _get_page_data(self, force_refresh=False) ->
|
27
|
+
async def _get_page_data(self, force_refresh=False) -> NotionPageResponse:
|
27
28
|
"""
|
28
29
|
Gets the page data and caches it for future use.
|
29
30
|
|
@@ -39,22 +40,19 @@ class PageDatabaseRelation(LoggingMixin):
|
|
39
40
|
|
40
41
|
async def get_parent_database_id(self) -> Optional[str]:
|
41
42
|
"""
|
42
|
-
|
43
|
-
|
44
|
-
Returns:
|
45
|
-
Optional[str]: The database ID or None if the page doesn't belong to a database
|
43
|
+
Returns the ID of the database this page belongs to, if any.
|
46
44
|
"""
|
47
45
|
if self._parent_database_id is not None:
|
48
46
|
return self._parent_database_id
|
49
47
|
|
50
48
|
page_data = await self._get_page_data()
|
51
49
|
|
52
|
-
if not page_data
|
50
|
+
if not page_data:
|
53
51
|
return None
|
54
52
|
|
55
|
-
parent = page_data.
|
56
|
-
if parent
|
57
|
-
self._parent_database_id = parent.
|
53
|
+
parent = page_data.parent
|
54
|
+
if isinstance(parent, DatabaseParent):
|
55
|
+
self._parent_database_id = parent.database_id
|
58
56
|
return self._parent_database_id
|
59
57
|
|
60
58
|
return None
|