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
@@ -2,7 +2,9 @@ from typing import override
2
2
 
3
3
  from notionary.http.client import NotionHttpClient
4
4
  from notionary.page.schemas import NotionPageDto
5
- from notionary.shared.entity.entity_metadata_update_client import EntityMetadataUpdateClient
5
+ from notionary.shared.entity.entity_metadata_update_client import (
6
+ EntityMetadataUpdateClient,
7
+ )
6
8
  from notionary.shared.entity.schemas import NotionEntityUpdateDto
7
9
 
8
10
 
@@ -12,8 +14,14 @@ class PageMetadataUpdateClient(NotionHttpClient, EntityMetadataUpdateClient):
12
14
  self._page_id = page_id
13
15
 
14
16
  @override
15
- async def patch_metadata(self, updated_data: NotionEntityUpdateDto) -> NotionPageDto:
16
- updated_data_dict = updated_data.model_dump(exclude_unset=True, exclude_none=True)
17
+ async def patch_metadata(
18
+ self, updated_data: NotionEntityUpdateDto
19
+ ) -> NotionPageDto:
20
+ updated_data_dict = updated_data.model_dump(
21
+ exclude_unset=True, exclude_none=True
22
+ )
17
23
 
18
- response_dict = await self.patch(f"pages/{self._page_id}", data=updated_data_dict)
24
+ response_dict = await self.patch(
25
+ f"pages/{self._page_id}", data=updated_data_dict
26
+ )
19
27
  return NotionPageDto.model_validate(response_dict)
@@ -4,7 +4,7 @@ from pydantic import BaseModel
4
4
 
5
5
  from notionary.blocks.rich_text.models import RichText
6
6
  from notionary.http.client import NotionHttpClient
7
- from notionary.page.properties.models import (
7
+ from notionary.page.properties.schemas import (
8
8
  DateValue,
9
9
  PageCheckboxProperty,
10
10
  PageDateProperty,
@@ -44,7 +44,9 @@ class PagePropertyHttpClient(NotionHttpClient):
44
44
  property_type: type[PagePropertyT],
45
45
  current_property: PagePropertyT | None = None,
46
46
  ) -> NotionPageDto:
47
- updated_property = self._create_updated_property(property_type, current_property, value)
47
+ updated_property = self._create_updated_property(
48
+ property_type, current_property, value
49
+ )
48
50
 
49
51
  properties = {property_name: updated_property}
50
52
  update_dto = PgePropertiesUpdateDto(properties=properties)
@@ -54,40 +56,64 @@ class PagePropertyHttpClient(NotionHttpClient):
54
56
  async def patch_title(self, property_name: str, title: str) -> NotionPageDto:
55
57
  return await self._patch_property(property_name, title, PageTitleProperty)
56
58
 
57
- async def patch_rich_text_property(self, property_name: str, text: str) -> NotionPageDto:
59
+ async def patch_rich_text_property(
60
+ self, property_name: str, text: str
61
+ ) -> NotionPageDto:
58
62
  return await self._patch_property(property_name, text, PageRichTextProperty)
59
63
 
60
64
  async def patch_url_property(self, property_name: str, url: str) -> NotionPageDto:
61
65
  return await self._patch_property(property_name, url, PageURLProperty)
62
66
 
63
- async def patch_email_property(self, property_name: str, email: str) -> NotionPageDto:
67
+ async def patch_email_property(
68
+ self, property_name: str, email: str
69
+ ) -> NotionPageDto:
64
70
  return await self._patch_property(property_name, email, PageEmailProperty)
65
71
 
66
- async def patch_phone_property(self, property_name: str, phone: str) -> NotionPageDto:
72
+ async def patch_phone_property(
73
+ self, property_name: str, phone: str
74
+ ) -> NotionPageDto:
67
75
  return await self._patch_property(property_name, phone, PagePhoneNumberProperty)
68
76
 
69
- async def patch_number_property(self, property_name: str, number: int | float) -> NotionPageDto:
77
+ async def patch_number_property(
78
+ self, property_name: str, number: int | float
79
+ ) -> NotionPageDto:
70
80
  return await self._patch_property(property_name, number, PageNumberProperty)
71
81
 
72
- async def patch_checkbox_property(self, property_name: str, checked: bool) -> NotionPageDto:
82
+ async def patch_checkbox_property(
83
+ self, property_name: str, checked: bool
84
+ ) -> NotionPageDto:
73
85
  return await self._patch_property(property_name, checked, PageCheckboxProperty)
74
86
 
75
- async def patch_select_property(self, property_name: str, value: str) -> NotionPageDto:
87
+ async def patch_select_property(
88
+ self, property_name: str, value: str
89
+ ) -> NotionPageDto:
76
90
  return await self._patch_property(property_name, value, PageSelectProperty)
77
91
 
78
- async def patch_multi_select_property(self, property_name: str, values: list[str]) -> NotionPageDto:
79
- return await self._patch_property(property_name, values, PageMultiSelectProperty)
92
+ async def patch_multi_select_property(
93
+ self, property_name: str, values: list[str]
94
+ ) -> NotionPageDto:
95
+ return await self._patch_property(
96
+ property_name, values, PageMultiSelectProperty
97
+ )
80
98
 
81
- async def patch_date_property(self, property_name: str, date_value: str | dict) -> NotionPageDto:
99
+ async def patch_date_property(
100
+ self, property_name: str, date_value: str | dict
101
+ ) -> NotionPageDto:
82
102
  return await self._patch_property(property_name, date_value, PageDateProperty)
83
103
 
84
- async def patch_status_property(self, property_name: str, status: str) -> NotionPageDto:
104
+ async def patch_status_property(
105
+ self, property_name: str, status: str
106
+ ) -> NotionPageDto:
85
107
  return await self._patch_property(property_name, status, PageStatusProperty)
86
108
 
87
- async def patch_relation_property(self, property_name: str, relation_ids: str | list[str]) -> NotionPageDto:
109
+ async def patch_relation_property(
110
+ self, property_name: str, relation_ids: str | list[str]
111
+ ) -> NotionPageDto:
88
112
  if isinstance(relation_ids, str):
89
113
  relation_ids = [relation_ids]
90
- return await self._patch_property(property_name, relation_ids, PageRelationProperty)
114
+ return await self._patch_property(
115
+ property_name, relation_ids, PageRelationProperty
116
+ )
91
117
 
92
118
  # TODO: Fix this shit here
93
119
  def _create_updated_property(
@@ -126,8 +152,12 @@ class PagePropertyHttpClient(NotionHttpClient):
126
152
  select_option = SelectOption(name=str(value))
127
153
  return PageSelectProperty(id=property_id, select=select_option)
128
154
  elif property_type == PageMultiSelectProperty:
129
- multi_select_options = [SelectOption(id="", name=str(item)) for item in value]
130
- return PageMultiSelectProperty(id=property_id, multi_select=multi_select_options)
155
+ multi_select_options = [
156
+ SelectOption(id="", name=str(item)) for item in value
157
+ ]
158
+ return PageMultiSelectProperty(
159
+ id=property_id, multi_select=multi_select_options
160
+ )
131
161
  elif property_type == PageDateProperty:
132
162
  if isinstance(value, dict) and "start" in value:
133
163
  date_value = DateValue(**value)
@@ -7,12 +7,16 @@ from notionary.shared.models.parent import DataSourceParent, ParentType
7
7
 
8
8
 
9
9
  class PagePropertyHandlerFactory:
10
- def create_from_page_response(self, page_response: NotionPageDto) -> PagePropertyHandler:
10
+ def create_from_page_response(
11
+ self, page_response: NotionPageDto
12
+ ) -> PagePropertyHandler:
11
13
  return PagePropertyHandler(
12
14
  properties=page_response.properties,
13
15
  parent_type=page_response.parent.type,
14
16
  page_url=page_response.url,
15
- page_property_http_client=self._create_http_client(page_id=page_response.id),
17
+ page_property_http_client=self._create_http_client(
18
+ page_id=page_response.id
19
+ ),
16
20
  parent_data_source=self._extract_parent_data_source_id(page_response),
17
21
  )
18
22
 
@@ -1,9 +1,10 @@
1
1
  from enum import StrEnum
2
- from typing import Annotated, Any, Literal, TypeVar
2
+ from typing import Any, Literal, TypeVar
3
3
 
4
- from pydantic import BaseModel, Field
4
+ from pydantic import BaseModel, ConfigDict, Field
5
5
 
6
6
  from notionary.blocks.rich_text.models import RichText
7
+ from notionary.shared.models.file import File
7
8
  from notionary.shared.properties.type import PropertyType
8
9
  from notionary.shared.typings import JsonDict
9
10
  from notionary.user.schemas import PersonUserResponseDto, UserResponseDto
@@ -38,38 +39,6 @@ class DateValue(BaseModel):
38
39
  time_zone: str | None = None
39
40
 
40
41
 
41
- # ============================================================================
42
- # File Models
43
- # ============================================================================
44
-
45
-
46
- class FileType(StrEnum):
47
- EXTERNAL = "external"
48
- FILE = "file"
49
-
50
-
51
- class ExternalFile(BaseModel):
52
- """External file hosted outside of Notion."""
53
-
54
- url: str
55
-
56
-
57
- class NotionFile(BaseModel):
58
- """File uploaded to Notion with expiration."""
59
-
60
- url: str
61
- expiry_time: str
62
-
63
-
64
- class FileObject(BaseModel):
65
- """File object can be external or uploaded to Notion."""
66
-
67
- name: str
68
- type: FileType
69
- external: ExternalFile | None = None
70
- file: NotionFile | None = None
71
-
72
-
73
42
  # ============================================================================
74
43
  # Formula Models
75
44
  # ============================================================================
@@ -142,25 +111,9 @@ class VerificationValue(BaseModel):
142
111
  # ============================================================================
143
112
 
144
113
 
145
- class PageStatusProperty(PageProperty):
146
- type: Literal[PropertyType.STATUS] = PropertyType.STATUS
147
- status: StatusOption | None = None
148
- options: list[StatusOption] = Field(default_factory=list)
149
-
150
- @property
151
- def option_names(self) -> list[str]:
152
- return [option.name for option in self.options]
153
-
154
-
155
- class PageRelationProperty(PageProperty):
156
- type: Literal[PropertyType.RELATION] = PropertyType.RELATION
157
- relation: list[RelationItem] = Field(default_factory=list)
158
- has_more: bool = False
159
-
160
-
161
- class PageURLProperty(PageProperty):
162
- type: Literal[PropertyType.URL] = PropertyType.URL
163
- url: str | None = None
114
+ class PageTitleProperty(PageProperty):
115
+ type: Literal[PropertyType.TITLE] = PropertyType.TITLE
116
+ title: list[RichText] = Field(default_factory=list)
164
117
 
165
118
 
166
119
  class PageRichTextProperty(PageProperty):
@@ -168,6 +121,16 @@ class PageRichTextProperty(PageProperty):
168
121
  rich_text: list[RichText] = Field(default_factory=list)
169
122
 
170
123
 
124
+ class PageSelectProperty(PageProperty):
125
+ type: Literal[PropertyType.SELECT] = PropertyType.SELECT
126
+ select: SelectOption | None = None
127
+ options: list[SelectOption] = Field(default_factory=list)
128
+
129
+ @property
130
+ def option_names(self) -> list[str]:
131
+ return [option.name for option in self.options]
132
+
133
+
171
134
  class PageMultiSelectProperty(PageProperty):
172
135
  type: Literal[PropertyType.MULTI_SELECT] = PropertyType.MULTI_SELECT
173
136
  multi_select: list[SelectOption] = Field(default_factory=list)
@@ -178,19 +141,19 @@ class PageMultiSelectProperty(PageProperty):
178
141
  return [option.name for option in self.options]
179
142
 
180
143
 
181
- class PageSelectProperty(PageProperty):
182
- type: Literal[PropertyType.SELECT] = PropertyType.SELECT
183
- select: SelectOption | None = None
184
- options: list[SelectOption] = Field(default_factory=list)
144
+ class PageStatusProperty(PageProperty):
145
+ type: Literal[PropertyType.STATUS] = PropertyType.STATUS
146
+ status: StatusOption | None = None
147
+ options: list[StatusOption] = Field(default_factory=list)
185
148
 
186
149
  @property
187
150
  def option_names(self) -> list[str]:
188
151
  return [option.name for option in self.options]
189
152
 
190
153
 
191
- class PagePeopleProperty(PageProperty):
192
- type: Literal[PropertyType.PEOPLE] = PropertyType.PEOPLE
193
- people: list[PersonUserResponseDto] = Field(default_factory=list)
154
+ class PageNumberProperty(PageProperty):
155
+ type: Literal[PropertyType.NUMBER] = PropertyType.NUMBER
156
+ number: float | None = None
194
157
 
195
158
 
196
159
  class PageDateProperty(PageProperty):
@@ -198,21 +161,16 @@ class PageDateProperty(PageProperty):
198
161
  date: DateValue | None = None
199
162
 
200
163
 
201
- class PageTitleProperty(PageProperty):
202
- type: Literal[PropertyType.TITLE] = PropertyType.TITLE
203
- title: list[RichText] = Field(default_factory=list)
204
-
205
-
206
- class PageNumberProperty(PageProperty):
207
- type: Literal[PropertyType.NUMBER] = PropertyType.NUMBER
208
- number: float | None = None
209
-
210
-
211
164
  class PageCheckboxProperty(PageProperty):
212
165
  type: Literal[PropertyType.CHECKBOX] = PropertyType.CHECKBOX
213
166
  checkbox: bool = False
214
167
 
215
168
 
169
+ class PageURLProperty(PageProperty):
170
+ type: Literal[PropertyType.URL] = PropertyType.URL
171
+ url: str | None = None
172
+
173
+
216
174
  class PageEmailProperty(PageProperty):
217
175
  type: Literal[PropertyType.EMAIL] = PropertyType.EMAIL
218
176
  email: str | None = None
@@ -223,29 +181,34 @@ class PagePhoneNumberProperty(PageProperty):
223
181
  phone_number: str | None = None
224
182
 
225
183
 
226
- class PageCreatedTimeProperty(PageProperty):
227
- type: Literal[PropertyType.CREATED_TIME] = PropertyType.CREATED_TIME
228
- created_time: str # ISO 8601 datetime - read-only
229
-
230
-
231
- class PageLastEditedTimeProperty(PageProperty):
232
- type: Literal[PropertyType.LAST_EDITED_TIME] = PropertyType.LAST_EDITED_TIME
233
- last_edited_time: str # ISO 8601 datetime - read-only
184
+ class PagePeopleProperty(PageProperty):
185
+ type: Literal[PropertyType.PEOPLE] = PropertyType.PEOPLE
186
+ people: list[PersonUserResponseDto] = Field(default_factory=list)
234
187
 
235
188
 
236
189
  class PageCreatedByProperty(PageProperty):
237
190
  type: Literal[PropertyType.CREATED_BY] = PropertyType.CREATED_BY
238
- created_by: UserResponseDto # User object - read-only
191
+ created_by: UserResponseDto
239
192
 
240
193
 
241
194
  class PageLastEditedByProperty(PageProperty):
242
195
  type: Literal[PropertyType.LAST_EDITED_BY] = PropertyType.LAST_EDITED_BY
243
- last_edited_by: UserResponseDto # User object - read-only
196
+ last_edited_by: UserResponseDto
244
197
 
245
198
 
246
- class PageFilesProperty(PageProperty):
247
- type: Literal[PropertyType.FILES] = PropertyType.FILES
248
- files: list[FileObject] = Field(default_factory=list)
199
+ class PageCreatedTimeProperty(PageProperty):
200
+ type: Literal[PropertyType.CREATED_TIME] = PropertyType.CREATED_TIME
201
+ created_time: str
202
+
203
+
204
+ class PageLastEditedTimeProperty(PageProperty):
205
+ type: Literal[PropertyType.LAST_EDITED_TIME] = PropertyType.LAST_EDITED_TIME
206
+ last_edited_time: str
207
+
208
+
209
+ class PageLastVisitedTimeProperty(PageProperty):
210
+ type: Literal[PropertyType.LAST_VISITED_TIME] = PropertyType.LAST_VISITED_TIME
211
+ last_visited_time: str | None = None
249
212
 
250
213
 
251
214
  class PageFormulaProperty(PageProperty):
@@ -258,14 +221,15 @@ class PageRollupProperty(PageProperty):
258
221
  rollup: RollupValue
259
222
 
260
223
 
261
- class PageUniqueIdProperty(PageProperty):
262
- type: Literal[PropertyType.UNIQUE_ID] = PropertyType.UNIQUE_ID
263
- unique_id: UniqueIdValue
224
+ class PageFilesProperty(PageProperty):
225
+ type: Literal[PropertyType.FILES] = PropertyType.FILES
226
+ files: list[File] = Field(default_factory=list)
264
227
 
265
228
 
266
- class PageVerificationProperty(PageProperty):
267
- type: Literal[PropertyType.VERIFICATION] = PropertyType.VERIFICATION
268
- verification: VerificationValue
229
+ class PageRelationProperty(PageProperty):
230
+ type: Literal[PropertyType.RELATION] = PropertyType.RELATION
231
+ relation: list[RelationItem] = Field(default_factory=list)
232
+ has_more: bool = False
269
233
 
270
234
 
271
235
  class PageButtonProperty(PageProperty):
@@ -273,36 +237,58 @@ class PageButtonProperty(PageProperty):
273
237
  button: JsonDict = Field(default_factory=dict)
274
238
 
275
239
 
276
- # ============================================================================
277
- # Discriminated Union
278
- # ============================================================================
240
+ class PageLocationProperty(PageProperty):
241
+ type: Literal[PropertyType.LOCATION] = PropertyType.LOCATION
242
+ location: JsonDict | None = None
279
243
 
280
244
 
281
- DiscriminatedPageProperty = Annotated[
282
- PageStatusProperty
283
- | PageRelationProperty
284
- | PageURLProperty
245
+ class PagePlaceProperty(PageProperty):
246
+ type: Literal[PropertyType.PLACE] = PropertyType.PLACE
247
+ place: JsonDict | None = None
248
+
249
+
250
+ class PageVerificationProperty(PageProperty):
251
+ type: Literal[PropertyType.VERIFICATION] = PropertyType.VERIFICATION
252
+ verification: VerificationValue
253
+
254
+
255
+ class PageUniqueIdProperty(PageProperty):
256
+ type: Literal[PropertyType.UNIQUE_ID] = PropertyType.UNIQUE_ID
257
+ unique_id: UniqueIdValue
258
+
259
+
260
+ class PageUnknownProperty(PageProperty):
261
+ model_config = ConfigDict(extra="allow")
262
+
263
+
264
+ type AnyPageProperty = (
265
+ PageTitleProperty
285
266
  | PageRichTextProperty
286
- | PageMultiSelectProperty
287
267
  | PageSelectProperty
288
- | PagePeopleProperty
289
- | PageDateProperty
290
- | PageTitleProperty
268
+ | PageMultiSelectProperty
269
+ | PageStatusProperty
291
270
  | PageNumberProperty
271
+ | PageDateProperty
292
272
  | PageCheckboxProperty
273
+ | PageURLProperty
293
274
  | PageEmailProperty
294
275
  | PagePhoneNumberProperty
295
- | PageCreatedTimeProperty
296
- | PageLastEditedTimeProperty
276
+ | PagePeopleProperty
297
277
  | PageCreatedByProperty
298
278
  | PageLastEditedByProperty
299
- | PageFilesProperty
279
+ | PageCreatedTimeProperty
280
+ | PageLastEditedTimeProperty
281
+ | PageLastVisitedTimeProperty
300
282
  | PageFormulaProperty
301
283
  | PageRollupProperty
302
- | PageUniqueIdProperty
284
+ | PageFilesProperty
285
+ | PageRelationProperty
286
+ | PageButtonProperty
287
+ | PageLocationProperty
288
+ | PagePlaceProperty
303
289
  | PageVerificationProperty
304
- | PageButtonProperty,
305
- Field(discriminator="type"),
306
- ]
290
+ | PageUniqueIdProperty
291
+ | PageUnknownProperty
292
+ )
307
293
 
308
294
  PagePropertyT = TypeVar("PagePropertyT", bound=PageProperty)