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,66 +0,0 @@
1
- import re
2
- from dataclasses import dataclass
3
- from enum import StrEnum
4
-
5
-
6
- class SyntaxRegistryKey(StrEnum):
7
- AUDIO = "audio"
8
- BOOKMARK = "bookmark"
9
- IMAGE = "image"
10
- VIDEO = "video"
11
- FILE = "file"
12
- PDF = "pdf"
13
-
14
- # List blocks
15
- BULLETED_LIST = "bulleted_list"
16
- NUMBERED_LIST = "numbered_list"
17
- TO_DO = "todo"
18
- TO_DO_DONE = "todo_done"
19
-
20
- TOGGLE = "toggle"
21
- TOGGLEABLE_HEADING = "toggleable_heading"
22
- CALLOUT = "callout"
23
- QUOTE = "quote"
24
- CODE = "code"
25
-
26
- COLUMN_LIST = "column_list"
27
- COLUMN = "column"
28
-
29
- # Heading blocks
30
- HEADING_1 = "heading_1"
31
- HEADING_2 = "heading_2"
32
- HEADING_3 = "heading_3"
33
- HEADING = "heading" # Shared pattern for regular headings
34
-
35
- DIVIDER = "divider"
36
- BREADCRUMB = "breadcrumb"
37
- TABLE_OF_CONTENTS = "table_of_contents"
38
- EQUATION = "equation"
39
- EMBED = "embed"
40
- TABLE = "table"
41
- TABLE_ROW = "table_row"
42
-
43
- CAPTION = "caption"
44
- SPACE = "space"
45
-
46
-
47
- # some elemente need closing delimiters, others not
48
- # either use union type or validate config in service
49
- @dataclass(frozen=True)
50
- class SyntaxDefinition:
51
- """
52
- Defines the syntax pattern for a block type.
53
-
54
- Attributes:
55
- start_delimiter: The opening delimiter (e.g., "```", "+++", ">")
56
- end_delimiter: The optional closing delimiter (empty string if none)
57
- regex_pattern: The compiled regex pattern to match this syntax
58
- end_regex_pattern: Optional compiled regex pattern for end delimiter
59
- is_multiline_block: Whether this block can contain child blocks
60
- is_inline: Whether this is an inline syntax (like [audio](url))
61
- """
62
-
63
- start_delimiter: str
64
- end_delimiter: str
65
- regex_pattern: re.Pattern
66
- end_regex_pattern: re.Pattern | None = None
@@ -1,393 +0,0 @@
1
- import re
2
-
3
- from notionary.page.content.syntax.grammar import MarkdownGrammar
4
- from notionary.page.content.syntax.models import SyntaxDefinition, SyntaxRegistryKey
5
-
6
-
7
- class SyntaxRegistry:
8
- def __init__(self, markdown_markdown_grammar: MarkdownGrammar | None = None) -> None:
9
- self._markdown_grammar = markdown_markdown_grammar or MarkdownGrammar()
10
-
11
- self._definitions: dict[SyntaxRegistryKey, SyntaxDefinition] = {}
12
- self._register_defaults()
13
-
14
- def get_audio_syntax(self) -> SyntaxDefinition:
15
- return self._definitions[SyntaxRegistryKey.AUDIO]
16
-
17
- def get_bookmark_syntax(self) -> SyntaxDefinition:
18
- return self._definitions[SyntaxRegistryKey.BOOKMARK]
19
-
20
- def get_breadcrumb_syntax(self) -> SyntaxDefinition:
21
- return self._definitions[SyntaxRegistryKey.BREADCRUMB]
22
-
23
- def get_bulleted_list_syntax(self) -> SyntaxDefinition:
24
- return self._definitions[SyntaxRegistryKey.BULLETED_LIST]
25
-
26
- def get_callout_syntax(self) -> SyntaxDefinition:
27
- return self._definitions[SyntaxRegistryKey.CALLOUT]
28
-
29
- def get_code_syntax(self) -> SyntaxDefinition:
30
- return self._definitions[SyntaxRegistryKey.CODE]
31
-
32
- def get_column_syntax(self) -> SyntaxDefinition:
33
- return self._definitions[SyntaxRegistryKey.COLUMN]
34
-
35
- def get_column_list_syntax(self) -> SyntaxDefinition:
36
- return self._definitions[SyntaxRegistryKey.COLUMN_LIST]
37
-
38
- def get_divider_syntax(self) -> SyntaxDefinition:
39
- return self._definitions[SyntaxRegistryKey.DIVIDER]
40
-
41
- def get_embed_syntax(self) -> SyntaxDefinition:
42
- return self._definitions[SyntaxRegistryKey.EMBED]
43
-
44
- def get_equation_syntax(self) -> SyntaxDefinition:
45
- return self._definitions[SyntaxRegistryKey.EQUATION]
46
-
47
- def get_file_syntax(self) -> SyntaxDefinition:
48
- return self._definitions[SyntaxRegistryKey.FILE]
49
-
50
- def get_image_syntax(self) -> SyntaxDefinition:
51
- return self._definitions[SyntaxRegistryKey.IMAGE]
52
-
53
- def get_numbered_list_syntax(self) -> SyntaxDefinition:
54
- return self._definitions[SyntaxRegistryKey.NUMBERED_LIST]
55
-
56
- def get_pdf_syntax(self) -> SyntaxDefinition:
57
- return self._definitions[SyntaxRegistryKey.PDF]
58
-
59
- def get_quote_syntax(self) -> SyntaxDefinition:
60
- return self._definitions[SyntaxRegistryKey.QUOTE]
61
-
62
- def get_table_syntax(self) -> SyntaxDefinition:
63
- return self._definitions[SyntaxRegistryKey.TABLE]
64
-
65
- def get_table_row_syntax(self) -> SyntaxDefinition:
66
- return self._definitions[SyntaxRegistryKey.TABLE_ROW]
67
-
68
- def get_table_of_contents_syntax(self) -> SyntaxDefinition:
69
- return self._definitions[SyntaxRegistryKey.TABLE_OF_CONTENTS]
70
-
71
- def get_todo_syntax(self) -> SyntaxDefinition:
72
- return self._definitions[SyntaxRegistryKey.TO_DO]
73
-
74
- def get_todo_done_syntax(self) -> SyntaxDefinition:
75
- return self._definitions[SyntaxRegistryKey.TO_DO_DONE]
76
-
77
- def get_toggle_syntax(self) -> SyntaxDefinition:
78
- return self._definitions[SyntaxRegistryKey.TOGGLE]
79
-
80
- def get_toggleable_heading_syntax(self) -> SyntaxDefinition:
81
- return self._definitions[SyntaxRegistryKey.TOGGLEABLE_HEADING]
82
-
83
- def get_video_syntax(self) -> SyntaxDefinition:
84
- return self._definitions[SyntaxRegistryKey.VIDEO]
85
-
86
- def get_caption_syntax(self) -> SyntaxDefinition:
87
- return self._definitions[SyntaxRegistryKey.CAPTION]
88
-
89
- def get_space_syntax(self) -> SyntaxDefinition:
90
- return self._definitions[SyntaxRegistryKey.SPACE]
91
-
92
- def get_heading_syntax(self) -> SyntaxDefinition:
93
- return self._definitions[SyntaxRegistryKey.HEADING]
94
-
95
- def _register_defaults(self) -> None:
96
- self._register_audio_syntax()
97
- self._register_bookmark_syntax()
98
- self._register_image_syntax()
99
- self._register_video_syntax()
100
- self._register_file_syntax()
101
- self._register_pdf_syntax()
102
-
103
- # List blocks
104
- self._register_bulleted_list_syntax()
105
- self._register_numbered_list_syntax()
106
- self._register_todo_syntax()
107
- self._register_todo_done_syntax()
108
-
109
- # Container blocks
110
- self._register_toggle_syntax()
111
- self._register_toggleable_heading_syntax()
112
- self._register_callout_syntax()
113
- self._register_quote_syntax()
114
- self._register_code_syntax()
115
-
116
- # Column layout blocks
117
- self._register_column_list_syntax()
118
- self._register_column_syntax()
119
-
120
- self._register_heading_1_syntax()
121
- self._register_heading_2_syntax()
122
- self._register_heading_3_syntax()
123
- self._register_heading_syntax() # Shared pattern for regular headings
124
-
125
- self._register_divider_syntax()
126
- self._register_breadcrumb_syntax()
127
- self._register_table_of_contents_syntax()
128
- self._register_equation_syntax()
129
- self._register_embed_syntax()
130
- self._register_table_syntax()
131
- self._register_table_row_syntax()
132
-
133
- # Post-processing and utility blocks
134
- self._register_caption_syntax()
135
- self._register_space_syntax()
136
-
137
- def _register_audio_syntax(self) -> None:
138
- definition = SyntaxDefinition(
139
- start_delimiter="[audio](",
140
- end_delimiter=")",
141
- regex_pattern=re.compile(r"\[audio\]\(([^)]+)\)"),
142
- )
143
- self._definitions[SyntaxRegistryKey.AUDIO] = definition
144
-
145
- def _register_bookmark_syntax(self) -> None:
146
- definition = SyntaxDefinition(
147
- start_delimiter="[bookmark](",
148
- end_delimiter=")",
149
- regex_pattern=re.compile(r"\[bookmark\]\((https?://[^\s\"]+)\)"),
150
- )
151
- self._definitions[SyntaxRegistryKey.BOOKMARK] = definition
152
-
153
- def _register_breadcrumb_syntax(self) -> None:
154
- definition = SyntaxDefinition(
155
- start_delimiter="[breadcrumb]",
156
- end_delimiter="",
157
- regex_pattern=re.compile(r"^\[breadcrumb\]\s*$", re.IGNORECASE),
158
- )
159
- self._definitions[SyntaxRegistryKey.BREADCRUMB] = definition
160
-
161
- def _register_bulleted_list_syntax(self) -> None:
162
- definition = SyntaxDefinition(
163
- start_delimiter="- ",
164
- end_delimiter="",
165
- regex_pattern=re.compile(r"^(\s*)-\s+(?!\[[ xX]\])(.+)$"),
166
- )
167
- self._definitions[SyntaxRegistryKey.BULLETED_LIST] = definition
168
-
169
- def _register_callout_syntax(self) -> None:
170
- definition = SyntaxDefinition(
171
- start_delimiter="[callout]",
172
- end_delimiter=")",
173
- regex_pattern=re.compile(
174
- r'\[callout\](?:\(([^")]+?)(?:\s+"([^"]+)")?\)|(?:\s+([^"\n]+?)(?:\s+"([^"]+)")?)(?:\n|$))'
175
- ),
176
- )
177
- self._definitions[SyntaxRegistryKey.CALLOUT] = definition
178
-
179
- def _register_code_syntax(self) -> None:
180
- code_delimiter = "```"
181
- definition = SyntaxDefinition(
182
- start_delimiter=code_delimiter,
183
- end_delimiter=code_delimiter,
184
- regex_pattern=re.compile("^" + re.escape(code_delimiter) + r"(\w*)\s*$"),
185
- end_regex_pattern=re.compile("^" + re.escape(code_delimiter) + r"\s*$"),
186
- )
187
- self._definitions[SyntaxRegistryKey.CODE] = definition
188
-
189
- def _register_column_syntax(self) -> None:
190
- delimiter = self._markdown_grammar.column_delimiter
191
- definition = SyntaxDefinition(
192
- start_delimiter=f"{delimiter} column",
193
- end_delimiter=delimiter,
194
- regex_pattern=re.compile(
195
- rf"^{re.escape(delimiter)}\s*column(?:\s+(0?\.\d+|1(?:\.0?)?))??\s*$",
196
- re.IGNORECASE | re.MULTILINE,
197
- ),
198
- end_regex_pattern=re.compile(rf"^{re.escape(delimiter)}\s*$", re.MULTILINE),
199
- )
200
- self._definitions[SyntaxRegistryKey.COLUMN] = definition
201
-
202
- def _register_column_list_syntax(self) -> None:
203
- delimiter = self._markdown_grammar.column_delimiter
204
- definition = SyntaxDefinition(
205
- start_delimiter=f"{delimiter} columns",
206
- end_delimiter=delimiter,
207
- regex_pattern=re.compile(rf"^{re.escape(delimiter)}\s*columns?\s*$", re.IGNORECASE),
208
- end_regex_pattern=re.compile(rf"^{re.escape(delimiter)}\s*$"),
209
- )
210
- self._definitions[SyntaxRegistryKey.COLUMN_LIST] = definition
211
-
212
- def _register_divider_syntax(self) -> None:
213
- definition = SyntaxDefinition(
214
- start_delimiter="---",
215
- end_delimiter="",
216
- regex_pattern=re.compile(r"^\s*-{3,}\s*$"),
217
- )
218
- self._definitions[SyntaxRegistryKey.DIVIDER] = definition
219
-
220
- def _register_embed_syntax(self) -> None:
221
- definition = SyntaxDefinition(
222
- start_delimiter="[embed](",
223
- end_delimiter=")",
224
- regex_pattern=re.compile(r"\[embed\]\((https?://[^\s)]+)\)"),
225
- )
226
- self._definitions[SyntaxRegistryKey.EMBED] = definition
227
-
228
- def _register_equation_syntax(self) -> None:
229
- definition = SyntaxDefinition(
230
- start_delimiter="$$",
231
- end_delimiter="$$",
232
- regex_pattern=re.compile(r"^\$\$\s*$"),
233
- )
234
- self._definitions[SyntaxRegistryKey.EQUATION] = definition
235
-
236
- def _register_file_syntax(self) -> None:
237
- definition = SyntaxDefinition(
238
- start_delimiter="[file](",
239
- end_delimiter=")",
240
- regex_pattern=re.compile(r"\[file\]\(([^)]+)\)"),
241
- )
242
- self._definitions[SyntaxRegistryKey.FILE] = definition
243
-
244
- def _register_heading_1_syntax(self) -> None:
245
- definition = SyntaxDefinition(
246
- start_delimiter="# ",
247
- end_delimiter="",
248
- regex_pattern=re.compile(r"^#\s+(.+)$"),
249
- )
250
- self._definitions[SyntaxRegistryKey.HEADING_1] = definition
251
-
252
- def _register_heading_2_syntax(self) -> None:
253
- definition = SyntaxDefinition(
254
- start_delimiter="## ",
255
- end_delimiter="",
256
- regex_pattern=re.compile(r"^#{2}\s+(.+)$"),
257
- )
258
- self._definitions[SyntaxRegistryKey.HEADING_2] = definition
259
-
260
- def _register_heading_3_syntax(self) -> None:
261
- definition = SyntaxDefinition(
262
- start_delimiter="### ",
263
- end_delimiter="",
264
- regex_pattern=re.compile(r"^#{3}\s+(.+)$"),
265
- )
266
- self._definitions[SyntaxRegistryKey.HEADING_3] = definition
267
-
268
- def _register_image_syntax(self) -> None:
269
- definition = SyntaxDefinition(
270
- start_delimiter="[image](",
271
- end_delimiter=")",
272
- regex_pattern=re.compile(r"(?<!!)\[image\]\(([^)]+)\)"),
273
- )
274
- self._definitions[SyntaxRegistryKey.IMAGE] = definition
275
-
276
- def _register_numbered_list_syntax(self) -> None:
277
- definition = SyntaxDefinition(
278
- start_delimiter="1. ",
279
- end_delimiter="",
280
- regex_pattern=re.compile(r"^(\s*)(\d+)\.\s+(.+)$"),
281
- )
282
- self._definitions[SyntaxRegistryKey.NUMBERED_LIST] = definition
283
-
284
- def _register_pdf_syntax(self) -> None:
285
- definition = SyntaxDefinition(
286
- start_delimiter="[pdf](",
287
- end_delimiter=")",
288
- regex_pattern=re.compile(r"\[pdf\]\(([^)]+)\)"),
289
- )
290
- self._definitions[SyntaxRegistryKey.PDF] = definition
291
-
292
- def _register_quote_syntax(self) -> None:
293
- definition = SyntaxDefinition(
294
- start_delimiter="> ",
295
- end_delimiter="",
296
- regex_pattern=re.compile(r"^>(?!>)\s*(.+)$"),
297
- )
298
- self._definitions[SyntaxRegistryKey.QUOTE] = definition
299
-
300
- def _register_table_syntax(self) -> None:
301
- delimiter = self._markdown_grammar.table_delimiter
302
- definition = SyntaxDefinition(
303
- start_delimiter=delimiter,
304
- end_delimiter="",
305
- regex_pattern=re.compile(rf"^\s*{re.escape(delimiter)}(.+){re.escape(delimiter)}\s*$"),
306
- )
307
- self._definitions[SyntaxRegistryKey.TABLE] = definition
308
-
309
- def _register_table_row_syntax(self) -> None:
310
- delimiter = self._markdown_grammar.table_delimiter
311
- definition = SyntaxDefinition(
312
- start_delimiter=delimiter,
313
- end_delimiter="",
314
- regex_pattern=re.compile(rf"^\s*{re.escape(delimiter)}([\s\-:|]+){re.escape(delimiter)}\s*$"),
315
- )
316
- self._definitions[SyntaxRegistryKey.TABLE_ROW] = definition
317
-
318
- def _register_table_of_contents_syntax(self) -> None:
319
- definition = SyntaxDefinition(
320
- start_delimiter="[toc]",
321
- end_delimiter="",
322
- regex_pattern=re.compile(r"^\[toc\]$", re.IGNORECASE),
323
- )
324
- self._definitions[SyntaxRegistryKey.TABLE_OF_CONTENTS] = definition
325
-
326
- def _register_todo_syntax(self) -> None:
327
- definition = SyntaxDefinition(
328
- start_delimiter="- [ ]",
329
- end_delimiter="",
330
- regex_pattern=re.compile(r"^\s*-\s+\[ \]\s+(.+)$"),
331
- )
332
- self._definitions[SyntaxRegistryKey.TO_DO] = definition
333
-
334
- def _register_todo_done_syntax(self) -> None:
335
- definition = SyntaxDefinition(
336
- start_delimiter="- [x]",
337
- end_delimiter="",
338
- regex_pattern=re.compile(r"^\s*-\s+\[x\]\s+(.+)$", re.IGNORECASE),
339
- )
340
- self._definitions[SyntaxRegistryKey.TO_DO_DONE] = definition
341
-
342
- def _register_toggle_syntax(self) -> None:
343
- delimiter = self._markdown_grammar.toggle_delimiter
344
- definition = SyntaxDefinition(
345
- start_delimiter=delimiter,
346
- end_delimiter=delimiter,
347
- regex_pattern=re.compile(rf"^{re.escape(delimiter)}\s+(.+)$"),
348
- end_regex_pattern=re.compile(rf"^{re.escape(delimiter)}\s*$"),
349
- )
350
- self._definitions[SyntaxRegistryKey.TOGGLE] = definition
351
-
352
- def _register_toggleable_heading_syntax(self) -> None:
353
- delimiter = self._markdown_grammar.toggle_delimiter
354
- escaped_delimiter = re.escape(delimiter)
355
- definition = SyntaxDefinition(
356
- start_delimiter=f"{delimiter} #",
357
- end_delimiter=delimiter,
358
- regex_pattern=re.compile(rf"^{escaped_delimiter}\s*(?P<level>#{{1,3}})(?!#)\s*(.+)$", re.IGNORECASE),
359
- end_regex_pattern=re.compile(rf"^{escaped_delimiter}\s*$"),
360
- )
361
- self._definitions[SyntaxRegistryKey.TOGGLEABLE_HEADING] = definition
362
-
363
- def _register_video_syntax(self) -> None:
364
- definition = SyntaxDefinition(
365
- start_delimiter="[video](",
366
- end_delimiter=")",
367
- regex_pattern=re.compile(r"\[video\]\(([^)]+)\)"),
368
- )
369
- self._definitions[SyntaxRegistryKey.VIDEO] = definition
370
-
371
- def _register_caption_syntax(self) -> None:
372
- definition = SyntaxDefinition(
373
- start_delimiter="[caption]",
374
- end_delimiter="",
375
- regex_pattern=re.compile(r"^\[caption\]\s+(\S.*)$"),
376
- )
377
- self._definitions[SyntaxRegistryKey.CAPTION] = definition
378
-
379
- def _register_space_syntax(self) -> None:
380
- definition = SyntaxDefinition(
381
- start_delimiter="[space]",
382
- end_delimiter="",
383
- regex_pattern=re.compile(r"^\[space\]\s*$"),
384
- )
385
- self._definitions[SyntaxRegistryKey.SPACE] = definition
386
-
387
- def _register_heading_syntax(self) -> None:
388
- definition = SyntaxDefinition(
389
- start_delimiter="#",
390
- end_delimiter="",
391
- regex_pattern=re.compile(r"^(#{1,3})[ \t]+(.+)$"),
392
- )
393
- self._definitions[SyntaxRegistryKey.HEADING] = definition
@@ -1,50 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from contextvars import ContextVar
4
- from dataclasses import dataclass
5
- from typing import TYPE_CHECKING
6
-
7
- if TYPE_CHECKING:
8
- from notionary.file_upload import FileUploadHttpClient
9
-
10
-
11
- @dataclass(frozen=True)
12
- class PageContextProvider:
13
- """Context object that provides dependencies for block conversion operations."""
14
-
15
- page_id: str
16
- file_upload_client: FileUploadHttpClient
17
-
18
-
19
- # Context variable
20
- _page_context: ContextVar[PageContextProvider | None] = ContextVar("page_context", default=None)
21
-
22
-
23
- def get_page_context() -> PageContextProvider:
24
- """Get current page context or raise if not available."""
25
- context = _page_context.get()
26
- if context is None:
27
- raise RuntimeError("No page context available. Use 'async with page_context(...)'")
28
- return context
29
-
30
-
31
- class page_context:
32
- def __init__(self, provider: PageContextProvider) -> None:
33
- self.provider = provider
34
- self._token = None
35
-
36
- def _set_context(self) -> PageContextProvider:
37
- self._token = _page_context.set(self.provider)
38
- return self.provider
39
-
40
- def _reset_context(self) -> None:
41
- """Helper to reset context."""
42
- if self._token is not None:
43
- _page_context.reset(self._token)
44
-
45
- async def __aenter__(self) -> PageContextProvider:
46
- return self._set_context()
47
-
48
- async def __aexit__(self, exc_type, exc_val, exc_tb):
49
- self._reset_context()
50
- return False
@@ -1,20 +0,0 @@
1
- from enum import StrEnum
2
- from typing import Literal, Self
3
-
4
- from pydantic import BaseModel
5
-
6
- from notionary.shared.models.file import ExternalFile
7
-
8
-
9
- class CoverType(StrEnum):
10
- EXTERNAL = "external"
11
- FILE = "file"
12
-
13
-
14
- class NotionCover(BaseModel):
15
- type: Literal[CoverType.EXTERNAL, CoverType.FILE] = CoverType.EXTERNAL
16
- external: ExternalFile | None = None
17
-
18
- @classmethod
19
- def from_url(cls, url: str) -> Self:
20
- return cls(external=ExternalFile(url=url))