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.
Files changed (32) hide show
  1. notionary/__init__.py +13 -2
  2. notionary/core/converters/elements/audio_element.py +6 -4
  3. notionary/core/converters/elements/embed_element.py +2 -4
  4. notionary/core/converters/elements/toggle_element.py +28 -20
  5. notionary/core/converters/markdown_to_notion_converter.py +70 -109
  6. notionary/core/converters/registry/block_element_registry.py +3 -3
  7. notionary/core/database/database_discovery.py +140 -0
  8. notionary/core/database/notion_database_manager.py +26 -49
  9. notionary/core/database/notion_database_manager_factory.py +10 -4
  10. notionary/core/notion_client.py +4 -2
  11. notionary/core/page/content/notion_page_content_chunker.py +84 -0
  12. notionary/core/page/content/page_content_manager.py +26 -8
  13. notionary/core/page/metadata/metadata_editor.py +57 -44
  14. notionary/core/page/metadata/notion_icon_manager.py +9 -11
  15. notionary/core/page/metadata/notion_page_cover_manager.py +15 -20
  16. notionary/core/page/notion_page_manager.py +139 -149
  17. notionary/core/page/properites/database_property_service.py +114 -98
  18. notionary/core/page/properites/page_property_manager.py +78 -49
  19. notionary/core/page/properites/property_formatter.py +1 -1
  20. notionary/core/page/properites/property_operation_result.py +43 -30
  21. notionary/core/page/properites/property_value_extractor.py +26 -8
  22. notionary/core/page/relations/notion_page_relation_manager.py +71 -52
  23. notionary/core/page/relations/notion_page_title_resolver.py +11 -11
  24. notionary/core/page/relations/page_database_relation.py +14 -14
  25. notionary/core/page/relations/relation_operation_result.py +50 -41
  26. notionary/util/page_id_utils.py +11 -7
  27. {notionary-0.1.11.dist-info → notionary-0.1.12.dist-info}/METADATA +1 -1
  28. {notionary-0.1.11.dist-info → notionary-0.1.12.dist-info}/RECORD +31 -30
  29. notionary/core/database/notion_database_schema.py +0 -104
  30. {notionary-0.1.11.dist-info → notionary-0.1.12.dist-info}/WHEEL +0 -0
  31. {notionary-0.1.11.dist-info → notionary-0.1.12.dist-info}/licenses/LICENSE +0 -0
  32. {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(cls, property_name: str,
31
- found_pages: List[str],
32
- page_ids_added: List[str],
33
- api_response: Dict[str, Any],
34
- not_found_pages: Optional[List[str]] = None) -> "RelationOperationResult":
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(cls, property_name: str,
47
- error: str,
48
- found_pages: Optional[List[str]] = None,
49
- not_found_pages: Optional[List[str]] = None,
50
- page_ids_added: Optional[List[str]] = None) -> "RelationOperationResult":
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(cls, property_name: str,
63
- not_found_pages: List[str]) -> "RelationOperationResult":
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(cls, property_name: str,
73
- found_pages: List[str],
74
- page_ids_added: List[str]) -> "RelationOperationResult":
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}"
@@ -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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: notionary
3
- Version: 0.1.11
3
+ Version: 0.1.12
4
4
  Summary: A toolkit to convert between Markdown and Notion blocks
5
5
  Home-page: https://github.com/mathisarends/notionary
6
6
  Author: Mathis Arends
@@ -1,15 +1,15 @@
1
- notionary/__init__.py,sha256=5T16clJlSHFsopcPUnkGrEo8spNDUQ0i-O00UEF7nR8,320
2
- notionary/core/notion_client.py,sha256=9o9-Ki1homkSbM1C51nsaAzVPMt2d4r8cPzoX3NK_HQ,4495
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=PGtg4v5lUvkXXl1Y8E6a3Mf8hEfxfhBrslPs_H_Lq_E,16564
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=qTYxpErHw327JdESr4Biv-H89iZRXzBcllamrFu8P_k,5587
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=vEqY7VBOAvtI4uwys6_E1FT9j4bkHJM21OYaT51ahe8,4800
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=Xv4MuuOyoamvT3IEJX4mynvLEycgtZ9LWt6Nm764KXE,6980
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=SRIsPr6xb6xX7GHyrYYNBbt9-l6os29rQndmoXnr5W0,8707
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=cEQHf8bTcgA3hLMgsbMGSXhCmccmxWLQ6oOJiINR3ac,8257
28
- notionary/core/database/notion_database_manager_factory.py,sha256=SoWUiM5zdajmR1ppYHTdPgHrdZbwuTMdoXW3_tBffyU,6831
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=O5GBa2KzjAiqH_NDg4JpJbkNcfh3AD5uzTkhqHMr8XE,13635
32
- notionary/core/page/content/page_content_manager.py,sha256=GjgxVwi5NOMsvGwBNj-woq940ZupzALCQegDyIcsgMg,3358
33
- notionary/core/page/metadata/metadata_editor.py,sha256=U3Ff9GRk28dqT9M1xsl6Q3Cj47-hB1n2pNJzeDXy4ks,4938
34
- notionary/core/page/metadata/notion_icon_manager.py,sha256=v9pUG61TOT8x9UzDqBtQW6S5XQzWostq7IwrURnWvF4,1499
35
- notionary/core/page/metadata/notion_page_cover_manager.py,sha256=nDWXeEztKyPscq5dRxIZ6d6IqV7E3vR-Qg1N8KzP_fo,1831
36
- notionary/core/page/properites/database_property_service.py,sha256=z_HTt_HdB75ffYW5XNwfthZrjLEBXYqKrrK-iGHblek,12073
37
- notionary/core/page/properites/page_property_manager.py,sha256=jMiSt9uzr9bKXYhZMg60LVLewp03OFYCeD_qQhKmFT0,6806
38
- notionary/core/page/properites/property_formatter.py,sha256=N7GGf-ecUuMLvgt5T_KxabjmvUN7uJrMYFCL7438AZo,3665
39
- notionary/core/page/properites/property_operation_result.py,sha256=BVje4SnWf2EdWQYH8sv_6rGd2dL0Owsixfn9SuJY0bk,3961
40
- notionary/core/page/properites/property_value_extractor.py,sha256=IG8hKon83CZJ0zYJ-EtgHd2wbjoKOHdA3jB2vmR50Mw,2035
41
- notionary/core/page/relations/notion_page_relation_manager.py,sha256=EHavK75Semzh8d7edI1ubh0SJyD8E0loNWVIsfxGAY4,12685
42
- notionary/core/page/relations/notion_page_title_resolver.py,sha256=bV0ecP2dikr3vbTEXXsx_4jEtQtpQAHvG-wulASqj3o,1679
43
- notionary/core/page/relations/page_database_relation.py,sha256=2WO1HFyIMQwgYoxvxBDUa_iTnJu-Y3Wkzy4JGJ4loME,2420
44
- notionary/core/page/relations/relation_operation_result.py,sha256=XkO4rK0ha_FRsfq_Vlwp4a2cE-dGVPBrVxCXOlWqfwk,5258
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=9XexVGy8jY5iOlueS1MXFWHtRRmZ8js-EO3hT0_wg2E,1381
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.11.dist-info/licenses/LICENSE,sha256=zOm3cRT1qD49eg7vgw95MI79rpUAZa1kRBFwL2FkAr8,1120
51
- notionary-0.1.11.dist-info/METADATA,sha256=3mCAD1Q1IlhUkPaf8NJAfDENEeZlZWjAmp1tN3e8F28,6154
52
- notionary-0.1.11.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
53
- notionary-0.1.11.dist-info/top_level.txt,sha256=fhONa6BMHQXqthx5PanWGbPL0b8rdFqhrJKVLf_adSs,10
54
- notionary-0.1.11.dist-info/RECORD,,
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