notionary 0.4.0__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 (176) hide show
  1. notionary/__init__.py +44 -1
  2. notionary/blocks/client.py +37 -11
  3. notionary/blocks/rich_text/markdown_rich_text_converter.py +49 -15
  4. notionary/blocks/rich_text/models.py +13 -4
  5. notionary/blocks/rich_text/name_id_resolver/data_source.py +9 -3
  6. notionary/blocks/rich_text/name_id_resolver/person.py +6 -2
  7. notionary/blocks/rich_text/rich_text_markdown_converter.py +10 -3
  8. notionary/blocks/schemas.py +2 -1
  9. notionary/comments/client.py +19 -6
  10. notionary/comments/factory.py +10 -3
  11. notionary/comments/schemas.py +9 -3
  12. notionary/comments/service.py +12 -4
  13. notionary/data_source/http/data_source_instance_client.py +59 -17
  14. notionary/data_source/properties/schemas.py +30 -10
  15. notionary/data_source/query/builder.py +67 -18
  16. notionary/data_source/query/resolver.py +16 -5
  17. notionary/data_source/query/schema.py +24 -6
  18. notionary/data_source/query/validator.py +18 -6
  19. notionary/data_source/schema/registry.py +31 -12
  20. notionary/data_source/schema/service.py +66 -20
  21. notionary/data_source/service.py +74 -23
  22. notionary/database/client.py +27 -9
  23. notionary/database/database_metadata_update_client.py +12 -4
  24. notionary/database/service.py +11 -4
  25. notionary/exceptions/__init__.py +15 -3
  26. notionary/exceptions/block_parsing.py +6 -2
  27. notionary/exceptions/data_source/builder.py +11 -5
  28. notionary/exceptions/data_source/properties.py +3 -1
  29. notionary/exceptions/file_upload.py +12 -3
  30. notionary/exceptions/properties.py +3 -1
  31. notionary/exceptions/search.py +6 -2
  32. notionary/file_upload/client.py +5 -1
  33. notionary/file_upload/config/config.py +10 -3
  34. notionary/file_upload/query/builder.py +6 -2
  35. notionary/file_upload/schemas.py +3 -1
  36. notionary/file_upload/service.py +42 -14
  37. notionary/file_upload/validation/factory.py +3 -1
  38. notionary/file_upload/validation/impl/file_name_length.py +3 -1
  39. notionary/file_upload/validation/models.py +15 -5
  40. notionary/file_upload/validation/validators/file_extension.py +12 -3
  41. notionary/http/client.py +27 -8
  42. notionary/page/content/__init__.py +9 -0
  43. notionary/page/content/factory.py +21 -7
  44. notionary/page/content/markdown/builder.py +85 -23
  45. notionary/page/content/markdown/nodes/audio.py +8 -4
  46. notionary/page/content/markdown/nodes/base.py +3 -3
  47. notionary/page/content/markdown/nodes/bookmark.py +5 -3
  48. notionary/page/content/markdown/nodes/breadcrumb.py +2 -2
  49. notionary/page/content/markdown/nodes/bulleted_list.py +5 -3
  50. notionary/page/content/markdown/nodes/callout.py +2 -2
  51. notionary/page/content/markdown/nodes/code.py +5 -3
  52. notionary/page/content/markdown/nodes/columns.py +3 -3
  53. notionary/page/content/markdown/nodes/container.py +9 -5
  54. notionary/page/content/markdown/nodes/divider.py +2 -2
  55. notionary/page/content/markdown/nodes/embed.py +8 -4
  56. notionary/page/content/markdown/nodes/equation.py +4 -2
  57. notionary/page/content/markdown/nodes/file.py +8 -4
  58. notionary/page/content/markdown/nodes/heading.py +2 -2
  59. notionary/page/content/markdown/nodes/image.py +8 -4
  60. notionary/page/content/markdown/nodes/mixins/caption.py +5 -3
  61. notionary/page/content/markdown/nodes/numbered_list.py +5 -3
  62. notionary/page/content/markdown/nodes/paragraph.py +4 -2
  63. notionary/page/content/markdown/nodes/pdf.py +8 -4
  64. notionary/page/content/markdown/nodes/quote.py +2 -2
  65. notionary/page/content/markdown/nodes/space.py +2 -2
  66. notionary/page/content/markdown/nodes/table.py +8 -5
  67. notionary/page/content/markdown/nodes/table_of_contents.py +2 -2
  68. notionary/page/content/markdown/nodes/todo.py +15 -7
  69. notionary/page/content/markdown/nodes/toggle.py +2 -2
  70. notionary/page/content/markdown/nodes/video.py +8 -4
  71. notionary/page/content/markdown/structured_output/__init__.py +73 -0
  72. notionary/page/content/markdown/structured_output/models.py +391 -0
  73. notionary/page/content/markdown/structured_output/service.py +211 -0
  74. notionary/page/content/parser/context.py +1 -1
  75. notionary/page/content/parser/factory.py +23 -8
  76. notionary/page/content/parser/parsers/audio.py +7 -2
  77. notionary/page/content/parser/parsers/base.py +2 -2
  78. notionary/page/content/parser/parsers/bookmark.py +2 -2
  79. notionary/page/content/parser/parsers/breadcrumb.py +2 -2
  80. notionary/page/content/parser/parsers/bulleted_list.py +19 -6
  81. notionary/page/content/parser/parsers/callout.py +15 -5
  82. notionary/page/content/parser/parsers/caption.py +9 -3
  83. notionary/page/content/parser/parsers/code.py +21 -7
  84. notionary/page/content/parser/parsers/column.py +8 -4
  85. notionary/page/content/parser/parsers/column_list.py +19 -7
  86. notionary/page/content/parser/parsers/divider.py +2 -2
  87. notionary/page/content/parser/parsers/embed.py +2 -2
  88. notionary/page/content/parser/parsers/equation.py +8 -4
  89. notionary/page/content/parser/parsers/file.py +7 -2
  90. notionary/page/content/parser/parsers/file_like_block.py +30 -10
  91. notionary/page/content/parser/parsers/heading.py +31 -10
  92. notionary/page/content/parser/parsers/image.py +7 -2
  93. notionary/page/content/parser/parsers/numbered_list.py +18 -6
  94. notionary/page/content/parser/parsers/paragraph.py +3 -1
  95. notionary/page/content/parser/parsers/pdf.py +7 -2
  96. notionary/page/content/parser/parsers/quote.py +28 -9
  97. notionary/page/content/parser/parsers/space.py +2 -2
  98. notionary/page/content/parser/parsers/table.py +31 -10
  99. notionary/page/content/parser/parsers/table_of_contents.py +7 -3
  100. notionary/page/content/parser/parsers/todo.py +15 -5
  101. notionary/page/content/parser/parsers/toggle.py +15 -5
  102. notionary/page/content/parser/parsers/video.py +7 -2
  103. notionary/page/content/parser/post_processing/handlers/rich_text_length.py +8 -2
  104. notionary/page/content/parser/post_processing/handlers/rich_text_length_truncation.py +8 -2
  105. notionary/page/content/parser/post_processing/service.py +3 -1
  106. notionary/page/content/parser/pre_processsing/handlers/column_syntax.py +21 -7
  107. notionary/page/content/parser/pre_processsing/handlers/indentation.py +11 -4
  108. notionary/page/content/parser/pre_processsing/handlers/video_syntax.py +13 -6
  109. notionary/page/content/parser/service.py +4 -1
  110. notionary/page/content/renderer/context.py +15 -5
  111. notionary/page/content/renderer/factory.py +12 -6
  112. notionary/page/content/renderer/post_processing/handlers/numbered_list.py +19 -9
  113. notionary/page/content/renderer/renderers/audio.py +14 -5
  114. notionary/page/content/renderer/renderers/base.py +3 -3
  115. notionary/page/content/renderer/renderers/bookmark.py +3 -1
  116. notionary/page/content/renderer/renderers/bulleted_list.py +11 -5
  117. notionary/page/content/renderer/renderers/callout.py +19 -7
  118. notionary/page/content/renderer/renderers/captioned_block.py +11 -5
  119. notionary/page/content/renderer/renderers/code.py +6 -2
  120. notionary/page/content/renderer/renderers/column.py +3 -1
  121. notionary/page/content/renderer/renderers/column_list.py +3 -1
  122. notionary/page/content/renderer/renderers/embed.py +3 -1
  123. notionary/page/content/renderer/renderers/equation.py +3 -1
  124. notionary/page/content/renderer/renderers/file.py +14 -5
  125. notionary/page/content/renderer/renderers/file_like_block.py +8 -4
  126. notionary/page/content/renderer/renderers/heading.py +22 -8
  127. notionary/page/content/renderer/renderers/image.py +13 -4
  128. notionary/page/content/renderer/renderers/numbered_list.py +8 -3
  129. notionary/page/content/renderer/renderers/paragraph.py +12 -4
  130. notionary/page/content/renderer/renderers/pdf.py +14 -5
  131. notionary/page/content/renderer/renderers/quote.py +14 -6
  132. notionary/page/content/renderer/renderers/table.py +15 -5
  133. notionary/page/content/renderer/renderers/todo.py +16 -6
  134. notionary/page/content/renderer/renderers/toggle.py +8 -4
  135. notionary/page/content/renderer/renderers/video.py +14 -5
  136. notionary/page/content/renderer/service.py +9 -3
  137. notionary/page/content/service.py +21 -7
  138. notionary/page/content/syntax/definition/__init__.py +11 -0
  139. notionary/page/content/syntax/definition/models.py +57 -0
  140. notionary/page/content/syntax/definition/registry.py +371 -0
  141. notionary/page/content/syntax/prompts/__init__.py +4 -0
  142. notionary/page/content/syntax/prompts/models.py +11 -0
  143. notionary/page/content/syntax/prompts/registry.py +703 -0
  144. notionary/page/page_metadata_update_client.py +12 -4
  145. notionary/page/properties/client.py +45 -15
  146. notionary/page/properties/factory.py +6 -2
  147. notionary/page/properties/service.py +110 -36
  148. notionary/page/service.py +20 -6
  149. notionary/shared/entity/client.py +6 -2
  150. notionary/shared/entity/dto_parsers.py +3 -1
  151. notionary/shared/entity/entity_metadata_update_client.py +9 -3
  152. notionary/shared/entity/service.py +53 -22
  153. notionary/shared/models/file.py +3 -1
  154. notionary/user/base.py +6 -2
  155. notionary/user/bot.py +10 -2
  156. notionary/user/client.py +3 -1
  157. notionary/user/person.py +3 -1
  158. notionary/user/schemas.py +3 -1
  159. notionary/user/service.py +6 -2
  160. notionary/utils/decorators.py +6 -2
  161. notionary/utils/fuzzy.py +6 -2
  162. notionary/utils/mixins/logging.py +3 -1
  163. notionary/utils/pagination.py +14 -4
  164. notionary/workspace/__init__.py +5 -1
  165. notionary/workspace/query/service.py +59 -16
  166. notionary/workspace/service.py +39 -11
  167. {notionary-0.4.0.dist-info → notionary-0.4.1.dist-info}/METADATA +1 -1
  168. notionary-0.4.1.dist-info/RECORD +236 -0
  169. notionary/page/blocks/client.py +0 -1
  170. notionary/page/content/syntax/__init__.py +0 -5
  171. notionary/page/content/syntax/models.py +0 -66
  172. notionary/page/content/syntax/registry.py +0 -371
  173. notionary-0.4.0.dist-info/RECORD +0 -230
  174. /notionary/page/content/syntax/{grammar.py → definition/grammar.py} +0 -0
  175. {notionary-0.4.0.dist-info → notionary-0.4.1.dist-info}/WHEEL +0 -0
  176. {notionary-0.4.0.dist-info → notionary-0.4.1.dist-info}/licenses/LICENSE +0 -0
@@ -13,36 +13,52 @@ class DatabasePropertyTypeDescriptorRegistry:
13
13
  def __init__(self):
14
14
  self._DESCRIPTORS = {
15
15
  PropertyType.TITLE: PropertyTypeDescriptor(
16
- display_name="Title", description="Required field for the main heading of the entry"
16
+ display_name="Title",
17
+ description="Required field for the main heading of the entry",
17
18
  ),
18
19
  PropertyType.RICH_TEXT: PropertyTypeDescriptor(
19
- display_name="Rich Text", description="Free-form text field for additional information"
20
+ display_name="Rich Text",
21
+ description="Free-form text field for additional information",
22
+ ),
23
+ PropertyType.NUMBER: PropertyTypeDescriptor(
24
+ display_name="Number", description="Numeric value field"
20
25
  ),
21
- PropertyType.NUMBER: PropertyTypeDescriptor(display_name="Number", description="Numeric value field"),
22
26
  PropertyType.CHECKBOX: PropertyTypeDescriptor(
23
27
  display_name="Checkbox", description="Boolean value (true/false)"
24
28
  ),
25
- PropertyType.DATE: PropertyTypeDescriptor(display_name="Date", description="Date or date range field"),
26
- PropertyType.URL: PropertyTypeDescriptor(display_name="URL", description="Web address field"),
27
- PropertyType.EMAIL: PropertyTypeDescriptor(display_name="Email", description="Email address field"),
29
+ PropertyType.DATE: PropertyTypeDescriptor(
30
+ display_name="Date", description="Date or date range field"
31
+ ),
32
+ PropertyType.URL: PropertyTypeDescriptor(
33
+ display_name="URL", description="Web address field"
34
+ ),
35
+ PropertyType.EMAIL: PropertyTypeDescriptor(
36
+ display_name="Email", description="Email address field"
37
+ ),
28
38
  PropertyType.PHONE_NUMBER: PropertyTypeDescriptor(
29
39
  display_name="Phone Number", description="Phone number field"
30
40
  ),
31
41
  PropertyType.FILES: PropertyTypeDescriptor(
32
42
  display_name="Files & Media", description="Upload or link to files"
33
43
  ),
34
- PropertyType.PEOPLE: PropertyTypeDescriptor(display_name="People", description="Reference to Notion users"),
44
+ PropertyType.PEOPLE: PropertyTypeDescriptor(
45
+ display_name="People", description="Reference to Notion users"
46
+ ),
35
47
  PropertyType.SELECT: PropertyTypeDescriptor(
36
- display_name="Single Select", description="Choose one option from available choices"
48
+ display_name="Single Select",
49
+ description="Choose one option from available choices",
37
50
  ),
38
51
  PropertyType.MULTI_SELECT: PropertyTypeDescriptor(
39
- display_name="Multi Select", description="Choose multiple options from available choices"
52
+ display_name="Multi Select",
53
+ description="Choose multiple options from available choices",
40
54
  ),
41
55
  PropertyType.STATUS: PropertyTypeDescriptor(
42
- display_name="Status", description="Track status with predefined options"
56
+ display_name="Status",
57
+ description="Track status with predefined options",
43
58
  ),
44
59
  PropertyType.RELATION: PropertyTypeDescriptor(
45
- display_name="Relation", description="Link to entries in another database"
60
+ display_name="Relation",
61
+ description="Link to entries in another database",
46
62
  ),
47
63
  PropertyType.CREATED_TIME: PropertyTypeDescriptor(
48
64
  display_name="Created Time",
@@ -97,7 +113,10 @@ class DatabasePropertyTypeDescriptorRegistry:
97
113
  def get_descriptor(self, property_type: PropertyType) -> PropertyTypeDescriptor:
98
114
  return self._DESCRIPTORS.get(
99
115
  property_type,
100
- PropertyTypeDescriptor(display_name=self._format_unknown_type_name(property_type), description=""),
116
+ PropertyTypeDescriptor(
117
+ display_name=self._format_unknown_type_name(property_type),
118
+ description="",
119
+ ),
101
120
  )
102
121
 
103
122
  def _format_unknown_type_name(self, property_type: PropertyType) -> str:
@@ -8,7 +8,10 @@ from notionary.data_source.properties.schemas import (
8
8
  DataSourceSelectProperty,
9
9
  DataSourceStatusProperty,
10
10
  )
11
- from notionary.data_source.schema.registry import DatabasePropertyTypeDescriptorRegistry, PropertyTypeDescriptor
11
+ from notionary.data_source.schema.registry import (
12
+ DatabasePropertyTypeDescriptorRegistry,
13
+ PropertyTypeDescriptor,
14
+ )
12
15
  from notionary.shared.properties.type import PropertyType
13
16
 
14
17
 
@@ -17,12 +20,16 @@ class PropertyFormatter:
17
20
 
18
21
  def __init__(
19
22
  self,
20
- relation_options_fetcher: Callable[[DataSourceRelationProperty], Awaitable[list[str]]],
23
+ relation_options_fetcher: Callable[
24
+ [DataSourceRelationProperty], Awaitable[list[str]]
25
+ ],
21
26
  type_descriptor_registry: DatabasePropertyTypeDescriptorRegistry | None = None,
22
27
  data_source_resolver: DataSourceNameIdResolver | None = None,
23
28
  ) -> None:
24
29
  self._relation_options_fetcher = relation_options_fetcher
25
- self._type_descriptor_registry = type_descriptor_registry or DatabasePropertyTypeDescriptorRegistry()
30
+ self._type_descriptor_registry = (
31
+ type_descriptor_registry or DatabasePropertyTypeDescriptorRegistry()
32
+ )
26
33
  self._data_source_resolver = data_source_resolver or DataSourceNameIdResolver()
27
34
 
28
35
  async def format_property(self, prop: DataSourceProperty) -> list[str]:
@@ -32,22 +39,35 @@ class PropertyFormatter:
32
39
  return [*specific_details, *self._format_custom_description(prop)]
33
40
 
34
41
  descriptor = self._type_descriptor_registry.get_descriptor(prop.type)
35
- return [*self._format_property_description(descriptor), *self._format_custom_description(prop)]
36
-
37
- def _format_property_description(self, descriptor: PropertyTypeDescriptor) -> list[str]:
42
+ return [
43
+ *self._format_property_description(descriptor),
44
+ *self._format_custom_description(prop),
45
+ ]
46
+
47
+ def _format_property_description(
48
+ self, descriptor: PropertyTypeDescriptor
49
+ ) -> list[str]:
38
50
  if not descriptor.description:
39
51
  return []
40
52
  return [f"{self.INDENTATION}{descriptor.description}"]
41
53
 
42
- async def _format_property_specific_details(self, prop: DataSourceProperty) -> list[str]:
54
+ async def _format_property_specific_details(
55
+ self, prop: DataSourceProperty
56
+ ) -> list[str]:
43
57
  if isinstance(prop, DataSourceSelectProperty):
44
- return self._format_available_options("Choose one option from", prop.option_names)
58
+ return self._format_available_options(
59
+ "Choose one option from", prop.option_names
60
+ )
45
61
 
46
62
  if isinstance(prop, DataSourceMultiSelectProperty):
47
- return self._format_available_options("Choose multiple options from", prop.option_names)
63
+ return self._format_available_options(
64
+ "Choose multiple options from", prop.option_names
65
+ )
48
66
 
49
67
  if isinstance(prop, DataSourceStatusProperty):
50
- return self._format_available_options("Available statuses", prop.option_names)
68
+ return self._format_available_options(
69
+ "Available statuses", prop.option_names
70
+ )
51
71
 
52
72
  if isinstance(prop, DataSourceRelationProperty):
53
73
  return await self._format_relation_details(prop)
@@ -63,11 +83,15 @@ class PropertyFormatter:
63
83
  options_text = ", ".join(options)
64
84
  return [f"{self.INDENTATION}{label}: {options_text}"]
65
85
 
66
- async def _format_relation_details(self, prop: DataSourceRelationProperty) -> list[str]:
86
+ async def _format_relation_details(
87
+ self, prop: DataSourceRelationProperty
88
+ ) -> list[str]:
67
89
  if not prop.related_data_source_id:
68
90
  return []
69
91
 
70
- data_source_name = await self._data_source_resolver.resolve_id_to_name(prop.related_data_source_id)
92
+ data_source_name = await self._data_source_resolver.resolve_id_to_name(
93
+ prop.related_data_source_id
94
+ )
71
95
  data_source_display = data_source_name or prop.related_data_source_id
72
96
  lines = [f"{self.INDENTATION}Links to datasource: {data_source_display}"]
73
97
 
@@ -78,7 +102,9 @@ class PropertyFormatter:
78
102
 
79
103
  return lines
80
104
 
81
- async def _fetch_relation_entries(self, prop: DataSourceRelationProperty) -> list[str] | None:
105
+ async def _fetch_relation_entries(
106
+ self, prop: DataSourceRelationProperty
107
+ ) -> list[str] | None:
82
108
  try:
83
109
  return await self._relation_options_fetcher(prop)
84
110
  except Exception:
@@ -88,14 +114,22 @@ class PropertyFormatter:
88
114
  class DataSourcePropertySchemaFormatter:
89
115
  def __init__(
90
116
  self,
91
- relation_options_fetcher: Callable[[DataSourceRelationProperty], Awaitable[list[str]]] | None = None,
117
+ relation_options_fetcher: Callable[
118
+ [DataSourceRelationProperty], Awaitable[list[str]]
119
+ ]
120
+ | None = None,
92
121
  data_source_resolver: DataSourceNameIdResolver | None = None,
93
122
  ) -> None:
94
123
  self._property_formatter = PropertyFormatter(
95
124
  relation_options_fetcher, data_source_resolver=data_source_resolver
96
125
  )
97
126
 
98
- async def format(self, title: str, description: str | None, properties: dict[str, DataSourceProperty]) -> str:
127
+ async def format(
128
+ self,
129
+ title: str,
130
+ description: str | None,
131
+ properties: dict[str, DataSourceProperty],
132
+ ) -> str:
99
133
  lines = self._format_header(title, description)
100
134
  lines.append("Properties:")
101
135
  lines.append("")
@@ -112,7 +146,9 @@ class DataSourcePropertySchemaFormatter:
112
146
 
113
147
  return lines
114
148
 
115
- async def _format_properties(self, properties: dict[str, DataSourceProperty]) -> list[str]:
149
+ async def _format_properties(
150
+ self, properties: dict[str, DataSourceProperty]
151
+ ) -> list[str]:
116
152
  lines = []
117
153
  sorted_properties = self._sort_with_title_first(properties)
118
154
 
@@ -121,14 +157,24 @@ class DataSourcePropertySchemaFormatter:
121
157
 
122
158
  return lines
123
159
 
124
- def _sort_with_title_first(self, properties: dict[str, DataSourceProperty]) -> list[tuple[str, DataSourceProperty]]:
125
- return sorted(properties.items(), key=lambda item: (self._is_not_title_property(item[1]), item[0]))
160
+ def _sort_with_title_first(
161
+ self, properties: dict[str, DataSourceProperty]
162
+ ) -> list[tuple[str, DataSourceProperty]]:
163
+ return sorted(
164
+ properties.items(),
165
+ key=lambda item: (self._is_not_title_property(item[1]), item[0]),
166
+ )
126
167
 
127
168
  def _is_not_title_property(self, prop: DataSourceProperty) -> bool:
128
169
  return prop.type != PropertyType.TITLE
129
170
 
130
- async def _format_single_property(self, index: int, name: str, prop: DataSourceProperty) -> list[str]:
131
- lines = [f"{index}. - Property Name: '{name}'", f" - Property Type: '{prop.type.value}'"]
171
+ async def _format_single_property(
172
+ self, index: int, name: str, prop: DataSourceProperty
173
+ ) -> list[str]:
174
+ lines = [
175
+ f"{index}. - Property Name: '{name}'",
176
+ f" - Property Type: '{prop.type.value}'",
177
+ ]
132
178
 
133
179
  lines.extend(await self._property_formatter.format_property(prop))
134
180
  lines.append("")
@@ -4,9 +4,13 @@ import asyncio
4
4
  from collections.abc import AsyncIterator, Callable
5
5
  from typing import TYPE_CHECKING, Self
6
6
 
7
- from notionary.blocks.rich_text.rich_text_markdown_converter import RichTextToMarkdownConverter
7
+ from notionary.blocks.rich_text.rich_text_markdown_converter import (
8
+ RichTextToMarkdownConverter,
9
+ )
8
10
  from notionary.data_source.http.client import DataSourceClient
9
- from notionary.data_source.http.data_source_instance_client import DataSourceInstanceClient
11
+ from notionary.data_source.http.data_source_instance_client import (
12
+ DataSourceInstanceClient,
13
+ )
10
14
  from notionary.data_source.properties.schemas import (
11
15
  DataSourceMultiSelectProperty,
12
16
  DataSourceProperty,
@@ -16,10 +20,17 @@ from notionary.data_source.properties.schemas import (
16
20
  DataSourceSelectProperty,
17
21
  DataSourceStatusProperty,
18
22
  )
19
- from notionary.data_source.query import DataSourceQueryBuilder, DataSourceQueryParams, QueryResolver
23
+ from notionary.data_source.query import (
24
+ DataSourceQueryBuilder,
25
+ DataSourceQueryParams,
26
+ QueryResolver,
27
+ )
20
28
  from notionary.data_source.schema.service import DataSourcePropertySchemaFormatter
21
29
  from notionary.data_source.schemas import DataSourceDto
22
- from notionary.exceptions.data_source.properties import DataSourcePropertyNotFound, DataSourcePropertyTypeError
30
+ from notionary.exceptions.data_source.properties import (
31
+ DataSourcePropertyNotFound,
32
+ DataSourcePropertyTypeError,
33
+ )
23
34
  from notionary.file_upload.service import NotionFileUpload
24
35
  from notionary.page.properties.schemas import PageTitleProperty
25
36
  from notionary.page.schemas import NotionPageDto
@@ -27,7 +38,9 @@ from notionary.shared.entity.dto_parsers import (
27
38
  extract_description,
28
39
  extract_title,
29
40
  )
30
- from notionary.shared.entity.entity_metadata_update_client import EntityMetadataUpdateClient
41
+ from notionary.shared.entity.entity_metadata_update_client import (
42
+ EntityMetadataUpdateClient,
43
+ )
31
44
  from notionary.shared.entity.service import Entity
32
45
  from notionary.user.service import UserService
33
46
  from notionary.workspace.query.service import WorkspaceQueryService
@@ -48,7 +61,9 @@ class NotionDataSource(Entity):
48
61
  user_service: UserService | None = None,
49
62
  file_upload_service: NotionFileUpload | None = None,
50
63
  ) -> None:
51
- super().__init__(dto=dto, user_service=user_service, file_upload_service=file_upload_service)
64
+ super().__init__(
65
+ dto=dto, user_service=user_service, file_upload_service=file_upload_service
66
+ )
52
67
 
53
68
  self._parent_database: NotionDatabase | None = None
54
69
  self._title = title
@@ -146,7 +161,9 @@ class NotionDataSource(Entity):
146
161
  self._archived = False
147
162
 
148
163
  async def update_description(self, description: str) -> None:
149
- self._description = await self._data_source_client.update_description(description)
164
+ self._description = await self._data_source_client.update_description(
165
+ description
166
+ )
150
167
 
151
168
  async def get_options_for_property_by_name(self, property_name: str) -> list[str]:
152
169
  prop = self._properties.get(property_name)
@@ -169,22 +186,36 @@ class NotionDataSource(Entity):
169
186
  return []
170
187
 
171
188
  def get_select_options_by_property_name(self, property_name: str) -> list[str]:
172
- select_prop = self._get_typed_property_or_raise(property_name, DataSourceSelectProperty)
189
+ select_prop = self._get_typed_property_or_raise(
190
+ property_name, DataSourceSelectProperty
191
+ )
173
192
  return select_prop.option_names
174
193
 
175
- def get_multi_select_options_by_property_name(self, property_name: str) -> list[DataSourcePropertyOption]:
176
- multi_select_prop = self._get_typed_property_or_raise(property_name, DataSourceMultiSelectProperty)
194
+ def get_multi_select_options_by_property_name(
195
+ self, property_name: str
196
+ ) -> list[DataSourcePropertyOption]:
197
+ multi_select_prop = self._get_typed_property_or_raise(
198
+ property_name, DataSourceMultiSelectProperty
199
+ )
177
200
  return multi_select_prop.option_names
178
201
 
179
202
  def get_status_options_by_property_name(self, property_name: str) -> list[str]:
180
- status_prop = self._get_typed_property_or_raise(property_name, DataSourceStatusProperty)
203
+ status_prop = self._get_typed_property_or_raise(
204
+ property_name, DataSourceStatusProperty
205
+ )
181
206
  return status_prop.option_names
182
207
 
183
- async def get_relation_options_by_property_name(self, property_name: str) -> list[str]:
184
- relation_prop = self._get_typed_property_or_raise(property_name, DataSourceRelationProperty)
208
+ async def get_relation_options_by_property_name(
209
+ self, property_name: str
210
+ ) -> list[str]:
211
+ relation_prop = self._get_typed_property_or_raise(
212
+ property_name, DataSourceRelationProperty
213
+ )
185
214
  return await self._get_relation_options(relation_prop)
186
215
 
187
- async def _get_relation_options(self, relation_prop: DataSourceRelationProperty) -> list[str]:
216
+ async def _get_relation_options(
217
+ self, relation_prop: DataSourceRelationProperty
218
+ ) -> list[str]:
188
219
  related_data_source_id = relation_prop.related_data_source_id
189
220
  if not related_data_source_id:
190
221
  return []
@@ -205,7 +236,11 @@ class NotionDataSource(Entity):
205
236
  return None
206
237
 
207
238
  title_property = next(
208
- (prop for prop in page.properties.values() if isinstance(prop, PageTitleProperty)),
239
+ (
240
+ prop
241
+ for prop in page.properties.values()
242
+ if isinstance(prop, PageTitleProperty)
243
+ ),
209
244
  None,
210
245
  )
211
246
 
@@ -214,7 +249,9 @@ class NotionDataSource(Entity):
214
249
 
215
250
  return "".join(item.plain_text for item in title_property.title)
216
251
 
217
- def _get_typed_property_or_raise(self, name: str, property_type: type[DataSourcePropertyT]) -> DataSourcePropertyT:
252
+ def _get_typed_property_or_raise(
253
+ self, name: str, property_type: type[DataSourcePropertyT]
254
+ ) -> DataSourcePropertyT:
218
255
  prop = self._properties.get(name)
219
256
 
220
257
  if prop is None:
@@ -225,7 +262,9 @@ class NotionDataSource(Entity):
225
262
 
226
263
  if not isinstance(prop, property_type):
227
264
  raise DataSourcePropertyTypeError(
228
- property_name=name, expected_type=property_type.__name__, actual_type=type(prop).__name__
265
+ property_name=name,
266
+ expected_type=property_type.__name__,
267
+ actual_type=type(prop).__name__,
229
268
  )
230
269
 
231
270
  return prop
@@ -236,7 +275,8 @@ class NotionDataSource(Entity):
236
275
  async def get_pages(
237
276
  self,
238
277
  *,
239
- filter_fn: Callable[[DataSourceQueryBuilder], DataSourceQueryBuilder] | None = None,
278
+ filter_fn: Callable[[DataSourceQueryBuilder], DataSourceQueryBuilder]
279
+ | None = None,
240
280
  query_params: DataSourceQueryParams | None = None,
241
281
  ) -> list[NotionPage]:
242
282
  from notionary import NotionPage
@@ -250,13 +290,16 @@ class NotionDataSource(Entity):
250
290
  query_params = configured_builder.build()
251
291
 
252
292
  resolved_params = await self._resolve_query_params_if_needed(query_params)
253
- query_response = await self._data_source_client.query(query_params=resolved_params)
293
+ query_response = await self._data_source_client.query(
294
+ query_params=resolved_params
295
+ )
254
296
  return [await NotionPage.from_id(page.id) for page in query_response.results]
255
297
 
256
298
  async def iter_pages(
257
299
  self,
258
300
  *,
259
- filter_fn: Callable[[DataSourceQueryBuilder], DataSourceQueryBuilder] | None = None,
301
+ filter_fn: Callable[[DataSourceQueryBuilder], DataSourceQueryBuilder]
302
+ | None = None,
260
303
  query_params: DataSourceQueryParams | None = None,
261
304
  ) -> AsyncIterator[NotionPage]:
262
305
  from notionary import NotionPage
@@ -271,7 +314,9 @@ class NotionDataSource(Entity):
271
314
 
272
315
  resolved_params = await self._resolve_query_params_if_needed(query_params)
273
316
 
274
- async for page in self._data_source_client.query_stream(query_params=resolved_params):
317
+ async for page in self._data_source_client.query_stream(
318
+ query_params=resolved_params
319
+ ):
275
320
  yield await NotionPage.from_id(page.id)
276
321
 
277
322
  async def _resolve_query_params_if_needed(
@@ -284,5 +329,11 @@ class NotionDataSource(Entity):
284
329
  return await self.query_resolver.resolve_params(query_params)
285
330
 
286
331
  async def get_schema_description(self) -> str:
287
- formatter = DataSourcePropertySchemaFormatter(relation_options_fetcher=self._get_relation_options)
288
- return await formatter.format(title=self._title, description=self._description, properties=self._properties)
332
+ formatter = DataSourcePropertySchemaFormatter(
333
+ relation_options_fetcher=self._get_relation_options
334
+ )
335
+ return await formatter.format(
336
+ title=self._title,
337
+ description=self._description,
338
+ properties=self._properties,
339
+ )
@@ -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,10 +2,14 @@ import asyncio
2
2
  from collections.abc import Awaitable, Callable
3
3
  from typing import Self
4
4
 
5
- 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
+ )
6
8
  from notionary.data_source.service import NotionDataSource
7
9
  from notionary.database.client import NotionDatabaseHttpClient
8
- from notionary.database.database_metadata_update_client import DatabaseMetadataUpdateClient
10
+ from notionary.database.database_metadata_update_client import (
11
+ DatabaseMetadataUpdateClient,
12
+ )
9
13
  from notionary.database.schemas import NotionDatabaseDto
10
14
  from notionary.shared.entity.dto_parsers import (
11
15
  extract_description,
@@ -71,7 +75,8 @@ class NotionDatabase(Entity):
71
75
  client: NotionDatabaseHttpClient,
72
76
  ) -> Self:
73
77
  title, description = await asyncio.gather(
74
- 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),
75
80
  )
76
81
 
77
82
  metadata_update_client = DatabaseMetadataUpdateClient(database_id=dto.id)
@@ -120,5 +125,7 @@ class NotionDatabase(Entity):
120
125
  self._title = result.title[0].plain_text if result.title else ""
121
126
 
122
127
  async def set_description(self, description: str) -> None:
123
- updated_description = await self.client.update_database_description(description=description)
128
+ updated_description = await self.client.update_database_description(
129
+ description=description
130
+ )
124
131
  self._description = updated_description
@@ -8,10 +8,22 @@ from .api import (
8
8
  NotionValidationError,
9
9
  )
10
10
  from .base import NotionaryException
11
- from .block_parsing import InsufficientColumnsError, InvalidColumnRatioSumError, UnsupportedVideoFormatError
11
+ from .block_parsing import (
12
+ InsufficientColumnsError,
13
+ InvalidColumnRatioSumError,
14
+ UnsupportedVideoFormatError,
15
+ )
12
16
  from .data_source import DataSourcePropertyNotFound, DataSourcePropertyTypeError
13
- from .file_upload import FileSizeException, NoFileExtensionException, UnsupportedFileTypeException
14
- 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
+ )
15
27
  from .search import DatabaseNotFound, DataSourceNotFound, EntityNotFound, PageNotFound
16
28
 
17
29
  __all__ = [
@@ -6,14 +6,18 @@ RATIO_TOLERANCE = 0.0001
6
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
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):
@@ -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
 
@@ -29,6 +29,8 @@ class DataSourcePropertyNotFound(NotionaryException):
29
29
 
30
30
 
31
31
  class DataSourcePropertyTypeError(NotionaryException):
32
- def __init__(self, property_name: str, expected_type: str, actual_type: str) -> None:
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)