notionary 0.1.11__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 +6 -4
- 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 +3 -3
- 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 +139 -149
- 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.11.dist-info → notionary-0.1.12.dist-info}/METADATA +1 -1
- {notionary-0.1.11.dist-info → notionary-0.1.12.dist-info}/RECORD +31 -30
- notionary/core/database/notion_database_schema.py +0 -104
- {notionary-0.1.11.dist-info → notionary-0.1.12.dist-info}/WHEEL +0 -0
- {notionary-0.1.11.dist-info → notionary-0.1.12.dist-info}/licenses/LICENSE +0 -0
- {notionary-0.1.11.dist-info → notionary-0.1.12.dist-info}/top_level.txt +0 -0
@@ -1,11 +1,12 @@
|
|
1
1
|
from typing import Any, Dict, List, Optional
|
2
2
|
from dataclasses import dataclass, field
|
3
3
|
|
4
|
+
|
4
5
|
@dataclass
|
5
6
|
class RelationOperationResult:
|
6
7
|
"""
|
7
8
|
Result of a relation operation in Notion.
|
8
|
-
|
9
|
+
|
9
10
|
Attributes:
|
10
11
|
success: Whether the operation was successful overall
|
11
12
|
property_name: Name of the affected relation property
|
@@ -15,6 +16,7 @@ class RelationOperationResult:
|
|
15
16
|
error: Error message, if any
|
16
17
|
api_response: The original API response
|
17
18
|
"""
|
19
|
+
|
18
20
|
success: bool
|
19
21
|
property_name: str
|
20
22
|
found_pages: List[str] = field(default_factory=list)
|
@@ -22,32 +24,38 @@ class RelationOperationResult:
|
|
22
24
|
page_ids_added: List[str] = field(default_factory=list)
|
23
25
|
error: Optional[str] = None
|
24
26
|
api_response: Optional[Dict[str, Any]] = None
|
25
|
-
|
27
|
+
|
26
28
|
NO_API_RESPONSE = "Failed to update relation (no API response)"
|
27
29
|
NO_PAGES_FOUND = "No valid pages found for relation"
|
28
|
-
|
30
|
+
|
29
31
|
@classmethod
|
30
|
-
def from_success(
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
def from_success(
|
33
|
+
cls,
|
34
|
+
property_name: str,
|
35
|
+
found_pages: List[str],
|
36
|
+
page_ids_added: List[str],
|
37
|
+
api_response: Dict[str, Any],
|
38
|
+
not_found_pages: Optional[List[str]] = None,
|
39
|
+
) -> "RelationOperationResult":
|
35
40
|
"""Creates a success result."""
|
36
41
|
return cls(
|
37
|
-
success=True,
|
42
|
+
success=True,
|
38
43
|
property_name=property_name,
|
39
44
|
found_pages=found_pages,
|
40
45
|
not_found_pages=not_found_pages or [],
|
41
46
|
page_ids_added=page_ids_added,
|
42
|
-
api_response=api_response
|
47
|
+
api_response=api_response,
|
43
48
|
)
|
44
|
-
|
49
|
+
|
45
50
|
@classmethod
|
46
|
-
def from_error(
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
+
def from_error(
|
52
|
+
cls,
|
53
|
+
property_name: str,
|
54
|
+
error: str,
|
55
|
+
found_pages: Optional[List[str]] = None,
|
56
|
+
not_found_pages: Optional[List[str]] = None,
|
57
|
+
page_ids_added: Optional[List[str]] = None,
|
58
|
+
) -> "RelationOperationResult":
|
51
59
|
"""Creates an error result."""
|
52
60
|
return cls(
|
53
61
|
success=False,
|
@@ -55,81 +63,82 @@ class RelationOperationResult:
|
|
55
63
|
found_pages=found_pages or [],
|
56
64
|
not_found_pages=not_found_pages or [],
|
57
65
|
page_ids_added=page_ids_added or [],
|
58
|
-
error=error
|
66
|
+
error=error,
|
59
67
|
)
|
60
|
-
|
68
|
+
|
61
69
|
@classmethod
|
62
|
-
def from_no_pages_found(
|
63
|
-
|
70
|
+
def from_no_pages_found(
|
71
|
+
cls, property_name: str, not_found_pages: List[str]
|
72
|
+
) -> "RelationOperationResult":
|
64
73
|
"""Creates a standardized result for when no pages were found."""
|
65
74
|
return cls.from_error(
|
66
75
|
property_name=property_name,
|
67
76
|
error=cls.NO_PAGES_FOUND,
|
68
|
-
not_found_pages=not_found_pages
|
77
|
+
not_found_pages=not_found_pages,
|
69
78
|
)
|
70
79
|
|
71
80
|
@classmethod
|
72
|
-
def from_no_api_response(
|
73
|
-
|
74
|
-
|
81
|
+
def from_no_api_response(
|
82
|
+
cls, property_name: str, found_pages: List[str], page_ids_added: List[str]
|
83
|
+
) -> "RelationOperationResult":
|
75
84
|
"""Creates a standardized result for a missing API response."""
|
76
85
|
return cls.from_error(
|
77
86
|
property_name=property_name,
|
78
87
|
error=cls.NO_API_RESPONSE,
|
79
88
|
found_pages=found_pages,
|
80
|
-
page_ids_added=page_ids_added
|
89
|
+
page_ids_added=page_ids_added,
|
81
90
|
)
|
82
|
-
|
91
|
+
|
83
92
|
@property
|
84
93
|
def has_not_found_pages(self) -> bool:
|
85
94
|
"""Returns True if there were any pages that couldn't be found."""
|
86
95
|
return len(self.not_found_pages) > 0
|
87
|
-
|
96
|
+
|
88
97
|
@property
|
89
98
|
def has_found_pages(self) -> bool:
|
90
99
|
"""Returns True if any pages were found."""
|
91
100
|
return len(self.found_pages) > 0
|
92
|
-
|
101
|
+
|
93
102
|
def to_dict(self) -> Dict[str, Any]:
|
94
103
|
"""Converts the result to a dictionary."""
|
95
104
|
result = {
|
96
105
|
"success": self.success,
|
97
106
|
"property": self.property_name,
|
98
107
|
}
|
99
|
-
|
108
|
+
|
100
109
|
if self.found_pages:
|
101
110
|
result["found_pages"] = self.found_pages
|
102
|
-
|
111
|
+
|
103
112
|
if self.not_found_pages:
|
104
113
|
result["not_found_pages"] = self.not_found_pages
|
105
|
-
|
114
|
+
|
106
115
|
if self.page_ids_added:
|
107
116
|
result["page_ids_added"] = self.page_ids_added
|
108
|
-
|
117
|
+
|
109
118
|
if not self.success:
|
110
119
|
result["error"] = self.error
|
111
|
-
|
120
|
+
|
112
121
|
if self.api_response:
|
113
122
|
result["api_response"] = self.api_response
|
114
|
-
|
123
|
+
|
115
124
|
return result
|
116
|
-
|
125
|
+
|
117
126
|
def __str__(self) -> str:
|
118
127
|
"""String representation of the result."""
|
119
128
|
if self.success:
|
120
129
|
base = f"Success: Added {len(self.page_ids_added)} relation(s) to property '{self.property_name}'"
|
121
|
-
|
130
|
+
|
122
131
|
if self.not_found_pages:
|
123
132
|
pages_str = "', '".join(self.not_found_pages)
|
124
133
|
base += f"\nWarning: Could not find pages: '{pages_str}'"
|
125
|
-
|
134
|
+
|
126
135
|
return base
|
127
|
-
|
136
|
+
|
128
137
|
if not self.found_pages and self.not_found_pages:
|
129
138
|
pages_str = "', '".join(self.not_found_pages)
|
130
139
|
return f"Error: {self.error}\nNone of the requested pages were found: '{pages_str}'"
|
131
|
-
|
140
|
+
|
132
141
|
if self.found_pages and not self.page_ids_added:
|
133
142
|
return f"Error: {self.error}\nPages were found but could not be added to the relation."
|
134
|
-
|
135
|
-
return f"Error: {self.error}"
|
143
|
+
|
144
|
+
return f"Error: {self.error}"
|
notionary/util/page_id_utils.py
CHANGED
@@ -4,39 +4,43 @@ from typing import Optional
|
|
4
4
|
UUID_PATTERN = r"^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$"
|
5
5
|
UUID_RAW_PATTERN = r"([a-f0-9]{32})"
|
6
6
|
|
7
|
+
|
7
8
|
def extract_uuid(source: str) -> Optional[str]:
|
8
9
|
if is_valid_uuid(source):
|
9
10
|
return source
|
10
|
-
|
11
|
+
|
11
12
|
match = re.search(UUID_RAW_PATTERN, source.lower())
|
12
13
|
if not match:
|
13
14
|
return None
|
14
|
-
|
15
|
+
|
15
16
|
uuid_raw = match.group(1)
|
16
17
|
return f"{uuid_raw[0:8]}-{uuid_raw[8:12]}-{uuid_raw[12:16]}-{uuid_raw[16:20]}-{uuid_raw[20:32]}"
|
17
18
|
|
19
|
+
|
18
20
|
def is_valid_uuid(uuid: str) -> bool:
|
19
21
|
return bool(re.match(UUID_PATTERN, uuid.lower()))
|
20
22
|
|
23
|
+
|
21
24
|
def format_uuid(value: str) -> Optional[str]:
|
22
25
|
if is_valid_uuid(value):
|
23
26
|
return value
|
24
27
|
return extract_uuid(value)
|
25
28
|
|
29
|
+
|
26
30
|
def extract_and_validate_page_id(page_id: Optional[str], url: Optional[str]) -> str:
|
27
31
|
if not page_id and not url:
|
28
32
|
raise ValueError("Either page_id or url must be provided")
|
29
|
-
|
33
|
+
|
30
34
|
candidate = page_id or url
|
31
|
-
|
35
|
+
|
32
36
|
if is_valid_uuid(candidate):
|
33
37
|
return candidate
|
34
|
-
|
38
|
+
|
35
39
|
extracted_id = extract_uuid(candidate)
|
36
40
|
if not extracted_id:
|
37
41
|
raise ValueError(f"Could not extract a valid UUID from: {candidate}")
|
38
|
-
|
42
|
+
|
39
43
|
formatted = format_uuid(extracted_id)
|
40
44
|
if not formatted or not is_valid_uuid(formatted):
|
41
45
|
raise ValueError(f"Invalid UUID format: {formatted}")
|
42
|
-
return formatted
|
46
|
+
return formatted
|
@@ -1,15 +1,15 @@
|
|
1
|
-
notionary/__init__.py,sha256=
|
2
|
-
notionary/core/notion_client.py,sha256=
|
1
|
+
notionary/__init__.py,sha256=19UodWJsuHVSQBFZ5rFBnsSPznz22GTy2XYLIldL7-Q,730
|
2
|
+
notionary/core/notion_client.py,sha256=VdIE1TSEZTy2BhR7Hnx_McndvQYxlu-aJN_7LeDpXgY,4497
|
3
3
|
notionary/core/converters/__init__.py,sha256=GOUehJbe4BKHtec1MqL1YGu3AX8zFtkwSZfhYkY5-P0,1798
|
4
|
-
notionary/core/converters/markdown_to_notion_converter.py,sha256=
|
4
|
+
notionary/core/converters/markdown_to_notion_converter.py,sha256=u2mjshWiiLRVHYrdcXh7fdVMDwWMQLq5LKtvDmX_IWo,15110
|
5
5
|
notionary/core/converters/notion_to_markdown_converter.py,sha256=c8GyWX8-UrNfRDk7OOBKbSEb5qOwljUCwI6g5risO2c,1287
|
6
|
-
notionary/core/converters/elements/audio_element.py,sha256=
|
6
|
+
notionary/core/converters/elements/audio_element.py,sha256=as8X3EKRn5YIZQph60UdSdnrYQWDCCknvuQ4D3vr8B4,5605
|
7
7
|
notionary/core/converters/elements/bookmark_element.py,sha256=bpHobkGnyBGDAJK5vY9R3Ntl4GiRSF-EyyA31aq2O3E,8593
|
8
8
|
notionary/core/converters/elements/callout_element.py,sha256=rkDoXikjIl-zU3GLawSXgRunBJGLnEvin9zIlCgW4TY,5964
|
9
9
|
notionary/core/converters/elements/code_block_element.py,sha256=G1iGMsGSK5KPSk-tA8TsPs9XNU9ydjYfOVnjIvdZG74,5189
|
10
10
|
notionary/core/converters/elements/column_element.py,sha256=ZwQsLBEownVJnzyv-GfNjvzJhAfKz9ncggqZUmZHF5A,10722
|
11
11
|
notionary/core/converters/elements/divider_element.py,sha256=Ul0wXHY96qWL72iAvttRQMOoAGuASgwFwPraGnpUkX0,2792
|
12
|
-
notionary/core/converters/elements/embed_element.py,sha256=
|
12
|
+
notionary/core/converters/elements/embed_element.py,sha256=AOFCAj5cR1mTg8scFh1GK3bmasSZLltp_xcrVZR3sOc,4784
|
13
13
|
notionary/core/converters/elements/heading_element.py,sha256=BCBcpEO_UX92nzCclVHAjlOLFJ5zu9wDlAGbphesaOQ,2788
|
14
14
|
notionary/core/converters/elements/image_element.py,sha256=uU3bY26LvJwD_CAXN11tqYt5Ed84gjUeHWnJmxvH07Y,4861
|
15
15
|
notionary/core/converters/elements/list_element.py,sha256=lM9nVGVG3VtmjMkqxrBj71wiJITuRypwxORu4zghqAM,4878
|
@@ -19,36 +19,37 @@ notionary/core/converters/elements/qoute_element.py,sha256=CZD1Fe_Lhxsv4mdAM_dr4
|
|
19
19
|
notionary/core/converters/elements/table_element.py,sha256=3V9bnNBdsslXZivQ0vpF4_rzrdyI3SWt3aYR814mOzA,11254
|
20
20
|
notionary/core/converters/elements/text_inline_formatter.py,sha256=FE_Sq2cozpu5RVtMbnPq21gD06UjH3LMRYr3s16JKYo,10606
|
21
21
|
notionary/core/converters/elements/todo_lists.py,sha256=wgY6YejURBQ5ESdVLZVIy9QKchS-x8odrmS8X4cC5Kc,4265
|
22
|
-
notionary/core/converters/elements/toggle_element.py,sha256=
|
22
|
+
notionary/core/converters/elements/toggle_element.py,sha256=17chs10njaMfhGeQblvy_JZA7gRMqLp7cXfipIdK3Jo,7635
|
23
23
|
notionary/core/converters/elements/video_element.py,sha256=xrBLY3e_SgKNamItZkfPNMbNEh37Ftp4jWIV6nwV-ds,6047
|
24
|
-
notionary/core/converters/registry/block_element_registry.py,sha256=
|
24
|
+
notionary/core/converters/registry/block_element_registry.py,sha256=MVL7SeUv5U2TzbqC5t9yDr1WQq7gOnQL2SnwSL-R478,8700
|
25
25
|
notionary/core/converters/registry/block_element_registry_builder.py,sha256=D4GmIAdMoP7K1P78qlgN-GoDwtB_4dZTws049gtXQ5c,9457
|
26
|
+
notionary/core/database/database_discovery.py,sha256=ViW3gcdujhmtwTa4HKv-bZOQXXbmBpZFLgzKT7vreXM,4625
|
26
27
|
notionary/core/database/database_info_service.py,sha256=58k7om0UXP8w0jCJHewccG5UbOvELMBAbQvXOm7F1OM,1341
|
27
|
-
notionary/core/database/notion_database_manager.py,sha256=
|
28
|
-
notionary/core/database/notion_database_manager_factory.py,sha256=
|
29
|
-
notionary/core/database/notion_database_schema.py,sha256=WUIjG7I5kusk4GOOdmVSHIKc2Z8SeOgJ1FuGpTn4avQ,3304
|
28
|
+
notionary/core/database/notion_database_manager.py,sha256=7xVJiR-7Kh2Wwoz1vMiOP5vfmNw_PoidnDqmjkHLxGA,7355
|
29
|
+
notionary/core/database/notion_database_manager_factory.py,sha256=bJ_9AbKJnb1g--reo36I8Tlbt_pST5kCmKwlqtPOpq4,6921
|
30
30
|
notionary/core/database/models/page_result.py,sha256=Vmm5_oYpYAkIIJVoTd1ZZGloeC3cmFLMYP255mAmtaw,233
|
31
|
-
notionary/core/page/notion_page_manager.py,sha256=
|
32
|
-
notionary/core/page/content/
|
33
|
-
notionary/core/page/
|
34
|
-
notionary/core/page/metadata/
|
35
|
-
notionary/core/page/metadata/
|
36
|
-
notionary/core/page/
|
37
|
-
notionary/core/page/properites/
|
38
|
-
notionary/core/page/properites/
|
39
|
-
notionary/core/page/properites/
|
40
|
-
notionary/core/page/properites/
|
41
|
-
notionary/core/page/
|
42
|
-
notionary/core/page/relations/
|
43
|
-
notionary/core/page/relations/
|
44
|
-
notionary/core/page/relations/
|
31
|
+
notionary/core/page/notion_page_manager.py,sha256=S3dPKK7YQ2VzNeQxyewkpkoyfuAwPiwjM_5pT7N8xms,23903
|
32
|
+
notionary/core/page/content/notion_page_content_chunker.py,sha256=xRks74Dqec-De6-AVTxMPnXs-MSJBzSm1HfJfaHiKr8,3330
|
33
|
+
notionary/core/page/content/page_content_manager.py,sha256=5qzpUFqMkOOqKWA6i6bWnGqbQyvdaEet0eNyerfFWck,3987
|
34
|
+
notionary/core/page/metadata/metadata_editor.py,sha256=VUF5rQIo7DBKU3-Noa_Qifj3KQofc5ZAUZCCruCfx3g,4959
|
35
|
+
notionary/core/page/metadata/notion_icon_manager.py,sha256=4CVahnmlf4m7nw5xBt_VC2Zuy1-tdC6aeLtf3vsFnPU,1431
|
36
|
+
notionary/core/page/metadata/notion_page_cover_manager.py,sha256=g36tCRpOYLTzX6b7vbyPsz1tclDW9lB6rUobDcstR5c,1722
|
37
|
+
notionary/core/page/properites/database_property_service.py,sha256=OJSfcXHRP5XGiMILcuvrnBKBbqz0kquMZVwp2i-wBtQ,11575
|
38
|
+
notionary/core/page/properites/page_property_manager.py,sha256=SZmk2RPjraUyPb9lz2tX7hY5Vunjd85pftAwMeTdeL8,6949
|
39
|
+
notionary/core/page/properites/property_formatter.py,sha256=d_Nr5XQxgjB6VIS0u3ey14MOUKY416o_BvdXjbkUNAQ,3667
|
40
|
+
notionary/core/page/properites/property_operation_result.py,sha256=PhxHJJxxG2BdDl7aswhWnMSmf9RQtoinKkRHDoqxwCs,3913
|
41
|
+
notionary/core/page/properites/property_value_extractor.py,sha256=1BfyCYrFzfIUmNTozavrLTjG--6P6Dy2tkewf6rHHwQ,2353
|
42
|
+
notionary/core/page/relations/notion_page_relation_manager.py,sha256=A5bdJj_8fckTuXEMscuEcPwRs6S___tBz06ISN3Qh4Y,12697
|
43
|
+
notionary/core/page/relations/notion_page_title_resolver.py,sha256=AcwQyji8WRysERXYXTFpl-kIz1yBxI4QF4HOWOqQWug,1727
|
44
|
+
notionary/core/page/relations/page_database_relation.py,sha256=lhcRzh2kWFgUYofxznWTgbA-CjOpJudhroaWmf4WEs4,2318
|
45
|
+
notionary/core/page/relations/relation_operation_result.py,sha256=NDxBzGntOxc_89ti-HG8xDSqfY6PwyGHKHrrKbCzNjM,5010
|
45
46
|
notionary/exceptions/database_exceptions.py,sha256=I-Tx6bYRLpi5pjGPtbT-Mqxvz3BFgYTiuZxknJeLxtI,2638
|
46
47
|
notionary/exceptions/page_creation_exception.py,sha256=4v7IuZD6GsQLrqhDLriGjuG3ML638gAO53zDCrLePuU,281
|
47
48
|
notionary/util/logging_mixin.py,sha256=fKsx9t90bwvL74ZX3dU-sXdC4TZCQyO6qU9I8txkw_U,1369
|
48
|
-
notionary/util/page_id_utils.py,sha256=
|
49
|
+
notionary/util/page_id_utils.py,sha256=gMNhuD2qRZ7PT8MAxqPaTaM7dgT01H-YqNZjmJFbEDs,1359
|
49
50
|
notionary/util/singleton_decorator.py,sha256=GTNMfIlVNRUVMw_c88xqd12-DcqZJjmyidN54yqiNVw,472
|
50
|
-
notionary-0.1.
|
51
|
-
notionary-0.1.
|
52
|
-
notionary-0.1.
|
53
|
-
notionary-0.1.
|
54
|
-
notionary-0.1.
|
51
|
+
notionary-0.1.12.dist-info/licenses/LICENSE,sha256=zOm3cRT1qD49eg7vgw95MI79rpUAZa1kRBFwL2FkAr8,1120
|
52
|
+
notionary-0.1.12.dist-info/METADATA,sha256=FneQ0YUpzkxpWH05hySub93Q7Hzz3BeUzOubv90iWJg,6154
|
53
|
+
notionary-0.1.12.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
54
|
+
notionary-0.1.12.dist-info/top_level.txt,sha256=fhONa6BMHQXqthx5PanWGbPL0b8rdFqhrJKVLf_adSs,10
|
55
|
+
notionary-0.1.12.dist-info/RECORD,,
|
@@ -1,104 +0,0 @@
|
|
1
|
-
from typing import (
|
2
|
-
AsyncGenerator,
|
3
|
-
Dict,
|
4
|
-
Optional,
|
5
|
-
Any,
|
6
|
-
)
|
7
|
-
from notionary.core.notion_client import NotionClient
|
8
|
-
from notionary.util.logging_mixin import LoggingMixin
|
9
|
-
|
10
|
-
class NotionDatabaseAccessor(LoggingMixin):
|
11
|
-
"""
|
12
|
-
A utility class that provides methods to access Notion databases.
|
13
|
-
Focused on efficient, paginated access to databases without unnecessary complexity.
|
14
|
-
"""
|
15
|
-
|
16
|
-
def __init__(self, client: Optional[NotionClient] = None) -> None:
|
17
|
-
"""
|
18
|
-
Initialize the accessor with a NotionClient.
|
19
|
-
|
20
|
-
Args:
|
21
|
-
client: NotionClient instance for API communication
|
22
|
-
"""
|
23
|
-
self._client = client if client else NotionClient()
|
24
|
-
self.logger.info("NotionDatabaseAccessor initialized")
|
25
|
-
|
26
|
-
async def iter_databases(
|
27
|
-
self, page_size: int = 100
|
28
|
-
) -> AsyncGenerator[Dict[str, Any], None]:
|
29
|
-
"""
|
30
|
-
Asynchronous generator that yields Notion databases one by one.
|
31
|
-
|
32
|
-
Uses the Notion API to provide paginated access to all databases
|
33
|
-
without loading all of them into memory at once.
|
34
|
-
|
35
|
-
Args:
|
36
|
-
page_size: The number of databases to fetch per request
|
37
|
-
|
38
|
-
Yields:
|
39
|
-
Individual database objects from the Notion API
|
40
|
-
"""
|
41
|
-
start_cursor: Optional[str] = None
|
42
|
-
|
43
|
-
while True:
|
44
|
-
body: Dict[str, Any] = {
|
45
|
-
"filter": {"value": "database", "property": "object"},
|
46
|
-
"page_size": page_size,
|
47
|
-
}
|
48
|
-
|
49
|
-
if start_cursor:
|
50
|
-
body["start_cursor"] = start_cursor
|
51
|
-
|
52
|
-
result = await self._client.post("search", data=body)
|
53
|
-
|
54
|
-
if not result or "results" not in result:
|
55
|
-
self.logger.error("Error fetching databases")
|
56
|
-
break
|
57
|
-
|
58
|
-
for database in result["results"]:
|
59
|
-
yield database
|
60
|
-
|
61
|
-
if "has_more" in result and result["has_more"] and "next_cursor" in result:
|
62
|
-
start_cursor = result["next_cursor"]
|
63
|
-
else:
|
64
|
-
break
|
65
|
-
|
66
|
-
async def get_database(self, database_id: str) -> Optional[Dict[str, Any]]:
|
67
|
-
"""
|
68
|
-
Get the details for a specific database.
|
69
|
-
|
70
|
-
Args:
|
71
|
-
database_id: The ID of the database
|
72
|
-
|
73
|
-
Returns:
|
74
|
-
Database details or None if not found
|
75
|
-
"""
|
76
|
-
db_details = await self._client.get(f"databases/{database_id}")
|
77
|
-
if not db_details:
|
78
|
-
self.logger.error("Failed to retrieve database %s", database_id)
|
79
|
-
return None
|
80
|
-
|
81
|
-
return db_details
|
82
|
-
|
83
|
-
def extract_database_title(self, database: Dict[str, Any]) -> str:
|
84
|
-
"""
|
85
|
-
Extract the database title from a Notion API response.
|
86
|
-
|
87
|
-
Args:
|
88
|
-
database: The database object from the Notion API
|
89
|
-
|
90
|
-
Returns:
|
91
|
-
The extracted title or "Untitled" if no title is found
|
92
|
-
"""
|
93
|
-
title = "Untitled"
|
94
|
-
|
95
|
-
if "title" in database:
|
96
|
-
title_parts = []
|
97
|
-
for text_obj in database["title"]:
|
98
|
-
if "plain_text" in text_obj:
|
99
|
-
title_parts.append(text_obj["plain_text"])
|
100
|
-
|
101
|
-
if title_parts:
|
102
|
-
title = "".join(title_parts)
|
103
|
-
|
104
|
-
return title
|
File without changes
|
File without changes
|
File without changes
|