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
@@ -1,4 +1,6 @@
1
- from notionary.blocks.rich_text.rich_text_markdown_converter import RichTextToMarkdownConverter
1
+ from notionary.blocks.rich_text.rich_text_markdown_converter import (
2
+ RichTextToMarkdownConverter,
3
+ )
2
4
  from notionary.database.schemas import (
3
5
  NotionDatabaseDto,
4
6
  NotionDatabaseUpdateDto,
@@ -15,14 +17,20 @@ class NotionDatabaseHttpClient(NotionHttpClient):
15
17
  response = await self.get(f"databases/{self._database_id}")
16
18
  return NotionDatabaseDto.model_validate(response)
17
19
 
18
- async def patch_database(self, update_database_dto: NotionDatabaseUpdateDto) -> NotionDatabaseDto:
20
+ async def patch_database(
21
+ self, update_database_dto: NotionDatabaseUpdateDto
22
+ ) -> NotionDatabaseDto:
19
23
  update_database_dto_dict = update_database_dto.model_dump(exclude_none=True)
20
24
 
21
- response = await self.patch(f"databases/{self._database_id}", data=update_database_dto_dict)
25
+ response = await self.patch(
26
+ f"databases/{self._database_id}", data=update_database_dto_dict
27
+ )
22
28
  return NotionDatabaseDto.model_validate(response)
23
29
 
24
30
  async def update_database_title(self, title: str) -> NotionDatabaseDto:
25
- from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
31
+ from notionary.blocks.rich_text.markdown_rich_text_converter import (
32
+ MarkdownRichTextConverter,
33
+ )
26
34
 
27
35
  markdown_rich_text_formatter = MarkdownRichTextConverter()
28
36
  database_rich_text = await markdown_rich_text_formatter.to_rich_text(title)
@@ -31,13 +39,23 @@ class NotionDatabaseHttpClient(NotionHttpClient):
31
39
  return await self.patch_database(database_title_update_dto)
32
40
 
33
41
  async def update_database_description(self, description: str) -> str:
34
- from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
42
+ from notionary.blocks.rich_text.markdown_rich_text_converter import (
43
+ MarkdownRichTextConverter,
44
+ )
35
45
 
36
46
  markdown_to_rich_text_converter = MarkdownRichTextConverter()
37
- rich_text_description = await markdown_to_rich_text_converter.to_rich_text(description)
47
+ rich_text_description = await markdown_to_rich_text_converter.to_rich_text(
48
+ description
49
+ )
38
50
 
39
- database_description_update_dto = NotionDatabaseUpdateDto(description=rich_text_description)
40
- update_database_response = await self.patch_database(database_description_update_dto)
51
+ database_description_update_dto = NotionDatabaseUpdateDto(
52
+ description=rich_text_description
53
+ )
54
+ update_database_response = await self.patch_database(
55
+ database_description_update_dto
56
+ )
41
57
 
42
58
  rich_text_to_markdown_converter = RichTextToMarkdownConverter()
43
- return await rich_text_to_markdown_converter.to_markdown(update_database_response.description)
59
+ return await rich_text_to_markdown_converter.to_markdown(
60
+ update_database_response.description
61
+ )
@@ -2,7 +2,9 @@ from typing import override
2
2
 
3
3
  from notionary.database.schemas import NotionDatabaseDto
4
4
  from notionary.http.client import NotionHttpClient
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 DatabaseMetadataUpdateClient(NotionHttpClient, EntityMetadataUpdateClient)
12
14
  self._database_id = database_id
13
15
 
14
16
  @override
15
- async def patch_metadata(self, updated_data: NotionEntityUpdateDto) -> NotionDatabaseDto:
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
+ ) -> NotionDatabaseDto:
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"databases/{self._database_id}", data=updated_data_dict)
24
+ response_dict = await self.patch(
25
+ f"databases/{self._database_id}", data=updated_data_dict
26
+ )
19
27
  return NotionDatabaseDto.model_validate(response_dict)
@@ -2,7 +2,7 @@ from pydantic import BaseModel, Field
2
2
 
3
3
  from notionary.blocks.rich_text.models import RichText
4
4
  from notionary.shared.entity.schemas import EntityResponseDto
5
- from notionary.shared.models.cover import NotionCover
5
+ from notionary.shared.models.file import File
6
6
  from notionary.shared.models.icon import Icon
7
7
 
8
8
 
@@ -24,6 +24,6 @@ class NotionDatabaseDto(EntityResponseDto):
24
24
  class NotionDatabaseUpdateDto(BaseModel):
25
25
  title: list[RichText] | None = None
26
26
  icon: Icon | None = None
27
- cover: NotionCover | None = None
27
+ cover: File | None = None
28
28
  archived: bool | None = None
29
29
  description: list[RichText] | None = None
@@ -1,13 +1,15 @@
1
- from __future__ import annotations
2
-
3
1
  import asyncio
4
2
  from collections.abc import Awaitable, Callable
5
3
  from typing import Self
6
4
 
7
- from notionary.blocks.rich_text.rich_text_markdown_converter import RichTextToMarkdownConverter
5
+ from notionary.blocks.rich_text.rich_text_markdown_converter import (
6
+ RichTextToMarkdownConverter,
7
+ )
8
8
  from notionary.data_source.service import NotionDataSource
9
9
  from notionary.database.client import NotionDatabaseHttpClient
10
- from notionary.database.database_metadata_update_client import DatabaseMetadataUpdateClient
10
+ from notionary.database.database_metadata_update_client import (
11
+ DatabaseMetadataUpdateClient,
12
+ )
11
13
  from notionary.database.schemas import NotionDatabaseDto
12
14
  from notionary.shared.entity.dto_parsers import (
13
15
  extract_description,
@@ -16,7 +18,7 @@ from notionary.shared.entity.dto_parsers import (
16
18
  from notionary.shared.entity.service import Entity
17
19
  from notionary.workspace.query.service import WorkspaceQueryService
18
20
 
19
- type DataSourceFactory = Callable[[str], Awaitable[NotionDataSource]]
21
+ type _DataSourceFactory = Callable[[str], Awaitable[NotionDataSource]]
20
22
 
21
23
 
22
24
  class NotionDatabase(Entity):
@@ -73,7 +75,8 @@ class NotionDatabase(Entity):
73
75
  client: NotionDatabaseHttpClient,
74
76
  ) -> Self:
75
77
  title, description = await asyncio.gather(
76
- extract_title(dto, rich_text_converter), extract_description(dto, rich_text_converter)
78
+ extract_title(dto, rich_text_converter),
79
+ extract_description(dto, rich_text_converter),
77
80
  )
78
81
 
79
82
  metadata_update_client = DatabaseMetadataUpdateClient(database_id=dto.id)
@@ -104,7 +107,7 @@ class NotionDatabase(Entity):
104
107
 
105
108
  async def get_data_sources(
106
109
  self,
107
- data_source_factory: DataSourceFactory = NotionDataSource.from_id,
110
+ data_source_factory: _DataSourceFactory = NotionDataSource.from_id,
108
111
  ) -> list[NotionDataSource]:
109
112
  if self._data_sources is None:
110
113
  self._data_sources = await self._load_data_sources(data_source_factory)
@@ -112,7 +115,7 @@ class NotionDatabase(Entity):
112
115
 
113
116
  async def _load_data_sources(
114
117
  self,
115
- data_source_factory: DataSourceFactory,
118
+ data_source_factory: _DataSourceFactory,
116
119
  ) -> list[NotionDataSource]:
117
120
  tasks = [data_source_factory(ds_id) for ds_id in self._data_source_ids]
118
121
  return list(await asyncio.gather(*tasks))
@@ -122,5 +125,7 @@ class NotionDatabase(Entity):
122
125
  self._title = result.title[0].plain_text if result.title else ""
123
126
 
124
127
  async def set_description(self, description: str) -> None:
125
- updated_description = await self.client.update_database_description(description=description)
128
+ updated_description = await self.client.update_database_description(
129
+ description=description
130
+ )
126
131
  self._description = updated_description
@@ -7,10 +7,23 @@ from .api import (
7
7
  NotionServerError,
8
8
  NotionValidationError,
9
9
  )
10
- from .base import NotionaryError
11
- from .block_parsing import InsufficientColumnsError, InvalidColumnRatioSumError, UnsupportedVideoFormatError
10
+ from .base import NotionaryException
11
+ from .block_parsing import (
12
+ InsufficientColumnsError,
13
+ InvalidColumnRatioSumError,
14
+ UnsupportedVideoFormatError,
15
+ )
12
16
  from .data_source import DataSourcePropertyNotFound, DataSourcePropertyTypeError
13
- from .properties import AccessPagePropertyWithoutDataSourceError, PagePropertyNotFoundError, PagePropertyTypeError
17
+ from .file_upload import (
18
+ FileSizeException,
19
+ NoFileExtensionException,
20
+ UnsupportedFileTypeException,
21
+ )
22
+ from .properties import (
23
+ AccessPagePropertyWithoutDataSourceError,
24
+ PagePropertyNotFoundError,
25
+ PagePropertyTypeError,
26
+ )
14
27
  from .search import DatabaseNotFound, DataSourceNotFound, EntityNotFound, PageNotFound
15
28
 
16
29
  __all__ = [
@@ -20,8 +33,10 @@ __all__ = [
20
33
  "DataSourcePropertyTypeError",
21
34
  "DatabaseNotFound",
22
35
  "EntityNotFound",
36
+ "FileSizeException",
23
37
  "InsufficientColumnsError",
24
38
  "InvalidColumnRatioSumError",
39
+ "NoFileExtensionException",
25
40
  "NotionApiError",
26
41
  "NotionAuthenticationError",
27
42
  "NotionConnectionError",
@@ -29,9 +44,10 @@ __all__ = [
29
44
  "NotionResourceNotFoundError",
30
45
  "NotionServerError",
31
46
  "NotionValidationError",
32
- "NotionaryError",
47
+ "NotionaryException",
33
48
  "PageNotFound",
34
49
  "PagePropertyNotFoundError",
35
50
  "PagePropertyTypeError",
51
+ "UnsupportedFileTypeException",
36
52
  "UnsupportedVideoFormatError",
37
53
  ]
@@ -1,7 +1,7 @@
1
- from notionary.exceptions.base import NotionaryError
1
+ from notionary.exceptions.base import NotionaryException
2
2
 
3
3
 
4
- class NotionApiError(NotionaryError):
4
+ class NotionApiError(NotionaryException):
5
5
  def __init__(
6
6
  self,
7
7
  message: str,
@@ -1,2 +1,2 @@
1
- class NotionaryError(Exception):
1
+ class NotionaryException(Exception):
2
2
  pass
@@ -1,19 +1,23 @@
1
- from notionary.exceptions.base import NotionaryError
1
+ from notionary.exceptions.base import NotionaryException
2
2
 
3
3
  RATIO_TOLERANCE = 0.0001
4
4
 
5
5
 
6
- class InsufficientColumnsError(NotionaryError):
6
+ class InsufficientColumnsError(NotionaryException):
7
7
  def __init__(self, column_count: int) -> None:
8
8
  self.column_count = column_count
9
- super().__init__(f"Columns container must contain at least 2 column blocks, but only {column_count} found")
9
+ super().__init__(
10
+ f"Columns container must contain at least 2 column blocks, but only {column_count} found"
11
+ )
10
12
 
11
13
 
12
- class InvalidColumnRatioSumError(NotionaryError):
14
+ class InvalidColumnRatioSumError(NotionaryException):
13
15
  def __init__(self, total: float, tolerance: float = RATIO_TOLERANCE) -> None:
14
16
  self.total = total
15
17
  self.tolerance = tolerance
16
- super().__init__(f"Width ratios must sum to 1.0 (±{tolerance}), but sum is {total}")
18
+ super().__init__(
19
+ f"Width ratios must sum to 1.0 (±{tolerance}), but sum is {total}"
20
+ )
17
21
 
18
22
 
19
23
  class UnsupportedVideoFormatError(ValueError):
@@ -8,11 +8,11 @@ from notionary.data_source.query.schema import (
8
8
  Operator,
9
9
  StringOperator,
10
10
  )
11
- from notionary.exceptions.base import NotionaryError
11
+ from notionary.exceptions.base import NotionaryException
12
12
  from notionary.shared.properties.type import PropertyType
13
13
 
14
14
 
15
- class QueryBuilderError(NotionaryError):
15
+ class QueryBuilderError(NotionaryException):
16
16
  def __init__(self, message: str, property_name: str | None = None) -> None:
17
17
  self.property_name = property_name
18
18
  super().__init__(message)
@@ -67,7 +67,11 @@ class MissingRequiredValue(QueryBuilderError):
67
67
  def __init__(
68
68
  self,
69
69
  property_name: str,
70
- operator: StringOperator | NumberOperator | BooleanOperator | DateOperator | ArrayOperator,
70
+ operator: StringOperator
71
+ | NumberOperator
72
+ | BooleanOperator
73
+ | DateOperator
74
+ | ArrayOperator,
71
75
  ) -> None:
72
76
  self.operator = operator
73
77
 
@@ -79,7 +83,11 @@ class ValueNotAllowedForOperator(QueryBuilderError):
79
83
  def __init__(
80
84
  self,
81
85
  property_name: str,
82
- operator: StringOperator | NumberOperator | BooleanOperator | DateOperator | ArrayOperator,
86
+ operator: StringOperator
87
+ | NumberOperator
88
+ | BooleanOperator
89
+ | DateOperator
90
+ | ArrayOperator,
83
91
  ) -> None:
84
92
  self.operator = operator
85
93
 
@@ -144,9 +152,7 @@ class NoPropertySelected(QueryBuilderError):
144
152
 
145
153
  class EmptyOrGroupError(QueryBuilderError):
146
154
  def __init__(self) -> None:
147
- message = (
148
- "Cannot create an OR group with no conditions. Add at least one filter condition before using .or_where()"
149
- )
155
+ message = "Cannot create an OR group with no conditions. Add at least one filter condition before using .or_where()"
150
156
  super().__init__(message)
151
157
 
152
158
 
@@ -1,9 +1,9 @@
1
1
  import difflib
2
2
 
3
- from notionary.exceptions.base import NotionaryError
3
+ from notionary.exceptions.base import NotionaryException
4
4
 
5
5
 
6
- class DataSourcePropertyNotFound(NotionaryError):
6
+ class DataSourcePropertyNotFound(NotionaryException):
7
7
  def __init__(
8
8
  self,
9
9
  property_name: str,
@@ -28,7 +28,9 @@ class DataSourcePropertyNotFound(NotionaryError):
28
28
  super().__init__(message)
29
29
 
30
30
 
31
- class DataSourcePropertyTypeError(NotionaryError):
32
- def __init__(self, property_name: str, expected_type: str, actual_type: str) -> None:
31
+ class DataSourcePropertyTypeError(NotionaryException):
32
+ def __init__(
33
+ self, property_name: str, expected_type: str, actual_type: str
34
+ ) -> None:
33
35
  message = f"Property '{property_name}' has the wrong type. Expected: '{expected_type}', found: '{actual_type}'."
34
36
  super().__init__(message)
@@ -0,0 +1,76 @@
1
+ from notionary.exceptions.base import NotionaryException
2
+
3
+
4
+ class UnsupportedFileTypeException(NotionaryException):
5
+ def __init__(
6
+ self,
7
+ extension: str,
8
+ filename: str,
9
+ supported_extensions_by_category: dict[str, list[str]],
10
+ ):
11
+ supported_exts = []
12
+ for category, extensions in supported_extensions_by_category.items():
13
+ supported_exts.append(f"{category}: {', '.join(extensions[:5])}...")
14
+
15
+ supported_info = "\n ".join(supported_exts)
16
+ super().__init__(
17
+ f"File '{filename}' has unsupported extension '{extension}'.\n"
18
+ f"Supported file types by category:\n {supported_info}"
19
+ )
20
+ self.extension = extension
21
+ self.filename = filename
22
+
23
+
24
+ class NoFileExtensionException(NotionaryException):
25
+ def __init__(self, filename: str):
26
+ super().__init__(
27
+ f"File '{filename}' has no extension. Files must have a valid extension to determine their type."
28
+ )
29
+ self.filename = filename
30
+
31
+
32
+ class FileSizeException(NotionaryException):
33
+ def __init__(self, filename: str, file_size_bytes: int, max_size_bytes: int):
34
+ file_size_mb = file_size_bytes / (1024 * 1024)
35
+ max_size_mb = max_size_bytes / (1024 * 1024)
36
+ super().__init__(
37
+ f"File '{filename}' is too large ({file_size_mb:.2f} MB). Maximum allowed size is {max_size_mb:.2f} MB."
38
+ )
39
+ self.filename = filename
40
+ self.file_size_bytes = file_size_bytes
41
+ self.max_size_bytes = max_size_bytes
42
+
43
+
44
+ class FileNotFoundError(NotionaryException):
45
+ def __init__(self, file_path: str):
46
+ super().__init__(f"File does not exist: {file_path}")
47
+ self.file_path = file_path
48
+
49
+
50
+ class FilenameTooLongError(NotionaryException):
51
+ def __init__(self, filename: str, filename_bytes: int, max_filename_bytes: int):
52
+ super().__init__(
53
+ f"Filename too long: {filename_bytes} bytes (max {max_filename_bytes}). Filename: {filename}"
54
+ )
55
+ self.filename = filename
56
+ self.filename_bytes = filename_bytes
57
+ self.max_filename_bytes = max_filename_bytes
58
+
59
+
60
+ class UploadFailedError(NotionaryException):
61
+ def __init__(self, file_upload_id: str, reason: str | None = None):
62
+ message = f"Upload failed for file_upload_id: {file_upload_id}"
63
+ if reason:
64
+ message += f". Reason: {reason}"
65
+ super().__init__(message)
66
+ self.file_upload_id = file_upload_id
67
+ self.reason = reason
68
+
69
+
70
+ class UploadTimeoutError(NotionaryException):
71
+ def __init__(self, file_upload_id: str, timeout_seconds: int):
72
+ super().__init__(
73
+ f"Upload timeout after {timeout_seconds}s for file_upload_id: {file_upload_id}"
74
+ )
75
+ self.file_upload_id = file_upload_id
76
+ self.timeout_seconds = timeout_seconds
@@ -1,11 +1,11 @@
1
1
  import difflib
2
2
  from typing import ClassVar
3
3
 
4
- from notionary.exceptions.base import NotionaryError
4
+ from notionary.exceptions.base import NotionaryException
5
5
  from notionary.shared.models.parent import ParentType
6
6
 
7
7
 
8
- class PagePropertyNotFoundError(NotionaryError):
8
+ class PagePropertyNotFoundError(NotionaryException):
9
9
  def __init__(
10
10
  self,
11
11
  page_url: str,
@@ -31,7 +31,7 @@ class PagePropertyNotFoundError(NotionaryError):
31
31
  super().__init__(message)
32
32
 
33
33
 
34
- class PagePropertyTypeError(NotionaryError):
34
+ class PagePropertyTypeError(NotionaryException):
35
35
  def __init__(
36
36
  self,
37
37
  property_name: str,
@@ -41,7 +41,7 @@ class PagePropertyTypeError(NotionaryError):
41
41
  super().__init__(message)
42
42
 
43
43
 
44
- class AccessPagePropertyWithoutDataSourceError(NotionaryError):
44
+ class AccessPagePropertyWithoutDataSourceError(NotionaryException):
45
45
  _PARENT_DESCRIPTIONS: ClassVar[dict[ParentType, str]] = {
46
46
  ParentType.WORKSPACE: "the workspace itself",
47
47
  ParentType.PAGE_ID: "another page",
@@ -50,7 +50,9 @@ class AccessPagePropertyWithoutDataSourceError(NotionaryError):
50
50
  }
51
51
 
52
52
  def __init__(self, parent_type: ParentType) -> None:
53
- parent_desc = self._PARENT_DESCRIPTIONS.get(parent_type, f"its parent type is '{parent_type}'")
53
+ parent_desc = self._PARENT_DESCRIPTIONS.get(
54
+ parent_type, f"its parent type is '{parent_type}'"
55
+ )
54
56
  message = (
55
57
  f"Cannot access properties other than title because this page's parent is {parent_desc}. "
56
58
  "To use operations like property reading/writing, you need to use a page whose parent is a data source."
@@ -1,8 +1,10 @@
1
- from notionary.exceptions.base import NotionaryError
1
+ from notionary.exceptions.base import NotionaryException
2
2
 
3
3
 
4
- class EntityNotFound(NotionaryError):
5
- def __init__(self, entity_type: str, query: str, available_titles: list[str] | None = None) -> None:
4
+ class EntityNotFound(NotionaryException):
5
+ def __init__(
6
+ self, entity_type: str, query: str, available_titles: list[str] | None = None
7
+ ) -> None:
6
8
  self.entity_type = entity_type
7
9
  self.query = query
8
10
  self.available_titles = available_titles or []
@@ -33,15 +35,17 @@ class DatabaseNotFound(EntityNotFound):
33
35
  super().__init__("database", query, available_titles)
34
36
 
35
37
 
36
- class NoUsersInWorkspace(NotionaryError):
38
+ class NoUsersInWorkspace(NotionaryException):
37
39
  def __init__(self, user_type: str) -> None:
38
40
  self.user_type = user_type
39
41
  message = f"No '{user_type}' users found in the workspace."
40
42
  super().__init__(message)
41
43
 
42
44
 
43
- class UserNotFound(NotionaryError):
44
- def __init__(self, user_type: str, query: str, available_names: list[str] | None = None) -> None:
45
+ class UserNotFound(NotionaryException):
46
+ def __init__(
47
+ self, user_type: str, query: str, available_names: list[str] | None = None
48
+ ) -> None:
45
49
  self.user_type = user_type
46
50
  self.query = query
47
51
  self.available_names = available_names or []
@@ -0,0 +1,4 @@
1
+ from .query import FileUploadQuery, FileUploadQueryBuilder
2
+ from .service import NotionFileUpload
3
+
4
+ __all__ = ["FileUploadQuery", "FileUploadQueryBuilder", "NotionFileUpload"]