notionary 0.3.1__py3-none-any.whl → 0.4.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.
Files changed (201) hide show
  1. notionary/__init__.py +49 -1
  2. notionary/blocks/client.py +37 -11
  3. notionary/blocks/enums.py +0 -6
  4. notionary/blocks/rich_text/markdown_rich_text_converter.py +49 -15
  5. notionary/blocks/rich_text/models.py +13 -4
  6. notionary/blocks/rich_text/name_id_resolver/data_source.py +9 -3
  7. notionary/blocks/rich_text/name_id_resolver/person.py +6 -2
  8. notionary/blocks/rich_text/rich_text_markdown_converter.py +10 -3
  9. notionary/blocks/schemas.py +33 -78
  10. notionary/comments/client.py +19 -6
  11. notionary/comments/factory.py +10 -3
  12. notionary/comments/schemas.py +10 -31
  13. notionary/comments/service.py +12 -4
  14. notionary/data_source/http/data_source_instance_client.py +59 -17
  15. notionary/data_source/properties/schemas.py +156 -115
  16. notionary/data_source/query/builder.py +67 -18
  17. notionary/data_source/query/resolver.py +16 -5
  18. notionary/data_source/query/schema.py +24 -6
  19. notionary/data_source/query/validator.py +18 -6
  20. notionary/data_source/schema/registry.py +31 -12
  21. notionary/data_source/schema/service.py +66 -20
  22. notionary/data_source/schemas.py +2 -2
  23. notionary/data_source/service.py +103 -43
  24. notionary/database/client.py +27 -9
  25. notionary/database/database_metadata_update_client.py +12 -4
  26. notionary/database/schemas.py +2 -2
  27. notionary/database/service.py +14 -9
  28. notionary/exceptions/__init__.py +20 -4
  29. notionary/exceptions/api.py +2 -2
  30. notionary/exceptions/base.py +1 -1
  31. notionary/exceptions/block_parsing.py +9 -5
  32. notionary/exceptions/data_source/builder.py +13 -7
  33. notionary/exceptions/data_source/properties.py +6 -4
  34. notionary/exceptions/file_upload.py +76 -0
  35. notionary/exceptions/properties.py +7 -5
  36. notionary/exceptions/search.py +10 -6
  37. notionary/file_upload/__init__.py +4 -0
  38. notionary/file_upload/client.py +128 -210
  39. notionary/file_upload/config/__init__.py +17 -0
  40. notionary/file_upload/config/config.py +39 -0
  41. notionary/file_upload/config/constants.py +16 -0
  42. notionary/file_upload/file/reader.py +28 -0
  43. notionary/file_upload/query/__init__.py +7 -0
  44. notionary/file_upload/query/builder.py +58 -0
  45. notionary/file_upload/query/models.py +37 -0
  46. notionary/file_upload/schemas.py +80 -0
  47. notionary/file_upload/service.py +182 -291
  48. notionary/file_upload/validation/factory.py +66 -0
  49. notionary/file_upload/validation/impl/file_name_length.py +25 -0
  50. notionary/file_upload/validation/models.py +134 -0
  51. notionary/file_upload/validation/port.py +7 -0
  52. notionary/file_upload/validation/service.py +17 -0
  53. notionary/file_upload/validation/validators/__init__.py +11 -0
  54. notionary/file_upload/validation/validators/file_exists.py +15 -0
  55. notionary/file_upload/validation/validators/file_extension.py +131 -0
  56. notionary/file_upload/validation/validators/file_name_length.py +21 -0
  57. notionary/file_upload/validation/validators/upload_limit.py +31 -0
  58. notionary/http/client.py +33 -30
  59. notionary/page/content/__init__.py +9 -0
  60. notionary/page/content/factory.py +21 -7
  61. notionary/page/content/markdown/builder.py +85 -23
  62. notionary/page/content/markdown/nodes/audio.py +8 -4
  63. notionary/page/content/markdown/nodes/base.py +3 -3
  64. notionary/page/content/markdown/nodes/bookmark.py +5 -3
  65. notionary/page/content/markdown/nodes/breadcrumb.py +2 -2
  66. notionary/page/content/markdown/nodes/bulleted_list.py +5 -3
  67. notionary/page/content/markdown/nodes/callout.py +2 -2
  68. notionary/page/content/markdown/nodes/code.py +5 -3
  69. notionary/page/content/markdown/nodes/columns.py +3 -3
  70. notionary/page/content/markdown/nodes/container.py +9 -5
  71. notionary/page/content/markdown/nodes/divider.py +2 -2
  72. notionary/page/content/markdown/nodes/embed.py +8 -4
  73. notionary/page/content/markdown/nodes/equation.py +4 -2
  74. notionary/page/content/markdown/nodes/file.py +8 -4
  75. notionary/page/content/markdown/nodes/heading.py +2 -2
  76. notionary/page/content/markdown/nodes/image.py +8 -4
  77. notionary/page/content/markdown/nodes/mixins/caption.py +5 -3
  78. notionary/page/content/markdown/nodes/numbered_list.py +5 -3
  79. notionary/page/content/markdown/nodes/paragraph.py +4 -2
  80. notionary/page/content/markdown/nodes/pdf.py +8 -4
  81. notionary/page/content/markdown/nodes/quote.py +2 -2
  82. notionary/page/content/markdown/nodes/space.py +2 -2
  83. notionary/page/content/markdown/nodes/table.py +8 -5
  84. notionary/page/content/markdown/nodes/table_of_contents.py +2 -2
  85. notionary/page/content/markdown/nodes/todo.py +15 -7
  86. notionary/page/content/markdown/nodes/toggle.py +2 -2
  87. notionary/page/content/markdown/nodes/video.py +8 -4
  88. notionary/page/content/markdown/structured_output/__init__.py +73 -0
  89. notionary/page/content/markdown/structured_output/models.py +391 -0
  90. notionary/page/content/markdown/structured_output/service.py +211 -0
  91. notionary/page/content/parser/context.py +1 -1
  92. notionary/page/content/parser/factory.py +26 -8
  93. notionary/page/content/parser/parsers/audio.py +12 -32
  94. notionary/page/content/parser/parsers/base.py +2 -2
  95. notionary/page/content/parser/parsers/bookmark.py +2 -2
  96. notionary/page/content/parser/parsers/breadcrumb.py +2 -2
  97. notionary/page/content/parser/parsers/bulleted_list.py +19 -6
  98. notionary/page/content/parser/parsers/callout.py +15 -5
  99. notionary/page/content/parser/parsers/caption.py +9 -3
  100. notionary/page/content/parser/parsers/code.py +21 -7
  101. notionary/page/content/parser/parsers/column.py +8 -4
  102. notionary/page/content/parser/parsers/column_list.py +19 -7
  103. notionary/page/content/parser/parsers/divider.py +2 -2
  104. notionary/page/content/parser/parsers/embed.py +2 -4
  105. notionary/page/content/parser/parsers/equation.py +8 -4
  106. notionary/page/content/parser/parsers/file.py +12 -34
  107. notionary/page/content/parser/parsers/file_like_block.py +109 -0
  108. notionary/page/content/parser/parsers/heading.py +31 -10
  109. notionary/page/content/parser/parsers/image.py +12 -34
  110. notionary/page/content/parser/parsers/numbered_list.py +18 -6
  111. notionary/page/content/parser/parsers/paragraph.py +3 -1
  112. notionary/page/content/parser/parsers/pdf.py +12 -34
  113. notionary/page/content/parser/parsers/quote.py +28 -9
  114. notionary/page/content/parser/parsers/space.py +2 -2
  115. notionary/page/content/parser/parsers/table.py +31 -10
  116. notionary/page/content/parser/parsers/table_of_contents.py +7 -3
  117. notionary/page/content/parser/parsers/todo.py +15 -5
  118. notionary/page/content/parser/parsers/toggle.py +15 -5
  119. notionary/page/content/parser/parsers/video.py +12 -34
  120. notionary/page/content/parser/post_processing/handlers/rich_text_length.py +8 -2
  121. notionary/page/content/parser/post_processing/handlers/rich_text_length_truncation.py +8 -2
  122. notionary/page/content/parser/post_processing/service.py +3 -1
  123. notionary/page/content/parser/pre_processsing/handlers/column_syntax.py +21 -7
  124. notionary/page/content/parser/pre_processsing/handlers/indentation.py +11 -4
  125. notionary/page/content/parser/pre_processsing/handlers/video_syntax.py +13 -6
  126. notionary/page/content/parser/service.py +4 -1
  127. notionary/page/content/renderer/context.py +15 -5
  128. notionary/page/content/renderer/factory.py +12 -6
  129. notionary/page/content/renderer/post_processing/handlers/numbered_list.py +19 -9
  130. notionary/page/content/renderer/renderers/audio.py +20 -23
  131. notionary/page/content/renderer/renderers/base.py +3 -3
  132. notionary/page/content/renderer/renderers/bookmark.py +3 -1
  133. notionary/page/content/renderer/renderers/bulleted_list.py +11 -5
  134. notionary/page/content/renderer/renderers/callout.py +19 -7
  135. notionary/page/content/renderer/renderers/captioned_block.py +11 -5
  136. notionary/page/content/renderer/renderers/code.py +6 -2
  137. notionary/page/content/renderer/renderers/column.py +3 -1
  138. notionary/page/content/renderer/renderers/column_list.py +3 -1
  139. notionary/page/content/renderer/renderers/embed.py +3 -1
  140. notionary/page/content/renderer/renderers/equation.py +3 -1
  141. notionary/page/content/renderer/renderers/file.py +20 -23
  142. notionary/page/content/renderer/renderers/file_like_block.py +47 -0
  143. notionary/page/content/renderer/renderers/heading.py +22 -8
  144. notionary/page/content/renderer/renderers/image.py +20 -23
  145. notionary/page/content/renderer/renderers/numbered_list.py +8 -3
  146. notionary/page/content/renderer/renderers/paragraph.py +12 -4
  147. notionary/page/content/renderer/renderers/pdf.py +20 -23
  148. notionary/page/content/renderer/renderers/quote.py +14 -6
  149. notionary/page/content/renderer/renderers/table.py +15 -5
  150. notionary/page/content/renderer/renderers/todo.py +16 -6
  151. notionary/page/content/renderer/renderers/toggle.py +8 -4
  152. notionary/page/content/renderer/renderers/video.py +20 -23
  153. notionary/page/content/renderer/service.py +9 -3
  154. notionary/page/content/service.py +21 -7
  155. notionary/page/content/syntax/definition/__init__.py +11 -0
  156. notionary/page/content/syntax/definition/models.py +57 -0
  157. notionary/page/content/syntax/definition/registry.py +371 -0
  158. notionary/page/content/syntax/prompts/__init__.py +4 -0
  159. notionary/page/content/syntax/prompts/models.py +11 -0
  160. notionary/page/content/syntax/prompts/registry.py +703 -0
  161. notionary/page/page_metadata_update_client.py +12 -4
  162. notionary/page/properties/client.py +46 -16
  163. notionary/page/properties/factory.py +6 -2
  164. notionary/page/properties/{models.py → schemas.py} +93 -107
  165. notionary/page/properties/service.py +111 -37
  166. notionary/page/schemas.py +3 -3
  167. notionary/page/service.py +21 -7
  168. notionary/shared/entity/client.py +6 -2
  169. notionary/shared/entity/dto_parsers.py +4 -37
  170. notionary/shared/entity/entity_metadata_update_client.py +25 -5
  171. notionary/shared/entity/schemas.py +6 -6
  172. notionary/shared/entity/service.py +89 -35
  173. notionary/shared/models/file.py +36 -6
  174. notionary/shared/models/icon.py +5 -12
  175. notionary/user/base.py +6 -2
  176. notionary/user/bot.py +22 -14
  177. notionary/user/client.py +3 -1
  178. notionary/user/person.py +3 -1
  179. notionary/user/schemas.py +3 -1
  180. notionary/user/service.py +6 -2
  181. notionary/utils/decorators.py +13 -9
  182. notionary/utils/fuzzy.py +6 -2
  183. notionary/utils/mixins/logging.py +3 -1
  184. notionary/utils/pagination.py +14 -4
  185. notionary/workspace/__init__.py +6 -2
  186. notionary/workspace/query/__init__.py +2 -1
  187. notionary/workspace/query/service.py +42 -13
  188. notionary/workspace/service.py +74 -46
  189. {notionary-0.3.1.dist-info → notionary-0.4.1.dist-info}/METADATA +1 -1
  190. notionary-0.4.1.dist-info/RECORD +236 -0
  191. notionary/file_upload/models.py +0 -69
  192. notionary/page/blocks/client.py +0 -1
  193. notionary/page/content/syntax/__init__.py +0 -4
  194. notionary/page/content/syntax/models.py +0 -66
  195. notionary/page/content/syntax/registry.py +0 -393
  196. notionary/page/page_context.py +0 -50
  197. notionary/shared/models/cover.py +0 -20
  198. notionary-0.3.1.dist-info/RECORD +0 -211
  199. /notionary/page/content/syntax/{grammar.py → definition/grammar.py} +0 -0
  200. {notionary-0.3.1.dist-info → notionary-0.4.1.dist-info}/WHEEL +0 -0
  201. {notionary-0.3.1.dist-info → notionary-0.4.1.dist-info}/licenses/LICENSE +0 -0
@@ -3,14 +3,16 @@ from __future__ import annotations
3
3
  import asyncio
4
4
  from typing import TYPE_CHECKING, Never
5
5
 
6
- from notionary.blocks.rich_text.rich_text_markdown_converter import convert_rich_text_to_markdown
6
+ from notionary.blocks.rich_text.rich_text_markdown_converter import (
7
+ convert_rich_text_to_markdown,
8
+ )
7
9
  from notionary.exceptions.properties import (
8
10
  AccessPagePropertyWithoutDataSourceError,
9
11
  PagePropertyNotFoundError,
10
12
  PagePropertyTypeError,
11
13
  )
12
14
  from notionary.page.properties.client import PagePropertyHttpClient
13
- from notionary.page.properties.models import (
15
+ from notionary.page.properties.schemas import (
14
16
  PageCheckboxProperty,
15
17
  PageCreatedTimeProperty,
16
18
  PageDateProperty,
@@ -68,23 +70,33 @@ class PagePropertyHandler:
68
70
  return await convert_rich_text_to_markdown(title_property.title)
69
71
 
70
72
  def get_values_of_people_property(self, property_name: str) -> list[str]:
71
- people_prop = self._get_typed_property_or_raise(property_name, PagePeopleProperty)
73
+ people_prop = self._get_typed_property_or_raise(
74
+ property_name, PagePeopleProperty
75
+ )
72
76
  return [person.name for person in people_prop.people if person.name]
73
77
 
74
78
  def get_value_of_created_time_property(self, name: str) -> str | None:
75
- created_time_property = self._get_typed_property_or_raise(name, PageCreatedTimeProperty)
79
+ created_time_property = self._get_typed_property_or_raise(
80
+ name, PageCreatedTimeProperty
81
+ )
76
82
  return created_time_property.created_time
77
83
 
78
84
  async def get_values_of_relation_property(self, name: str) -> list[str]:
79
85
  from notionary import NotionPage
80
86
 
81
- relation_property = self._get_typed_property_or_raise(name, PageRelationProperty)
87
+ relation_property = self._get_typed_property_or_raise(
88
+ name, PageRelationProperty
89
+ )
82
90
  relation_page_ids = [rel.id for rel in relation_property.relation]
83
- notion_pages = [await NotionPage.from_id(page_id) for page_id in relation_page_ids]
91
+ notion_pages = [
92
+ await NotionPage.from_id(page_id) for page_id in relation_page_ids
93
+ ]
84
94
  return [page.title for page in notion_pages if page]
85
95
 
86
96
  def get_values_of_multiselect_property(self, name: str) -> list[str]:
87
- multiselect_property = self._get_typed_property_or_raise(name, PageMultiSelectProperty)
97
+ multiselect_property = self._get_typed_property_or_raise(
98
+ name, PageMultiSelectProperty
99
+ )
88
100
  return [option.name for option in multiselect_property.multi_select]
89
101
 
90
102
  def get_value_of_url_property(self, name: str) -> str | None:
@@ -96,7 +108,9 @@ class PagePropertyHandler:
96
108
  return number_property.number
97
109
 
98
110
  def get_value_of_checkbox_property(self, name: str) -> bool:
99
- checkbox_property = self._get_typed_property_or_raise(name, PageCheckboxProperty)
111
+ checkbox_property = self._get_typed_property_or_raise(
112
+ name, PageCheckboxProperty
113
+ )
100
114
  return checkbox_property.checkbox
101
115
 
102
116
  def get_value_of_date_property(self, name: str) -> str | None:
@@ -104,7 +118,9 @@ class PagePropertyHandler:
104
118
  return date_property.date.start if date_property.date else None
105
119
 
106
120
  async def get_value_of_rich_text_property(self, name: str) -> str:
107
- rich_text_property = self._get_typed_property_or_raise(name, PageRichTextProperty)
121
+ rich_text_property = self._get_typed_property_or_raise(
122
+ name, PageRichTextProperty
123
+ )
108
124
  return await convert_rich_text_to_markdown(rich_text_property.rich_text)
109
125
 
110
126
  def get_value_of_email_property(self, name: str) -> str | None:
@@ -112,26 +128,36 @@ class PagePropertyHandler:
112
128
  return email_property.email
113
129
 
114
130
  def get_value_of_phone_number_property(self, name: str) -> str | None:
115
- phone_property = self._get_typed_property_or_raise(name, PagePhoneNumberProperty)
131
+ phone_property = self._get_typed_property_or_raise(
132
+ name, PagePhoneNumberProperty
133
+ )
116
134
  return phone_property.phone_number
117
135
 
118
136
  # =========================================================================
119
137
  # Options Getters
120
138
  # =========================================================================
121
139
 
122
- async def get_select_options_by_property_name(self, property_name: str) -> list[str]:
140
+ async def get_select_options_by_property_name(
141
+ self, property_name: str
142
+ ) -> list[str]:
123
143
  data_source = await self._get_parent_data_source_or_raise()
124
144
  return data_source.get_select_options_by_property_name(property_name)
125
145
 
126
- async def get_multi_select_options_by_property_name(self, property_name: str) -> list[str]:
146
+ async def get_multi_select_options_by_property_name(
147
+ self, property_name: str
148
+ ) -> list[str]:
127
149
  data_source = await self._get_parent_data_source_or_raise()
128
150
  return data_source.get_multi_select_options_by_property_name(property_name)
129
151
 
130
- async def get_status_options_by_property_name(self, property_name: str) -> list[str]:
152
+ async def get_status_options_by_property_name(
153
+ self, property_name: str
154
+ ) -> list[str]:
131
155
  data_source = await self._get_parent_data_source_or_raise()
132
156
  return data_source.get_status_options_by_property_name(property_name)
133
157
 
134
- async def get_relation_options_by_property_name(self, property_name: str) -> list[str]:
158
+ async def get_relation_options_by_property_name(
159
+ self, property_name: str
160
+ ) -> list[str]:
135
161
  data_source = await self._get_parent_data_source_or_raise()
136
162
  return await data_source.get_relation_options_by_property_name(property_name)
137
163
 
@@ -151,7 +177,9 @@ class PagePropertyHandler:
151
177
  title_property_name = self._extract_title_property_name()
152
178
 
153
179
  self._get_typed_property_or_raise(title_property_name, PageTitleProperty)
154
- updated_page = await self._property_http_client.patch_title(title_property_name, title)
180
+ updated_page = await self._property_http_client.patch_title(
181
+ title_property_name, title
182
+ )
155
183
  self._properties = updated_page.properties
156
184
 
157
185
  def _extract_title_property_name(self) -> str | None:
@@ -159,64 +187,104 @@ class PagePropertyHandler:
159
187
  return None
160
188
 
161
189
  return next(
162
- (key for key, prop in self._properties.items() if isinstance(prop, PageTitleProperty)),
190
+ (
191
+ key
192
+ for key, prop in self._properties.items()
193
+ if isinstance(prop, PageTitleProperty)
194
+ ),
163
195
  None,
164
196
  )
165
197
 
166
198
  async def set_rich_text_property(self, property_name: str, text: str) -> None:
167
199
  self._get_typed_property_or_raise(property_name, PageRichTextProperty)
168
- updated_page = await self._property_http_client.patch_rich_text_property(property_name, text)
200
+ updated_page = await self._property_http_client.patch_rich_text_property(
201
+ property_name, text
202
+ )
169
203
  self._properties = updated_page.properties
170
204
 
171
205
  async def set_url_property(self, property_name: str, url: str) -> None:
172
206
  self._get_typed_property_or_raise(property_name, PageURLProperty)
173
- updated_page = await self._property_http_client.patch_url_property(property_name, url)
207
+ updated_page = await self._property_http_client.patch_url_property(
208
+ property_name, url
209
+ )
174
210
  self._properties = updated_page.properties
175
211
 
176
212
  async def set_email_property(self, property_name: str, email: str) -> None:
177
213
  self._get_typed_property_or_raise(property_name, PageEmailProperty)
178
- updated_page = await self._property_http_client.patch_email_property(property_name, email)
214
+ updated_page = await self._property_http_client.patch_email_property(
215
+ property_name, email
216
+ )
179
217
  self._properties = updated_page.properties
180
218
 
181
- async def set_phone_number_property(self, property_name: str, phone_number: str) -> None:
219
+ async def set_phone_number_property(
220
+ self, property_name: str, phone_number: str
221
+ ) -> None:
182
222
  self._get_typed_property_or_raise(property_name, PagePhoneNumberProperty)
183
- updated_page = await self._property_http_client.patch_phone_property(property_name, phone_number)
223
+ updated_page = await self._property_http_client.patch_phone_property(
224
+ property_name, phone_number
225
+ )
184
226
  self._properties = updated_page.properties
185
227
 
186
- async def set_number_property(self, property_name: str, number: int | float) -> None:
228
+ async def set_number_property(
229
+ self, property_name: str, number: int | float
230
+ ) -> None:
187
231
  self._get_typed_property_or_raise(property_name, PageNumberProperty)
188
- updated_page = await self._property_http_client.patch_number_property(property_name, number)
232
+ updated_page = await self._property_http_client.patch_number_property(
233
+ property_name, number
234
+ )
189
235
  self._properties = updated_page.properties
190
236
 
191
237
  async def set_checkbox_property(self, property_name: str, checked: bool) -> None:
192
238
  self._get_typed_property_or_raise(property_name, PageCheckboxProperty)
193
- updated_page = await self._property_http_client.patch_checkbox_property(property_name, checked)
239
+ updated_page = await self._property_http_client.patch_checkbox_property(
240
+ property_name, checked
241
+ )
194
242
  self._properties = updated_page.properties
195
243
 
196
- async def set_date_property(self, property_name: str, date_value: str | dict) -> None:
244
+ async def set_date_property(
245
+ self, property_name: str, date_value: str | dict
246
+ ) -> None:
197
247
  self._get_typed_property_or_raise(property_name, PageDateProperty)
198
- updated_page = await self._property_http_client.patch_date_property(property_name, date_value)
248
+ updated_page = await self._property_http_client.patch_date_property(
249
+ property_name, date_value
250
+ )
199
251
  self._properties = updated_page.properties
200
252
 
201
- async def set_select_property_by_option_name(self, property_name: str, option_name: str) -> None:
253
+ async def set_select_property_by_option_name(
254
+ self, property_name: str, option_name: str
255
+ ) -> None:
202
256
  self._get_typed_property_or_raise(property_name, PageSelectProperty)
203
- updated_page = await self._property_http_client.patch_select_property(property_name, option_name)
257
+ updated_page = await self._property_http_client.patch_select_property(
258
+ property_name, option_name
259
+ )
204
260
  self._properties = updated_page.properties
205
261
 
206
- async def set_multi_select_property_by_option_names(self, property_name: str, option_names: list[str]) -> None:
262
+ async def set_multi_select_property_by_option_names(
263
+ self, property_name: str, option_names: list[str]
264
+ ) -> None:
207
265
  self._get_typed_property_or_raise(property_name, PageMultiSelectProperty)
208
- updated_page = await self._property_http_client.patch_multi_select_property(property_name, option_names)
266
+ updated_page = await self._property_http_client.patch_multi_select_property(
267
+ property_name, option_names
268
+ )
209
269
  self._properties = updated_page.properties
210
270
 
211
- async def set_status_property_by_option_name(self, property_name: str, status: str) -> None:
271
+ async def set_status_property_by_option_name(
272
+ self, property_name: str, status: str
273
+ ) -> None:
212
274
  self._get_typed_property_or_raise(property_name, PageStatusProperty)
213
- updated_page = await self._property_http_client.patch_status_property(property_name, status)
275
+ updated_page = await self._property_http_client.patch_status_property(
276
+ property_name, status
277
+ )
214
278
  self._properties = updated_page.properties
215
279
 
216
- async def set_relation_property_by_page_titles(self, property_name: str, page_titles: list[str]) -> None:
280
+ async def set_relation_property_by_page_titles(
281
+ self, property_name: str, page_titles: list[str]
282
+ ) -> None:
217
283
  self._get_typed_property_or_raise(property_name, PageRelationProperty)
218
284
  relation_ids = await self._convert_page_titles_to_ids(page_titles)
219
- updated_page = await self._property_http_client.patch_relation_property(property_name, relation_ids)
285
+ updated_page = await self._property_http_client.patch_relation_property(
286
+ property_name, relation_ids
287
+ )
220
288
  self._properties = updated_page.properties
221
289
 
222
290
  async def _ensure_data_source_loaded(self) -> None:
@@ -226,7 +294,9 @@ class PagePropertyHandler:
226
294
  return
227
295
 
228
296
  self._parent_data_source = (
229
- await NotionDataSource.from_id(self._parent_data_source_id) if self._parent_data_source_id else None
297
+ await NotionDataSource.from_id(self._parent_data_source_id)
298
+ if self._parent_data_source_id
299
+ else None
230
300
  )
231
301
  self._data_source_loaded = True
232
302
 
@@ -237,7 +307,9 @@ class PagePropertyHandler:
237
307
  raise AccessPagePropertyWithoutDataSourceError(self._parent_type)
238
308
  return self._parent_data_source
239
309
 
240
- def _get_typed_property_or_raise(self, name: str, property_type: type[PagePropertyT]) -> PagePropertyT:
310
+ def _get_typed_property_or_raise(
311
+ self, name: str, property_type: type[PagePropertyT]
312
+ ) -> PagePropertyT:
241
313
  prop = self._properties.get(name)
242
314
 
243
315
  if prop is None:
@@ -267,6 +339,8 @@ class PagePropertyHandler:
267
339
  if not page_titles:
268
340
  return []
269
341
 
270
- pages = await asyncio.gather(*[NotionPage.from_title(title=title) for title in page_titles])
342
+ pages = await asyncio.gather(
343
+ *[NotionPage.from_title(title=title) for title in page_titles]
344
+ )
271
345
 
272
346
  return [page.id for page in pages if page]
notionary/page/schemas.py CHANGED
@@ -1,13 +1,13 @@
1
1
  from pydantic import BaseModel
2
2
 
3
- from notionary.page.properties.models import DiscriminatedPageProperty
3
+ from notionary.page.properties.schemas import AnyPageProperty
4
4
  from notionary.shared.entity.schemas import EntityResponseDto
5
5
 
6
6
 
7
7
  class NotionPageDto(EntityResponseDto):
8
8
  archived: bool
9
- properties: dict[str, DiscriminatedPageProperty]
9
+ properties: dict[str, AnyPageProperty]
10
10
 
11
11
 
12
12
  class PgePropertiesUpdateDto(BaseModel):
13
- properties: dict[str, DiscriminatedPageProperty]
13
+ properties: dict[str, AnyPageProperty]
notionary/page/service.py CHANGED
@@ -2,7 +2,9 @@ from collections.abc import Callable
2
2
  from typing import Self
3
3
 
4
4
  from notionary.blocks.client import NotionBlockHttpClient
5
- from notionary.blocks.rich_text.rich_text_markdown_converter import convert_rich_text_to_markdown
5
+ from notionary.blocks.rich_text.rich_text_markdown_converter import (
6
+ convert_rich_text_to_markdown,
7
+ )
6
8
  from notionary.comments.models import Comment
7
9
  from notionary.comments.service import CommentService
8
10
  from notionary.page.content.factory import PageContentServiceFactory
@@ -11,7 +13,7 @@ from notionary.page.content.service import PageContentService
11
13
  from notionary.page.page_http_client import NotionPageHttpClient
12
14
  from notionary.page.page_metadata_update_client import PageMetadataUpdateClient
13
15
  from notionary.page.properties.factory import PagePropertyHandlerFactory
14
- from notionary.page.properties.models import PageTitleProperty
16
+ from notionary.page.properties.schemas import PageTitleProperty
15
17
  from notionary.page.properties.service import PagePropertyHandler
16
18
  from notionary.page.schemas import NotionPageDto
17
19
  from notionary.shared.entity.service import Entity
@@ -71,7 +73,9 @@ class NotionPage(Entity):
71
73
  page_property_handler_factory: PagePropertyHandlerFactory,
72
74
  ) -> Self:
73
75
  title_task = cls._extract_title_from_dto(dto)
74
- page_property_handler = page_property_handler_factory.create_from_page_response(dto)
76
+ page_property_handler = page_property_handler_factory.create_from_page_response(
77
+ dto
78
+ )
75
79
 
76
80
  title = await title_task
77
81
 
@@ -92,7 +96,9 @@ class NotionPage(Entity):
92
96
  comment_service = CommentService()
93
97
 
94
98
  page_content_service_factory = PageContentServiceFactory()
95
- page_content_service = page_content_service_factory.create(page_id=dto.id, block_client=block_client)
99
+ page_content_service = page_content_service_factory.create(
100
+ page_id=dto.id, block_client=block_client
101
+ )
96
102
 
97
103
  metadata_update_client = PageMetadataUpdateClient(page_id=dto.id)
98
104
 
@@ -109,7 +115,11 @@ class NotionPage(Entity):
109
115
  @staticmethod
110
116
  async def _extract_title_from_dto(response: NotionPageDto) -> str:
111
117
  title_property = next(
112
- (prop for prop in response.properties.values() if isinstance(prop, PageTitleProperty)),
118
+ (
119
+ prop
120
+ for prop in response.properties.values()
121
+ if isinstance(prop, PageTitleProperty)
122
+ ),
113
123
  None,
114
124
  )
115
125
  rich_text_title = title_property.title if title_property else []
@@ -135,10 +145,14 @@ class NotionPage(Entity):
135
145
  return await self._comment_service.list_all_comments_for_page(page_id=self._id)
136
146
 
137
147
  async def post_top_level_comment(self, comment: str) -> None:
138
- await self._comment_service.create_comment_on_page(page_id=self._id, text=comment)
148
+ await self._comment_service.create_comment_on_page(
149
+ page_id=self._id, text=comment
150
+ )
139
151
 
140
152
  async def post_reply_to_discussion(self, discussion_id: str, comment: str) -> None:
141
- await self._comment_service.reply_to_discussion_by_id(discussion_id=discussion_id, text=comment)
153
+ await self._comment_service.reply_to_discussion_by_id(
154
+ discussion_id=discussion_id, text=comment
155
+ )
142
156
 
143
157
  async def set_title(self, title: str) -> None:
144
158
  await self.properties.set_title_property(title)
@@ -1,7 +1,9 @@
1
1
  from typing import TypeVar, override
2
2
 
3
3
  from notionary.http.client import NotionHttpClient
4
- from notionary.shared.entity.entity_metadata_update_client import EntityMetadataUpdateClient
4
+ from notionary.shared.entity.entity_metadata_update_client import (
5
+ EntityMetadataUpdateClient,
6
+ )
5
7
  from notionary.shared.entity.schemas import EntityResponseDto, NotionEntityUpdateDto
6
8
 
7
9
  ResponseType = TypeVar("ResponseType", bound=EntityResponseDto)
@@ -22,7 +24,9 @@ class GenericEntityMetadataUpdateClient(NotionHttpClient, EntityMetadataUpdateCl
22
24
 
23
25
  @override
24
26
  async def patch_metadata(self, updated_data: NotionEntityUpdateDto) -> ResponseType:
25
- updated_data_dict = updated_data.model_dump(exclude_unset=True, exclude_none=True)
27
+ updated_data_dict = updated_data.model_dump(
28
+ exclude_unset=True, exclude_none=True
29
+ )
26
30
  url = f"{self._path_segment}/{self._entity_id}"
27
31
 
28
32
  response_dict = await self.patch(url, data=updated_data_dict)
@@ -1,40 +1,7 @@
1
- from typing import cast
2
-
3
- from notionary.blocks.rich_text.rich_text_markdown_converter import RichTextToMarkdownConverter
4
- from notionary.shared.entity.schemas import Describable, EntityResponseDto, Titled
5
- from notionary.shared.models.cover import CoverType
6
- from notionary.shared.models.icon import IconType
7
- from notionary.shared.models.parent import DatabaseParent, DataSourceParent, ParentType
8
-
9
-
10
- def extract_emoji_icon_from_dto(entity_dto: EntityResponseDto) -> str | None:
11
- if not entity_dto.icon or entity_dto.icon.type != IconType.EMOJI:
12
- return None
13
- return entity_dto.icon.emoji
14
-
15
-
16
- def extract_external_icon_url_from_dto(entity_dto: EntityResponseDto) -> str | None:
17
- if not entity_dto.icon or entity_dto.icon.type != IconType.EXTERNAL:
18
- return None
19
- return entity_dto.icon.external.url if entity_dto.icon.external else None
20
-
21
-
22
- def extract_cover_image_url_from_dto(entity_dto: EntityResponseDto) -> str | None:
23
- if not entity_dto.cover or entity_dto.cover.type != CoverType.EXTERNAL:
24
- return None
25
- return entity_dto.cover.external.url if entity_dto.cover.external else None
26
-
27
-
28
- def extract_database_id(entity_dto: EntityResponseDto) -> str | None:
29
- if entity_dto.parent.type == ParentType.DATA_SOURCE_ID:
30
- data_source_parent = cast(DataSourceParent, entity_dto.parent)
31
- return data_source_parent.database_id if data_source_parent else None
32
-
33
- if entity_dto.parent.type == ParentType.DATABASE_ID:
34
- database_parent = cast(DatabaseParent, entity_dto.parent)
35
- return database_parent.database_id if database_parent else None
36
-
37
- return None
1
+ from notionary.blocks.rich_text.rich_text_markdown_converter import (
2
+ RichTextToMarkdownConverter,
3
+ )
4
+ from notionary.shared.entity.schemas import Describable, Titled
38
5
 
39
6
 
40
7
  async def extract_title(
@@ -1,13 +1,15 @@
1
1
  from abc import ABC, abstractmethod
2
2
 
3
3
  from notionary.shared.entity.schemas import EntityResponseDto, NotionEntityUpdateDto
4
- from notionary.shared.models.cover import NotionCover
5
- from notionary.shared.models.icon import EmojiIcon, ExternalIcon
4
+ from notionary.shared.models.file import ExternalFile, FileUploadFile
5
+ from notionary.shared.models.icon import EmojiIcon, Icon
6
6
 
7
7
 
8
8
  class EntityMetadataUpdateClient(ABC):
9
9
  @abstractmethod
10
- async def patch_metadata(self, updated_data: NotionEntityUpdateDto) -> EntityResponseDto: ...
10
+ async def patch_metadata(
11
+ self, updated_data: NotionEntityUpdateDto
12
+ ) -> EntityResponseDto: ...
11
13
 
12
14
  async def patch_emoji_icon(self, emoji: str) -> EntityResponseDto:
13
15
  icon = EmojiIcon(emoji=emoji)
@@ -15,7 +17,16 @@ class EntityMetadataUpdateClient(ABC):
15
17
  return await self.patch_metadata(update_dto)
16
18
 
17
19
  async def patch_external_icon(self, icon_url: str) -> EntityResponseDto:
18
- icon = ExternalIcon.from_url(icon_url)
20
+ icon = ExternalFile.from_url(icon_url)
21
+ return await self._patch_icon(icon)
22
+
23
+ async def patch_icon_from_file_upload(
24
+ self, file_upload_id: str
25
+ ) -> EntityResponseDto:
26
+ icon = FileUploadFile.from_id(id=file_upload_id)
27
+ return await self._patch_icon(icon)
28
+
29
+ async def _patch_icon(self, icon: Icon) -> EntityResponseDto:
19
30
  update_dto = NotionEntityUpdateDto(icon=icon)
20
31
  return await self.patch_metadata(update_dto)
21
32
 
@@ -24,7 +35,16 @@ class EntityMetadataUpdateClient(ABC):
24
35
  return await self.patch_metadata(update_dto)
25
36
 
26
37
  async def patch_external_cover(self, cover_url: str) -> EntityResponseDto:
27
- cover = NotionCover.from_url(cover_url)
38
+ cover = ExternalFile.from_url(cover_url)
39
+ return await self._patch_cover(cover)
40
+
41
+ async def patch_cover_from_file_upload(
42
+ self, file_upload_id: str
43
+ ) -> EntityResponseDto:
44
+ cover = FileUploadFile.from_id(id=file_upload_id)
45
+ return await self._patch_cover(cover)
46
+
47
+ async def _patch_cover(self, cover: Icon) -> EntityResponseDto:
28
48
  update_dto = NotionEntityUpdateDto(cover=cover)
29
49
  return await self.patch_metadata(update_dto)
30
50
 
@@ -4,26 +4,26 @@ from typing import Protocol
4
4
  from pydantic import BaseModel
5
5
 
6
6
  from notionary.blocks.rich_text.models import RichText
7
- from notionary.shared.models.cover import NotionCover
7
+ from notionary.shared.models.file import File
8
8
  from notionary.shared.models.icon import Icon
9
9
  from notionary.shared.models.parent import Parent
10
10
  from notionary.user.schemas import PartialUserDto
11
11
 
12
12
 
13
- class EntityWorkspaceQueryObjectType(StrEnum):
13
+ class _EntityType(StrEnum):
14
14
  PAGE = "page"
15
15
  DATA_SOURCE = "data_source"
16
16
  DATABASE = "database"
17
17
 
18
18
 
19
19
  class EntityResponseDto(BaseModel):
20
- object: EntityWorkspaceQueryObjectType
20
+ object: _EntityType
21
21
  id: str
22
22
  created_time: str
23
23
  created_by: PartialUserDto
24
24
  last_edited_time: str
25
25
  last_edited_by: PartialUserDto
26
- cover: NotionCover | None = None
26
+ cover: File | None = None
27
27
  icon: Icon | None = None
28
28
  parent: Parent
29
29
  in_trash: bool
@@ -32,8 +32,8 @@ class EntityResponseDto(BaseModel):
32
32
 
33
33
 
34
34
  class NotionEntityUpdateDto(BaseModel):
35
- icon: Icon | None = None
36
- cover: NotionCover | None = None
35
+ icon: File | None = None
36
+ cover: File | None = None
37
37
  in_trash: bool | None = None
38
38
 
39
39