notionary 0.1.10__py3-none-any.whl → 0.1.12__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 +13 -2
- notionary/core/converters/elements/audio_element.py +143 -0
- notionary/core/converters/elements/embed_element.py +2 -4
- notionary/core/converters/elements/toggle_element.py +28 -20
- notionary/core/converters/markdown_to_notion_converter.py +70 -109
- notionary/core/converters/registry/block_element_registry.py +2 -6
- notionary/core/converters/registry/block_element_registry_builder.py +2 -0
- notionary/core/database/database_discovery.py +140 -0
- notionary/core/database/notion_database_manager.py +26 -49
- notionary/core/database/notion_database_manager_factory.py +10 -4
- notionary/core/notion_client.py +4 -2
- notionary/core/page/content/notion_page_content_chunker.py +84 -0
- notionary/core/page/content/page_content_manager.py +26 -8
- notionary/core/page/metadata/metadata_editor.py +57 -44
- notionary/core/page/metadata/notion_icon_manager.py +9 -11
- notionary/core/page/metadata/notion_page_cover_manager.py +15 -20
- notionary/core/page/notion_page_manager.py +137 -156
- notionary/core/page/properites/database_property_service.py +114 -98
- notionary/core/page/properites/page_property_manager.py +78 -49
- notionary/core/page/properites/property_formatter.py +1 -1
- notionary/core/page/properites/property_operation_result.py +43 -30
- notionary/core/page/properites/property_value_extractor.py +26 -8
- notionary/core/page/relations/notion_page_relation_manager.py +71 -52
- notionary/core/page/relations/notion_page_title_resolver.py +11 -11
- notionary/core/page/relations/page_database_relation.py +14 -14
- notionary/core/page/relations/relation_operation_result.py +50 -41
- notionary/util/page_id_utils.py +11 -7
- {notionary-0.1.10.dist-info → notionary-0.1.12.dist-info}/METADATA +1 -1
- {notionary-0.1.10.dist-info → notionary-0.1.12.dist-info}/RECORD +32 -30
- notionary/core/database/notion_database_schema.py +0 -104
- {notionary-0.1.10.dist-info → notionary-0.1.12.dist-info}/WHEEL +0 -0
- {notionary-0.1.10.dist-info → notionary-0.1.12.dist-info}/licenses/LICENSE +0 -0
- {notionary-0.1.10.dist-info → notionary-0.1.12.dist-info}/top_level.txt +0 -0
@@ -12,7 +12,7 @@ class DatabasePropertyService(LoggingMixin):
|
|
12
12
|
def __init__(self, database_id: str, client: NotionClient):
|
13
13
|
"""
|
14
14
|
Initialize the database property service.
|
15
|
-
|
15
|
+
|
16
16
|
Args:
|
17
17
|
database_id: ID of the Notion database
|
18
18
|
client: Instance of NotionClient
|
@@ -20,20 +20,20 @@ class DatabasePropertyService(LoggingMixin):
|
|
20
20
|
self._database_id = database_id
|
21
21
|
self._client = client
|
22
22
|
self._schema = None
|
23
|
-
|
23
|
+
|
24
24
|
async def load_schema(self, force_refresh=False) -> bool:
|
25
25
|
"""
|
26
26
|
Loads the database schema.
|
27
|
-
|
27
|
+
|
28
28
|
Args:
|
29
29
|
force_refresh: Whether to force a refresh of the schema
|
30
|
-
|
30
|
+
|
31
31
|
Returns:
|
32
32
|
bool: True if schema loaded successfully, False otherwise
|
33
33
|
"""
|
34
34
|
if self._schema is not None and not force_refresh:
|
35
35
|
return True
|
36
|
-
|
36
|
+
|
37
37
|
try:
|
38
38
|
database = await self._client.get(f"databases/{self._database_id}")
|
39
39
|
if database and "properties" in database:
|
@@ -41,290 +41,306 @@ class DatabasePropertyService(LoggingMixin):
|
|
41
41
|
self.logger.debug("Loaded schema for database %s", self._database_id)
|
42
42
|
return True
|
43
43
|
else:
|
44
|
-
self.logger.error(
|
44
|
+
self.logger.error(
|
45
|
+
"Failed to load schema: missing 'properties' in response"
|
46
|
+
)
|
45
47
|
return False
|
46
48
|
except Exception as e:
|
47
49
|
self.logger.error("Error loading database schema: %s", str(e))
|
48
50
|
return False
|
49
|
-
|
51
|
+
|
50
52
|
async def _ensure_schema_loaded(self) -> None:
|
51
53
|
"""
|
52
54
|
Ensures the schema is loaded before accessing it.
|
53
55
|
"""
|
54
56
|
if self._schema is None:
|
55
57
|
await self.load_schema()
|
56
|
-
|
58
|
+
|
57
59
|
async def get_schema(self) -> Dict[str, Any]:
|
58
60
|
"""
|
59
61
|
Gets the database schema.
|
60
|
-
|
62
|
+
|
61
63
|
Returns:
|
62
64
|
Dict[str, Any]: The database schema
|
63
65
|
"""
|
64
66
|
await self._ensure_schema_loaded()
|
65
67
|
return self._schema or {}
|
66
|
-
|
68
|
+
|
67
69
|
async def get_property_types(self) -> Dict[str, str]:
|
68
70
|
"""
|
69
71
|
Gets all property types for the database.
|
70
|
-
|
72
|
+
|
71
73
|
Returns:
|
72
74
|
Dict[str, str]: Dictionary mapping property names to their types
|
73
75
|
"""
|
74
76
|
await self._ensure_schema_loaded()
|
75
|
-
|
77
|
+
|
76
78
|
if not self._schema:
|
77
79
|
return {}
|
78
|
-
|
80
|
+
|
79
81
|
return {
|
80
82
|
prop_name: prop_data.get("type", "unknown")
|
81
83
|
for prop_name, prop_data in self._schema.items()
|
82
84
|
}
|
83
|
-
|
85
|
+
|
84
86
|
async def get_property_schema(self, property_name: str) -> Optional[Dict[str, Any]]:
|
85
87
|
"""
|
86
88
|
Gets the schema for a specific property.
|
87
|
-
|
89
|
+
|
88
90
|
Args:
|
89
91
|
property_name: The name of the property
|
90
|
-
|
92
|
+
|
91
93
|
Returns:
|
92
94
|
Optional[Dict[str, Any]]: The property schema or None if not found
|
93
95
|
"""
|
94
96
|
await self._ensure_schema_loaded()
|
95
|
-
|
97
|
+
|
96
98
|
if not self._schema or property_name not in self._schema:
|
97
99
|
return None
|
98
|
-
|
100
|
+
|
99
101
|
return self._schema[property_name]
|
100
|
-
|
102
|
+
|
101
103
|
async def get_property_type(self, property_name: str) -> Optional[str]:
|
102
104
|
"""
|
103
105
|
Gets the type of a specific property.
|
104
|
-
|
106
|
+
|
105
107
|
Args:
|
106
108
|
property_name: The name of the property
|
107
|
-
|
109
|
+
|
108
110
|
Returns:
|
109
111
|
Optional[str]: The property type or None if not found
|
110
112
|
"""
|
111
113
|
property_schema = await self.get_property_schema(property_name)
|
112
|
-
|
114
|
+
|
113
115
|
if not property_schema:
|
114
116
|
return None
|
115
|
-
|
117
|
+
|
116
118
|
return property_schema.get("type")
|
117
|
-
|
119
|
+
|
118
120
|
async def property_exists(self, property_name: str) -> bool:
|
119
121
|
"""
|
120
122
|
Checks if a property exists in the database.
|
121
|
-
|
123
|
+
|
122
124
|
Args:
|
123
125
|
property_name: The name of the property
|
124
|
-
|
126
|
+
|
125
127
|
Returns:
|
126
128
|
bool: True if the property exists, False otherwise
|
127
129
|
"""
|
128
130
|
property_schema = await self.get_property_schema(property_name)
|
129
131
|
return property_schema is not None
|
130
|
-
|
132
|
+
|
131
133
|
async def get_property_options(self, property_name: str) -> List[Dict[str, Any]]:
|
132
134
|
"""
|
133
135
|
Gets the available options for a property (select, multi_select, status).
|
134
|
-
|
136
|
+
|
135
137
|
Args:
|
136
138
|
property_name: The name of the property
|
137
|
-
|
139
|
+
|
138
140
|
Returns:
|
139
141
|
List[Dict[str, Any]]: List of available options with their metadata
|
140
142
|
"""
|
141
143
|
property_schema = await self.get_property_schema(property_name)
|
142
|
-
|
144
|
+
|
143
145
|
if not property_schema:
|
144
146
|
return []
|
145
|
-
|
147
|
+
|
146
148
|
property_type = property_schema.get("type")
|
147
|
-
|
149
|
+
|
148
150
|
if property_type in ["select", "multi_select", "status"]:
|
149
151
|
return property_schema.get(property_type, {}).get("options", [])
|
150
|
-
|
152
|
+
|
151
153
|
return []
|
152
|
-
|
154
|
+
|
153
155
|
async def get_option_names(self, property_name: str) -> List[str]:
|
154
156
|
"""
|
155
157
|
Gets the available option names for a property (select, multi_select, status).
|
156
|
-
|
158
|
+
|
157
159
|
Args:
|
158
160
|
property_name: The name of the property
|
159
|
-
|
161
|
+
|
160
162
|
Returns:
|
161
163
|
List[str]: List of available option names
|
162
164
|
"""
|
163
165
|
options = await self.get_property_options(property_name)
|
164
166
|
return [option.get("name", "") for option in options]
|
165
|
-
|
166
|
-
async def get_relation_details(
|
167
|
+
|
168
|
+
async def get_relation_details(
|
169
|
+
self, property_name: str
|
170
|
+
) -> Optional[Dict[str, Any]]:
|
167
171
|
"""
|
168
172
|
Gets details about a relation property, including the related database.
|
169
|
-
|
173
|
+
|
170
174
|
Args:
|
171
175
|
property_name: The name of the property
|
172
|
-
|
176
|
+
|
173
177
|
Returns:
|
174
178
|
Optional[Dict[str, Any]]: The relation details or None if not a relation
|
175
179
|
"""
|
176
180
|
property_schema = await self.get_property_schema(property_name)
|
177
|
-
|
181
|
+
|
178
182
|
if not property_schema or property_schema.get("type") != "relation":
|
179
183
|
return None
|
180
|
-
|
184
|
+
|
181
185
|
return property_schema.get("relation", {})
|
182
|
-
|
183
|
-
async def get_relation_options(
|
186
|
+
|
187
|
+
async def get_relation_options(
|
188
|
+
self, property_name: str, limit: int = 100
|
189
|
+
) -> List[Dict[str, Any]]:
|
184
190
|
"""
|
185
191
|
Gets available options for a relation property by querying the related database.
|
186
|
-
|
192
|
+
|
187
193
|
Args:
|
188
194
|
property_name: The name of the relation property
|
189
195
|
limit: Maximum number of options to retrieve
|
190
|
-
|
196
|
+
|
191
197
|
Returns:
|
192
198
|
List[Dict[str, Any]]: List of pages from the related database
|
193
199
|
"""
|
194
200
|
relation_details = await self.get_relation_details(property_name)
|
195
|
-
|
201
|
+
|
196
202
|
if not relation_details or "database_id" not in relation_details:
|
197
203
|
return []
|
198
|
-
|
204
|
+
|
199
205
|
related_db_id = relation_details["database_id"]
|
200
|
-
|
206
|
+
|
201
207
|
try:
|
202
208
|
# Query the related database to get options
|
203
209
|
query_result = await self._client.post(
|
204
210
|
f"databases/{related_db_id}/query",
|
205
211
|
{
|
206
212
|
"page_size": limit,
|
207
|
-
}
|
213
|
+
},
|
208
214
|
)
|
209
|
-
|
215
|
+
|
210
216
|
if not query_result or "results" not in query_result:
|
211
217
|
return []
|
212
|
-
|
218
|
+
|
213
219
|
# Extract relevant information from each page
|
214
220
|
options = []
|
215
221
|
for page in query_result["results"]:
|
216
222
|
page_id = page.get("id")
|
217
223
|
title = self._extract_title_from_page(page)
|
218
|
-
|
224
|
+
|
219
225
|
if page_id and title:
|
220
|
-
options.append({
|
221
|
-
|
222
|
-
"name": title
|
223
|
-
})
|
224
|
-
|
226
|
+
options.append({"id": page_id, "name": title})
|
227
|
+
|
225
228
|
return options
|
226
229
|
except Exception as e:
|
227
230
|
self.logger.error(f"Error getting relation options: {str(e)}")
|
228
231
|
return []
|
229
|
-
|
232
|
+
|
230
233
|
def _extract_title_from_page(self, page: Dict[str, Any]) -> Optional[str]:
|
231
234
|
"""
|
232
235
|
Extracts the title from a page object.
|
233
|
-
|
236
|
+
|
234
237
|
Args:
|
235
238
|
page: The page object from Notion API
|
236
|
-
|
239
|
+
|
237
240
|
Returns:
|
238
241
|
Optional[str]: The page title or None if not found
|
239
242
|
"""
|
240
243
|
if "properties" not in page:
|
241
244
|
return None
|
242
|
-
|
245
|
+
|
243
246
|
properties = page["properties"]
|
244
|
-
|
247
|
+
|
245
248
|
# Look for a title property
|
246
249
|
for prop_data in properties.values():
|
247
250
|
if prop_data.get("type") == "title" and "title" in prop_data:
|
248
251
|
title_parts = prop_data["title"]
|
249
|
-
return "".join(
|
250
|
-
|
252
|
+
return "".join(
|
253
|
+
[text_obj.get("plain_text", "") for text_obj in title_parts]
|
254
|
+
)
|
255
|
+
|
251
256
|
return None
|
252
|
-
|
253
|
-
async def validate_property_value(
|
257
|
+
|
258
|
+
async def validate_property_value(
|
259
|
+
self, property_name: str, value: Any
|
260
|
+
) -> Tuple[bool, Optional[str], Optional[List[str]]]:
|
254
261
|
"""
|
255
262
|
Validates a value for a property.
|
256
|
-
|
263
|
+
|
257
264
|
Args:
|
258
265
|
property_name: The name of the property
|
259
266
|
value: The value to validate
|
260
|
-
|
267
|
+
|
261
268
|
Returns:
|
262
|
-
Tuple[bool, Optional[str], Optional[List[str]]]:
|
269
|
+
Tuple[bool, Optional[str], Optional[List[str]]]:
|
263
270
|
- Boolean indicating if valid
|
264
271
|
- Error message if invalid
|
265
272
|
- Available options if applicable
|
266
273
|
"""
|
267
274
|
property_schema = await self.get_property_schema(property_name)
|
268
|
-
|
275
|
+
|
269
276
|
if not property_schema:
|
270
277
|
return False, f"Property '{property_name}' does not exist", None
|
271
|
-
|
278
|
+
|
272
279
|
property_type = property_schema.get("type")
|
273
|
-
|
280
|
+
|
274
281
|
# Validate select, multi_select, status properties
|
275
282
|
if property_type in ["select", "status"]:
|
276
283
|
options = await self.get_option_names(property_name)
|
277
|
-
|
284
|
+
|
278
285
|
if isinstance(value, str) and value not in options:
|
279
|
-
return
|
280
|
-
|
286
|
+
return (
|
287
|
+
False,
|
288
|
+
f"Invalid {property_type} option. Value '{value}' is not in the available options.",
|
289
|
+
options,
|
290
|
+
)
|
291
|
+
|
281
292
|
elif property_type == "multi_select":
|
282
293
|
options = await self.get_option_names(property_name)
|
283
|
-
|
294
|
+
|
284
295
|
if isinstance(value, list):
|
285
296
|
invalid_values = [val for val in value if val not in options]
|
286
297
|
if invalid_values:
|
287
|
-
return
|
288
|
-
|
298
|
+
return (
|
299
|
+
False,
|
300
|
+
f"Invalid multi_select options: {', '.join(invalid_values)}",
|
301
|
+
options,
|
302
|
+
)
|
303
|
+
|
289
304
|
return True, None, None
|
290
|
-
|
291
|
-
async def get_database_metadata(
|
305
|
+
|
306
|
+
async def get_database_metadata(
|
307
|
+
self, include_types: Optional[List[str]] = None
|
308
|
+
) -> Dict[str, Any]:
|
292
309
|
"""
|
293
310
|
Gets the complete metadata of the database, including property options.
|
294
|
-
|
311
|
+
|
295
312
|
Args:
|
296
313
|
include_types: List of property types to include (if None, include all)
|
297
|
-
|
314
|
+
|
298
315
|
Returns:
|
299
316
|
Dict[str, Any]: The database metadata
|
300
317
|
"""
|
301
318
|
await self._ensure_schema_loaded()
|
302
|
-
|
319
|
+
|
303
320
|
if not self._schema:
|
304
321
|
return {"properties": {}}
|
305
|
-
|
322
|
+
|
306
323
|
metadata = {"properties": {}}
|
307
|
-
|
324
|
+
|
308
325
|
for prop_name, prop_data in self._schema.items():
|
309
326
|
prop_type = prop_data.get("type")
|
310
|
-
|
327
|
+
|
311
328
|
# Skip if we're filtering and this type isn't included
|
312
329
|
if include_types and prop_type not in include_types:
|
313
330
|
continue
|
314
|
-
|
315
|
-
prop_metadata = {
|
316
|
-
|
317
|
-
"options": []
|
318
|
-
}
|
319
|
-
|
331
|
+
|
332
|
+
prop_metadata = {"type": prop_type, "options": []}
|
333
|
+
|
320
334
|
# Include options for select, multi_select, status
|
321
335
|
if prop_type in ["select", "multi_select", "status"]:
|
322
|
-
prop_metadata["options"] = prop_data.get(prop_type, {}).get(
|
323
|
-
|
336
|
+
prop_metadata["options"] = prop_data.get(prop_type, {}).get(
|
337
|
+
"options", []
|
338
|
+
)
|
339
|
+
|
324
340
|
# For relation properties, we might want to include related database info
|
325
341
|
elif prop_type == "relation":
|
326
342
|
prop_metadata["relation_details"] = prop_data.get("relation", {})
|
327
|
-
|
343
|
+
|
328
344
|
metadata["properties"][prop_name] = prop_metadata
|
329
|
-
|
330
|
-
return metadata
|
345
|
+
|
346
|
+
return metadata
|
@@ -1,40 +1,53 @@
|
|
1
1
|
from typing import Dict, Any, List, Optional
|
2
2
|
from notionary.core.notion_client import NotionClient
|
3
3
|
from notionary.core.page.metadata.metadata_editor import MetadataEditor
|
4
|
-
from notionary.core.page.properites.property_operation_result import
|
5
|
-
|
6
|
-
|
4
|
+
from notionary.core.page.properites.property_operation_result import (
|
5
|
+
PropertyOperationResult,
|
6
|
+
)
|
7
|
+
from notionary.core.page.relations.notion_page_title_resolver import (
|
8
|
+
NotionPageTitleResolver,
|
9
|
+
)
|
10
|
+
from notionary.core.page.properites.database_property_service import (
|
11
|
+
DatabasePropertyService,
|
12
|
+
)
|
7
13
|
from notionary.core.page.relations.page_database_relation import PageDatabaseRelation
|
8
|
-
from notionary.core.page.properites.property_value_extractor import
|
14
|
+
from notionary.core.page.properites.property_value_extractor import (
|
15
|
+
PropertyValueExtractor,
|
16
|
+
)
|
9
17
|
from notionary.util.logging_mixin import LoggingMixin
|
10
18
|
|
19
|
+
|
11
20
|
class PagePropertyManager(LoggingMixin):
|
12
21
|
"""Verwaltet den Zugriff auf und die Änderung von Seiteneigenschaften."""
|
13
|
-
|
14
|
-
def __init__(
|
15
|
-
|
16
|
-
|
22
|
+
|
23
|
+
def __init__(
|
24
|
+
self,
|
25
|
+
page_id: str,
|
26
|
+
client: NotionClient,
|
27
|
+
metadata_editor: MetadataEditor,
|
28
|
+
db_relation: PageDatabaseRelation,
|
29
|
+
):
|
17
30
|
self._page_id = page_id
|
18
31
|
self._client = client
|
19
32
|
self._page_data = None
|
20
33
|
self._metadata_editor = metadata_editor
|
21
34
|
self._db_relation = db_relation
|
22
35
|
self._db_property_service = None
|
23
|
-
|
36
|
+
|
24
37
|
self._extractor = PropertyValueExtractor(self.logger)
|
25
38
|
self._title_resolver = NotionPageTitleResolver(client)
|
26
|
-
|
39
|
+
|
27
40
|
async def get_properties(self) -> Dict[str, Any]:
|
28
41
|
"""Retrieves all properties of the page."""
|
29
42
|
page_data = await self._get_page_data()
|
30
43
|
if page_data and "properties" in page_data:
|
31
44
|
return page_data["properties"]
|
32
45
|
return {}
|
33
|
-
|
46
|
+
|
34
47
|
async def get_property_value(self, property_name: str, relation_getter=None) -> Any:
|
35
48
|
"""
|
36
49
|
Get the value of a specific property.
|
37
|
-
|
50
|
+
|
38
51
|
Args:
|
39
52
|
property_name: Name of the property to get
|
40
53
|
relation_getter: Optional callback function to get relation values
|
@@ -42,105 +55,121 @@ class PagePropertyManager(LoggingMixin):
|
|
42
55
|
properties = await self.get_properties()
|
43
56
|
if property_name not in properties:
|
44
57
|
return None
|
45
|
-
|
58
|
+
|
46
59
|
prop_data = properties[property_name]
|
47
60
|
return await self._extractor.extract(property_name, prop_data, relation_getter)
|
48
|
-
|
49
61
|
|
50
|
-
async def set_property_by_name(
|
62
|
+
async def set_property_by_name(
|
63
|
+
self, property_name: str, value: Any
|
64
|
+
) -> PropertyOperationResult:
|
51
65
|
"""
|
52
66
|
Set a property value by name, automatically detecting the property type.
|
53
|
-
|
67
|
+
|
54
68
|
Args:
|
55
69
|
property_name: Name of the property
|
56
70
|
value: Value to set
|
57
|
-
|
71
|
+
|
58
72
|
Returns:
|
59
|
-
PropertyOperationResult: Result of the operation with status, error messages,
|
73
|
+
PropertyOperationResult: Result of the operation with status, error messages,
|
60
74
|
and available options if applicable
|
61
75
|
"""
|
62
76
|
property_type = await self.get_property_type(property_name)
|
63
|
-
|
77
|
+
|
64
78
|
if property_type == "relation":
|
65
|
-
result = PropertyOperationResult.from_relation_type_error(
|
79
|
+
result = PropertyOperationResult.from_relation_type_error(
|
80
|
+
property_name, value
|
81
|
+
)
|
66
82
|
self.logger.warning(result.error)
|
67
83
|
return result
|
68
|
-
|
84
|
+
|
69
85
|
if not await self._db_relation.is_database_page():
|
70
|
-
api_response = await self._metadata_editor.set_property_by_name(
|
86
|
+
api_response = await self._metadata_editor.set_property_by_name(
|
87
|
+
property_name, value
|
88
|
+
)
|
71
89
|
if api_response:
|
72
90
|
await self.invalidate_cache()
|
73
|
-
return PropertyOperationResult.from_success(
|
91
|
+
return PropertyOperationResult.from_success(
|
92
|
+
property_name, value, api_response
|
93
|
+
)
|
74
94
|
return PropertyOperationResult.from_no_api_response(property_name, value)
|
75
|
-
|
95
|
+
|
76
96
|
db_service = await self._init_db_property_service()
|
77
|
-
|
97
|
+
|
78
98
|
if not db_service:
|
79
|
-
api_response = await self._metadata_editor.set_property_by_name(
|
99
|
+
api_response = await self._metadata_editor.set_property_by_name(
|
100
|
+
property_name, value
|
101
|
+
)
|
80
102
|
if api_response:
|
81
103
|
await self.invalidate_cache()
|
82
|
-
return PropertyOperationResult.from_success(
|
104
|
+
return PropertyOperationResult.from_success(
|
105
|
+
property_name, value, api_response
|
106
|
+
)
|
83
107
|
return PropertyOperationResult.from_no_api_response(property_name, value)
|
84
|
-
|
85
|
-
is_valid, error_message, available_options =
|
86
|
-
property_name, value
|
108
|
+
|
109
|
+
is_valid, error_message, available_options = (
|
110
|
+
await db_service.validate_property_value(property_name, value)
|
87
111
|
)
|
88
|
-
|
112
|
+
|
89
113
|
if not is_valid:
|
90
114
|
if available_options:
|
91
115
|
options_str = "', '".join(available_options)
|
92
116
|
detailed_error = f"{error_message}\nAvailable options for '{property_name}': '{options_str}'"
|
93
117
|
self.logger.warning(detailed_error)
|
94
118
|
else:
|
95
|
-
self.logger.warning(
|
96
|
-
|
119
|
+
self.logger.warning(
|
120
|
+
"%s\nNo valid options available for '%s'",
|
121
|
+
error_message,
|
122
|
+
property_name,
|
123
|
+
)
|
124
|
+
|
97
125
|
return PropertyOperationResult.from_error(
|
98
|
-
property_name,
|
99
|
-
error_message,
|
100
|
-
value,
|
101
|
-
available_options
|
126
|
+
property_name, error_message, value, available_options
|
102
127
|
)
|
103
|
-
|
104
|
-
api_response = await self._metadata_editor.set_property_by_name(
|
128
|
+
|
129
|
+
api_response = await self._metadata_editor.set_property_by_name(
|
130
|
+
property_name, value
|
131
|
+
)
|
105
132
|
if api_response:
|
106
133
|
await self.invalidate_cache()
|
107
|
-
return PropertyOperationResult.from_success(
|
108
|
-
|
134
|
+
return PropertyOperationResult.from_success(
|
135
|
+
property_name, value, api_response
|
136
|
+
)
|
137
|
+
|
109
138
|
return PropertyOperationResult.from_no_api_response(property_name, value)
|
110
|
-
|
139
|
+
|
111
140
|
async def get_property_type(self, property_name: str) -> Optional[str]:
|
112
141
|
"""Gets the type of a specific property."""
|
113
142
|
db_service = await self._init_db_property_service()
|
114
143
|
if db_service:
|
115
144
|
return await db_service.get_property_type(property_name)
|
116
145
|
return None
|
117
|
-
|
146
|
+
|
118
147
|
async def get_available_options_for_property(self, property_name: str) -> List[str]:
|
119
148
|
"""Gets the available option names for a property."""
|
120
149
|
db_service = await self._init_db_property_service()
|
121
150
|
if db_service:
|
122
151
|
return await db_service.get_option_names(property_name)
|
123
152
|
return []
|
124
|
-
|
153
|
+
|
125
154
|
async def _get_page_data(self, force_refresh=False) -> Dict[str, Any]:
|
126
155
|
"""Gets the page data and caches it for future use."""
|
127
156
|
if self._page_data is None or force_refresh:
|
128
157
|
self._page_data = await self._client.get_page(self._page_id)
|
129
158
|
return self._page_data
|
130
|
-
|
159
|
+
|
131
160
|
async def invalidate_cache(self) -> None:
|
132
161
|
"""Forces a refresh of the cached page data on next access."""
|
133
162
|
self._page_data = None
|
134
|
-
|
163
|
+
|
135
164
|
async def _init_db_property_service(self) -> Optional[DatabasePropertyService]:
|
136
165
|
"""Lazily initializes the database property service if needed."""
|
137
166
|
if self._db_property_service is not None:
|
138
167
|
return self._db_property_service
|
139
|
-
|
168
|
+
|
140
169
|
database_id = await self._db_relation.get_parent_database_id()
|
141
170
|
if not database_id:
|
142
171
|
return None
|
143
|
-
|
172
|
+
|
144
173
|
self._db_property_service = DatabasePropertyService(database_id, self._client)
|
145
174
|
await self._db_property_service.load_schema()
|
146
|
-
return self._db_property_service
|
175
|
+
return self._db_property_service
|