notionary 0.4.0__py3-none-any.whl → 0.4.2__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 (178) 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/schemas.py +1 -1
  153. notionary/shared/entity/service.py +53 -22
  154. notionary/shared/models/file.py +3 -1
  155. notionary/shared/models/icon.py +6 -4
  156. notionary/user/base.py +6 -2
  157. notionary/user/bot.py +10 -2
  158. notionary/user/client.py +3 -1
  159. notionary/user/person.py +3 -1
  160. notionary/user/schemas.py +3 -1
  161. notionary/user/service.py +6 -2
  162. notionary/utils/decorators.py +6 -2
  163. notionary/utils/fuzzy.py +6 -2
  164. notionary/utils/mixins/logging.py +3 -1
  165. notionary/utils/pagination.py +14 -4
  166. notionary/workspace/__init__.py +5 -1
  167. notionary/workspace/query/service.py +59 -16
  168. notionary/workspace/service.py +39 -11
  169. {notionary-0.4.0.dist-info → notionary-0.4.2.dist-info}/METADATA +1 -1
  170. notionary-0.4.2.dist-info/RECORD +236 -0
  171. notionary/page/blocks/client.py +0 -1
  172. notionary/page/content/syntax/__init__.py +0 -5
  173. notionary/page/content/syntax/models.py +0 -66
  174. notionary/page/content/syntax/registry.py +0 -371
  175. notionary-0.4.0.dist-info/RECORD +0 -230
  176. /notionary/page/content/syntax/{grammar.py → definition/grammar.py} +0 -0
  177. {notionary-0.4.0.dist-info → notionary-0.4.2.dist-info}/WHEEL +0 -0
  178. {notionary-0.4.0.dist-info → notionary-0.4.2.dist-info}/licenses/LICENSE +0 -0
@@ -2,11 +2,11 @@ from typing import override
2
2
 
3
3
  from notionary.blocks.schemas import CreateEmbedBlock, EmbedData
4
4
  from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
5
- from notionary.page.content.syntax import SyntaxRegistry
5
+ from notionary.page.content.syntax.definition import SyntaxDefinitionRegistry
6
6
 
7
7
 
8
8
  class EmbedParser(LineParser):
9
- def __init__(self, syntax_registry: SyntaxRegistry) -> None:
9
+ def __init__(self, syntax_registry: SyntaxDefinitionRegistry) -> None:
10
10
  super().__init__(syntax_registry)
11
11
  self._syntax = syntax_registry.get_embed_syntax()
12
12
 
@@ -5,11 +5,11 @@ from notionary.page.content.parser.parsers.base import (
5
5
  BlockParsingContext,
6
6
  LineParser,
7
7
  )
8
- from notionary.page.content.syntax import SyntaxRegistry
8
+ from notionary.page.content.syntax.definition import SyntaxDefinitionRegistry
9
9
 
10
10
 
11
11
  class EquationParser(LineParser):
12
- def __init__(self, syntax_registry: SyntaxRegistry) -> None:
12
+ def __init__(self, syntax_registry: SyntaxDefinitionRegistry) -> None:
13
13
  super().__init__(syntax_registry)
14
14
  self._syntax = syntax_registry.get_equation_syntax()
15
15
 
@@ -24,7 +24,9 @@ class EquationParser(LineParser):
24
24
  equation_content = self._collect_equation_content(context)
25
25
  lines_consumed = self._count_lines_consumed(context)
26
26
 
27
- block = self._create_equation_block(opening_line=context.line, equation_lines=equation_content)
27
+ block = self._create_equation_block(
28
+ opening_line=context.line, equation_lines=equation_content
29
+ )
28
30
 
29
31
  if block:
30
32
  context.lines_consumed = lines_consumed
@@ -50,7 +52,9 @@ class EquationParser(LineParser):
50
52
 
51
53
  return len(context.get_remaining_lines())
52
54
 
53
- def _create_equation_block(self, opening_line: str, equation_lines: list[str]) -> CreateEquationBlock | None:
55
+ def _create_equation_block(
56
+ self, opening_line: str, equation_lines: list[str]
57
+ ) -> CreateEquationBlock | None:
54
58
  if opening_line.strip() != self._syntax.start_delimiter:
55
59
  return None
56
60
 
@@ -2,12 +2,17 @@ from typing import override
2
2
 
3
3
  from notionary.blocks.schemas import CreateFileBlock, ExternalFileWithCaption
4
4
  from notionary.page.content.parser.parsers.file_like_block import FileLikeBlockParser
5
- from notionary.page.content.syntax import SyntaxDefinition, SyntaxRegistry
5
+ from notionary.page.content.syntax.definition import (
6
+ SyntaxDefinition,
7
+ SyntaxDefinitionRegistry,
8
+ )
6
9
 
7
10
 
8
11
  class FileParser(FileLikeBlockParser[CreateFileBlock]):
9
12
  @override
10
- def _get_syntax(self, syntax_registry: SyntaxRegistry) -> SyntaxDefinition:
13
+ def _get_syntax(
14
+ self, syntax_registry: SyntaxDefinitionRegistry
15
+ ) -> SyntaxDefinition:
11
16
  return syntax_registry.get_file_syntax()
12
17
 
13
18
  @override
@@ -10,8 +10,8 @@ from notionary.blocks.schemas import (
10
10
  from notionary.exceptions.file_upload import UploadFailedError, UploadTimeoutError
11
11
  from notionary.file_upload.service import NotionFileUpload
12
12
  from notionary.page.content.parser.parsers.base import BlockParsingContext, LineParser
13
- from notionary.page.content.syntax import SyntaxRegistry
14
- from notionary.page.content.syntax.models import SyntaxDefinition
13
+ from notionary.page.content.syntax.definition import SyntaxDefinitionRegistry
14
+ from notionary.page.content.syntax.definition.models import SyntaxDefinition
15
15
  from notionary.shared.models.file import ExternalFileData, FileUploadedFileData
16
16
  from notionary.utils.mixins.logging import LoggingMixin
17
17
 
@@ -19,13 +19,19 @@ _TBlock = TypeVar("_TBlock")
19
19
 
20
20
 
21
21
  class FileLikeBlockParser(LineParser, LoggingMixin, Generic[_TBlock]):
22
- def __init__(self, syntax_registry: SyntaxRegistry, file_upload_service: NotionFileUpload | None = None) -> None:
22
+ def __init__(
23
+ self,
24
+ syntax_registry: SyntaxDefinitionRegistry,
25
+ file_upload_service: NotionFileUpload | None = None,
26
+ ) -> None:
23
27
  super().__init__(syntax_registry)
24
28
  self._syntax = self._get_syntax(syntax_registry)
25
29
  self._file_upload_service = file_upload_service or NotionFileUpload()
26
30
 
27
31
  @abstractmethod
28
- def _get_syntax(self, syntax_registry: SyntaxRegistry) -> SyntaxDefinition:
32
+ def _get_syntax(
33
+ self, syntax_registry: SyntaxDefinitionRegistry
34
+ ) -> SyntaxDefinition:
29
35
  pass
30
36
 
31
37
  @abstractmethod
@@ -46,7 +52,9 @@ class FileLikeBlockParser(LineParser, LoggingMixin, Generic[_TBlock]):
46
52
 
47
53
  try:
48
54
  if self._is_external_url(path_or_url):
49
- file_data = ExternalFileWithCaption(external=ExternalFileData(url=path_or_url))
55
+ file_data = ExternalFileWithCaption(
56
+ external=ExternalFileData(url=path_or_url)
57
+ )
50
58
  else:
51
59
  file_data = await self._upload_local_file(path_or_url)
52
60
 
@@ -56,15 +64,27 @@ class FileLikeBlockParser(LineParser, LoggingMixin, Generic[_TBlock]):
56
64
  except FileNotFoundError:
57
65
  self.logger.warning("File not found: '%s' - skipping block", path_or_url)
58
66
  except PermissionError:
59
- self.logger.warning("No permission to read file: '%s' - skipping block", path_or_url)
67
+ self.logger.warning(
68
+ "No permission to read file: '%s' - skipping block", path_or_url
69
+ )
60
70
  except IsADirectoryError:
61
- self.logger.warning("Path is a directory, not a file: '%s' - skipping block", path_or_url)
71
+ self.logger.warning(
72
+ "Path is a directory, not a file: '%s' - skipping block", path_or_url
73
+ )
62
74
  except (UploadFailedError, UploadTimeoutError) as e:
63
- self.logger.warning("Upload failed for '%s': %s - skipping block", path_or_url, e)
75
+ self.logger.warning(
76
+ "Upload failed for '%s': %s - skipping block", path_or_url, e
77
+ )
64
78
  except OSError as e:
65
- self.logger.warning("IO error reading file '%s': %s - skipping block", path_or_url, e)
79
+ self.logger.warning(
80
+ "IO error reading file '%s': %s - skipping block", path_or_url, e
81
+ )
66
82
  except Exception as e:
67
- self.logger.warning("Unexpected error processing file '%s': %s - skipping block", path_or_url, e)
83
+ self.logger.warning(
84
+ "Unexpected error processing file '%s': %s - skipping block",
85
+ path_or_url,
86
+ e,
87
+ )
68
88
 
69
89
  def _extract_path_or_url(self, line: str) -> str | None:
70
90
  match = self._syntax.regex_pattern.search(line)
@@ -1,6 +1,8 @@
1
1
  from typing import override
2
2
 
3
- from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
3
+ from notionary.blocks.rich_text.markdown_rich_text_converter import (
4
+ MarkdownRichTextConverter,
5
+ )
4
6
  from notionary.blocks.schemas import (
5
7
  BlockColor,
6
8
  BlockCreatePayload,
@@ -15,14 +17,18 @@ from notionary.page.content.parser.parsers.base import (
15
17
  BlockParsingContext,
16
18
  LineParser,
17
19
  )
18
- from notionary.page.content.syntax import SyntaxRegistry
20
+ from notionary.page.content.syntax.definition import SyntaxDefinitionRegistry
19
21
 
20
22
 
21
23
  class HeadingParser(LineParser):
22
24
  MIN_HEADING_LEVEL = 1
23
25
  MAX_HEADING_LEVEL = 3
24
26
 
25
- def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
27
+ def __init__(
28
+ self,
29
+ syntax_registry: SyntaxDefinitionRegistry,
30
+ rich_text_converter: MarkdownRichTextConverter,
31
+ ) -> None:
26
32
  super().__init__(syntax_registry)
27
33
  self._syntax = syntax_registry.get_heading_syntax()
28
34
  self._rich_text_converter = rich_text_converter
@@ -42,7 +48,9 @@ class HeadingParser(LineParser):
42
48
  await self._process_nested_children(block, context)
43
49
  context.result_blocks.append(block)
44
50
 
45
- async def _process_nested_children(self, block: CreateHeadingBlock, context: BlockParsingContext) -> None:
51
+ async def _process_nested_children(
52
+ self, block: CreateHeadingBlock, context: BlockParsingContext
53
+ ) -> None:
46
54
  parent_indent_level = context.get_line_indentation_level()
47
55
  child_lines = context.collect_indented_child_lines(parent_indent_level)
48
56
 
@@ -64,7 +72,9 @@ class HeadingParser(LineParser):
64
72
 
65
73
  context.lines_consumed = len(child_lines)
66
74
 
67
- def _set_heading_toggleable(self, block: CreateHeadingBlock, is_toggleable: bool) -> None:
75
+ def _set_heading_toggleable(
76
+ self, block: CreateHeadingBlock, is_toggleable: bool
77
+ ) -> None:
68
78
  if block.type == BlockType.HEADING_1:
69
79
  block.heading_1.is_toggleable = is_toggleable
70
80
  elif block.type == BlockType.HEADING_2:
@@ -72,7 +82,9 @@ class HeadingParser(LineParser):
72
82
  elif block.type == BlockType.HEADING_3:
73
83
  block.heading_3.is_toggleable = is_toggleable
74
84
 
75
- def _set_heading_children(self, block: CreateHeadingBlock, children: list[BlockCreatePayload]) -> None:
85
+ def _set_heading_children(
86
+ self, block: CreateHeadingBlock, children: list[BlockCreatePayload]
87
+ ) -> None:
76
88
  if block.type == BlockType.HEADING_1:
77
89
  block.heading_1.children = children
78
90
  elif block.type == BlockType.HEADING_2:
@@ -100,13 +112,22 @@ class HeadingParser(LineParser):
100
112
  return self._create_heading_block_by_level(level, heading_data)
101
113
 
102
114
  def _is_valid_heading(self, level: int, content: str) -> bool:
103
- return self.MIN_HEADING_LEVEL <= level <= self.MAX_HEADING_LEVEL and bool(content)
115
+ return self.MIN_HEADING_LEVEL <= level <= self.MAX_HEADING_LEVEL and bool(
116
+ content
117
+ )
104
118
 
105
119
  async def _build_heading_data(self, content: str) -> CreateHeadingData:
106
120
  rich_text = await self._rich_text_converter.to_rich_text(content)
107
- return CreateHeadingData(rich_text=rich_text, color=BlockColor.DEFAULT, is_toggleable=False, children=[])
108
-
109
- def _create_heading_block_by_level(self, level: int, heading_data: CreateHeadingData) -> CreateHeadingBlock:
121
+ return CreateHeadingData(
122
+ rich_text=rich_text,
123
+ color=BlockColor.DEFAULT,
124
+ is_toggleable=False,
125
+ children=[],
126
+ )
127
+
128
+ def _create_heading_block_by_level(
129
+ self, level: int, heading_data: CreateHeadingData
130
+ ) -> CreateHeadingBlock:
110
131
  if level == 1:
111
132
  return CreateHeading1Block(heading_1=heading_data)
112
133
  elif level == 2:
@@ -2,12 +2,17 @@ from typing import override
2
2
 
3
3
  from notionary.blocks.schemas import CreateImageBlock, ExternalFileWithCaption
4
4
  from notionary.page.content.parser.parsers.file_like_block import FileLikeBlockParser
5
- from notionary.page.content.syntax import SyntaxDefinition, SyntaxRegistry
5
+ from notionary.page.content.syntax.definition import (
6
+ SyntaxDefinition,
7
+ SyntaxDefinitionRegistry,
8
+ )
6
9
 
7
10
 
8
11
  class ImageParser(FileLikeBlockParser[CreateImageBlock]):
9
12
  @override
10
- def _get_syntax(self, syntax_registry: SyntaxRegistry) -> SyntaxDefinition:
13
+ def _get_syntax(
14
+ self, syntax_registry: SyntaxDefinitionRegistry
15
+ ) -> SyntaxDefinition:
11
16
  return syntax_registry.get_image_syntax()
12
17
 
13
18
  @override
@@ -12,11 +12,15 @@ from notionary.page.content.parser.parsers.base import (
12
12
  BlockParsingContext,
13
13
  LineParser,
14
14
  )
15
- from notionary.page.content.syntax import SyntaxRegistry
15
+ from notionary.page.content.syntax.definition import SyntaxDefinitionRegistry
16
16
 
17
17
 
18
18
  class NumberedListParser(LineParser):
19
- def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
19
+ def __init__(
20
+ self,
21
+ syntax_registry: SyntaxDefinitionRegistry,
22
+ rich_text_converter: MarkdownRichTextConverter,
23
+ ) -> None:
20
24
  super().__init__(syntax_registry)
21
25
  self._syntax = syntax_registry.get_numbered_list_syntax()
22
26
  self._rich_text_converter = rich_text_converter
@@ -39,7 +43,9 @@ class NumberedListParser(LineParser):
39
43
  await self._process_nested_children(block, context)
40
44
  context.result_blocks.append(block)
41
45
 
42
- async def _process_nested_children(self, block: CreateNumberedListItemBlock, context: BlockParsingContext) -> None:
46
+ async def _process_nested_children(
47
+ self, block: CreateNumberedListItemBlock, context: BlockParsingContext
48
+ ) -> None:
43
49
  child_lines = self._collect_child_lines(context)
44
50
  if not child_lines:
45
51
  return
@@ -61,13 +67,17 @@ class NumberedListParser(LineParser):
61
67
  children_text = self._convert_lines_to_text(stripped_lines)
62
68
  return await context.parse_nested_markdown(children_text)
63
69
 
64
- def _remove_parent_indentation(self, lines: list[str], context: BlockParsingContext) -> list[str]:
70
+ def _remove_parent_indentation(
71
+ self, lines: list[str], context: BlockParsingContext
72
+ ) -> list[str]:
65
73
  return context.strip_indentation_level(lines, levels=1)
66
74
 
67
75
  def _convert_lines_to_text(self, lines: list[str]) -> str:
68
76
  return "\n".join(lines)
69
77
 
70
- async def _create_numbered_list_block(self, text: str) -> CreateNumberedListItemBlock | None:
78
+ async def _create_numbered_list_block(
79
+ self, text: str
80
+ ) -> CreateNumberedListItemBlock | None:
71
81
  content = self._extract_list_content(text)
72
82
  if content is None:
73
83
  return None
@@ -85,5 +95,7 @@ class NumberedListParser(LineParser):
85
95
  return await self._rich_text_converter.to_rich_text(content)
86
96
 
87
97
  def _build_block(self, rich_text) -> CreateNumberedListItemBlock:
88
- numbered_list_content = CreateNumberedListItemData(rich_text=rich_text, color=BlockColor.DEFAULT)
98
+ numbered_list_content = CreateNumberedListItemData(
99
+ rich_text=rich_text, color=BlockColor.DEFAULT
100
+ )
89
101
  return CreateNumberedListItemBlock(numbered_list_item=numbered_list_content)
@@ -33,5 +33,7 @@ class ParagraphParser(LineParser):
33
33
  return None
34
34
 
35
35
  rich_text = await self._rich_text_converter.to_rich_text(text)
36
- paragraph_content = CreateParagraphData(rich_text=rich_text, color=BlockColor.DEFAULT)
36
+ paragraph_content = CreateParagraphData(
37
+ rich_text=rich_text, color=BlockColor.DEFAULT
38
+ )
37
39
  return CreateParagraphBlock(paragraph=paragraph_content)
@@ -2,12 +2,17 @@ from typing import override
2
2
 
3
3
  from notionary.blocks.schemas import CreatePdfBlock, ExternalFileWithCaption
4
4
  from notionary.page.content.parser.parsers.file_like_block import FileLikeBlockParser
5
- from notionary.page.content.syntax import SyntaxDefinition, SyntaxRegistry
5
+ from notionary.page.content.syntax.definition import (
6
+ SyntaxDefinition,
7
+ SyntaxDefinitionRegistry,
8
+ )
6
9
 
7
10
 
8
11
  class PdfParser(FileLikeBlockParser[CreatePdfBlock]):
9
12
  @override
10
- def _get_syntax(self, syntax_registry: SyntaxRegistry) -> SyntaxDefinition:
13
+ def _get_syntax(
14
+ self, syntax_registry: SyntaxDefinitionRegistry
15
+ ) -> SyntaxDefinition:
11
16
  return syntax_registry.get_pdf_syntax()
12
17
 
13
18
  @override
@@ -1,16 +1,22 @@
1
1
  from typing import override
2
2
 
3
- from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
3
+ from notionary.blocks.rich_text.markdown_rich_text_converter import (
4
+ MarkdownRichTextConverter,
5
+ )
4
6
  from notionary.blocks.schemas import BlockColor, CreateQuoteBlock, CreateQuoteData
5
7
  from notionary.page.content.parser.parsers.base import (
6
8
  BlockParsingContext,
7
9
  LineParser,
8
10
  )
9
- from notionary.page.content.syntax import SyntaxRegistry
11
+ from notionary.page.content.syntax.definition import SyntaxDefinitionRegistry
10
12
 
11
13
 
12
14
  class QuoteParser(LineParser):
13
- def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
15
+ def __init__(
16
+ self,
17
+ syntax_registry: SyntaxDefinitionRegistry,
18
+ rich_text_converter: MarkdownRichTextConverter,
19
+ ) -> None:
14
20
  super().__init__(syntax_registry)
15
21
  self._syntax = syntax_registry.get_quote_syntax()
16
22
  self._rich_text_converter = rich_text_converter
@@ -47,11 +53,16 @@ class QuoteParser(LineParser):
47
53
  return quote_lines
48
54
 
49
55
  async def _process_nested_children(
50
- self, block: CreateQuoteBlock, context: BlockParsingContext, quote_lines: list[str]
56
+ self,
57
+ block: CreateQuoteBlock,
58
+ context: BlockParsingContext,
59
+ quote_lines: list[str],
51
60
  ) -> None:
52
61
  # Calculate indent level after all quote lines
53
62
  last_quote_line_index = len(quote_lines) - 1
54
- child_lines = self._collect_child_lines_after_quote(context, last_quote_line_index)
63
+ child_lines = self._collect_child_lines_after_quote(
64
+ context, last_quote_line_index
65
+ )
55
66
 
56
67
  if not child_lines:
57
68
  return
@@ -62,7 +73,9 @@ class QuoteParser(LineParser):
62
73
 
63
74
  context.lines_consumed += len(child_lines)
64
75
 
65
- def _collect_child_lines_after_quote(self, context: BlockParsingContext, last_quote_index: int) -> list[str]:
76
+ def _collect_child_lines_after_quote(
77
+ self, context: BlockParsingContext, last_quote_index: int
78
+ ) -> list[str]:
66
79
  """Collect indented children after the quote block."""
67
80
  parent_indent_level = context.get_line_indentation_level()
68
81
  remaining_lines = context.get_remaining_lines()
@@ -86,18 +99,24 @@ class QuoteParser(LineParser):
86
99
 
87
100
  return child_lines
88
101
 
89
- async def _parse_child_blocks(self, child_lines: list[str], context: BlockParsingContext) -> list[CreateQuoteBlock]:
102
+ async def _parse_child_blocks(
103
+ self, child_lines: list[str], context: BlockParsingContext
104
+ ) -> list[CreateQuoteBlock]:
90
105
  stripped_lines = self._remove_parent_indentation(child_lines, context)
91
106
  children_text = self._convert_lines_to_text(stripped_lines)
92
107
  return await context.parse_nested_markdown(children_text)
93
108
 
94
- def _remove_parent_indentation(self, lines: list[str], context: BlockParsingContext) -> list[str]:
109
+ def _remove_parent_indentation(
110
+ self, lines: list[str], context: BlockParsingContext
111
+ ) -> list[str]:
95
112
  return context.strip_indentation_level(lines, levels=1)
96
113
 
97
114
  def _convert_lines_to_text(self, lines: list[str]) -> str:
98
115
  return "\n".join(lines)
99
116
 
100
- async def _create_quote_block(self, quote_lines: list[str]) -> CreateQuoteBlock | None:
117
+ async def _create_quote_block(
118
+ self, quote_lines: list[str]
119
+ ) -> CreateQuoteBlock | None:
101
120
  contents = self._extract_quote_contents(quote_lines)
102
121
  if not contents:
103
122
  return None
@@ -6,11 +6,11 @@ from notionary.page.content.parser.parsers.base import (
6
6
  BlockParsingContext,
7
7
  LineParser,
8
8
  )
9
- from notionary.page.content.syntax import SyntaxRegistry
9
+ from notionary.page.content.syntax.definition import SyntaxDefinitionRegistry
10
10
 
11
11
 
12
12
  class SpaceParser(LineParser):
13
- def __init__(self, syntax_registry: SyntaxRegistry) -> None:
13
+ def __init__(self, syntax_registry: SyntaxDefinitionRegistry) -> None:
14
14
  super().__init__(syntax_registry)
15
15
  self._syntax = syntax_registry.get_space_syntax()
16
16
 
@@ -1,14 +1,25 @@
1
1
  from typing import override
2
2
 
3
- from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
3
+ from notionary.blocks.rich_text.markdown_rich_text_converter import (
4
+ MarkdownRichTextConverter,
5
+ )
4
6
  from notionary.blocks.rich_text.models import RichText
5
- from notionary.blocks.schemas import CreateTableBlock, CreateTableData, CreateTableRowBlock, TableRowData
7
+ from notionary.blocks.schemas import (
8
+ CreateTableBlock,
9
+ CreateTableData,
10
+ CreateTableRowBlock,
11
+ TableRowData,
12
+ )
6
13
  from notionary.page.content.parser.parsers import BlockParsingContext, LineParser
7
- from notionary.page.content.syntax import SyntaxRegistry
14
+ from notionary.page.content.syntax.definition import SyntaxDefinitionRegistry
8
15
 
9
16
 
10
17
  class TableParser(LineParser):
11
- def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
18
+ def __init__(
19
+ self,
20
+ syntax_registry: SyntaxDefinitionRegistry,
21
+ rich_text_converter: MarkdownRichTextConverter,
22
+ ) -> None:
12
23
  super().__init__(syntax_registry)
13
24
  self._syntax = syntax_registry.get_table_syntax()
14
25
  self._separator_syntax = syntax_registry.get_table_row_syntax()
@@ -41,7 +52,9 @@ class TableParser(LineParser):
41
52
  context.lines_consumed = lines_consumed
42
53
  context.result_blocks.append(block)
43
54
 
44
- def _collect_table_lines(self, table_lines: list[str], remaining_lines: list[str]) -> int:
55
+ def _collect_table_lines(
56
+ self, table_lines: list[str], remaining_lines: list[str]
57
+ ) -> int:
45
58
  lines_consumed = 0
46
59
 
47
60
  for index, line in enumerate(remaining_lines):
@@ -62,9 +75,13 @@ class TableParser(LineParser):
62
75
  return lines_consumed
63
76
 
64
77
  def _is_table_line(self, line: str) -> bool:
65
- return self._syntax.regex_pattern.match(line) or self._separator_syntax.regex_pattern.match(line)
78
+ return self._syntax.regex_pattern.match(
79
+ line
80
+ ) or self._separator_syntax.regex_pattern.match(line)
66
81
 
67
- async def _create_table_block(self, table_lines: list[str]) -> CreateTableBlock | None:
82
+ async def _create_table_block(
83
+ self, table_lines: list[str]
84
+ ) -> CreateTableBlock | None:
68
85
  if not table_lines:
69
86
  return None
70
87
 
@@ -93,7 +110,9 @@ class TableParser(LineParser):
93
110
  return line_stripped
94
111
  return None
95
112
 
96
- async def _process_table_rows(self, table_lines: list[str]) -> tuple[list[CreateTableRowBlock], bool]:
113
+ async def _process_table_rows(
114
+ self, table_lines: list[str]
115
+ ) -> tuple[list[CreateTableRowBlock], bool]:
97
116
  table_rows = []
98
117
  has_separator = False
99
118
 
@@ -122,7 +141,9 @@ class TableParser(LineParser):
122
141
  table_row_data = TableRowData(cells=rich_text_cells)
123
142
  return CreateTableRowBlock(table_row=table_row_data)
124
143
 
125
- async def _convert_cells_to_rich_text(self, cells: list[str]) -> list[list[RichText]]:
144
+ async def _convert_cells_to_rich_text(
145
+ self, cells: list[str]
146
+ ) -> list[list[RichText]]:
126
147
  rich_text_cells = []
127
148
 
128
149
  for cell in cells:
@@ -132,7 +153,7 @@ class TableParser(LineParser):
132
153
  return rich_text_cells
133
154
 
134
155
  def _parse_table_row(self, row_text: str) -> list[str]:
135
- """Parse a table row by splitting on the table delimiter from SyntaxRegistry."""
156
+ """Parse a table row by splitting on the table delimiter from SyntaxDefinitionRegistry."""
136
157
  row_content = row_text.strip()
137
158
  delimiter = self._syntax.start_delimiter
138
159
 
@@ -1,15 +1,19 @@
1
1
  from typing import override
2
2
 
3
- from notionary.blocks.schemas import BlockColor, CreateTableOfContentsBlock, TableOfContentsData
3
+ from notionary.blocks.schemas import (
4
+ BlockColor,
5
+ CreateTableOfContentsBlock,
6
+ TableOfContentsData,
7
+ )
4
8
  from notionary.page.content.parser.parsers.base import (
5
9
  BlockParsingContext,
6
10
  LineParser,
7
11
  )
8
- from notionary.page.content.syntax import SyntaxRegistry
12
+ from notionary.page.content.syntax.definition import SyntaxDefinitionRegistry
9
13
 
10
14
 
11
15
  class TableOfContentsParser(LineParser):
12
- def __init__(self, syntax_registry: SyntaxRegistry) -> None:
16
+ def __init__(self, syntax_registry: SyntaxDefinitionRegistry) -> None:
13
17
  super().__init__(syntax_registry)
14
18
  self._syntax = syntax_registry.get_table_of_contents_syntax()
15
19
 
@@ -8,11 +8,15 @@ from notionary.page.content.parser.parsers.base import (
8
8
  BlockParsingContext,
9
9
  LineParser,
10
10
  )
11
- from notionary.page.content.syntax import SyntaxRegistry
11
+ from notionary.page.content.syntax.definition import SyntaxDefinitionRegistry
12
12
 
13
13
 
14
14
  class TodoParser(LineParser):
15
- def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
15
+ def __init__(
16
+ self,
17
+ syntax_registry: SyntaxDefinitionRegistry,
18
+ rich_text_converter: MarkdownRichTextConverter,
19
+ ) -> None:
16
20
  super().__init__(syntax_registry)
17
21
  self._syntax = syntax_registry.get_todo_syntax()
18
22
  self._syntax_done = syntax_registry.get_todo_done_syntax()
@@ -39,7 +43,9 @@ class TodoParser(LineParser):
39
43
  await self._process_nested_children(block, context)
40
44
  context.result_blocks.append(block)
41
45
 
42
- async def _process_nested_children(self, block: CreateToDoBlock, context: BlockParsingContext) -> None:
46
+ async def _process_nested_children(
47
+ self, block: CreateToDoBlock, context: BlockParsingContext
48
+ ) -> None:
43
49
  child_lines = self._collect_child_lines(context)
44
50
  if not child_lines:
45
51
  return
@@ -54,12 +60,16 @@ class TodoParser(LineParser):
54
60
  parent_indent_level = context.get_line_indentation_level()
55
61
  return context.collect_indented_child_lines(parent_indent_level)
56
62
 
57
- async def _parse_child_blocks(self, child_lines: list[str], context: BlockParsingContext) -> list[CreateToDoBlock]:
63
+ async def _parse_child_blocks(
64
+ self, child_lines: list[str], context: BlockParsingContext
65
+ ) -> list[CreateToDoBlock]:
58
66
  stripped_lines = self._remove_parent_indentation(child_lines, context)
59
67
  children_text = self._convert_lines_to_text(stripped_lines)
60
68
  return await context.parse_nested_markdown(children_text)
61
69
 
62
- def _remove_parent_indentation(self, lines: list[str], context: BlockParsingContext) -> list[str]:
70
+ def _remove_parent_indentation(
71
+ self, lines: list[str], context: BlockParsingContext
72
+ ) -> list[str]:
63
73
  return context.strip_indentation_level(lines, levels=1)
64
74
 
65
75
  def _convert_lines_to_text(self, lines: list[str]) -> str:
@@ -1,16 +1,22 @@
1
1
  from typing import override
2
2
 
3
- from notionary.blocks.rich_text.markdown_rich_text_converter import MarkdownRichTextConverter
3
+ from notionary.blocks.rich_text.markdown_rich_text_converter import (
4
+ MarkdownRichTextConverter,
5
+ )
4
6
  from notionary.blocks.schemas import BlockColor, CreateToggleBlock, CreateToggleData
5
7
  from notionary.page.content.parser.parsers import (
6
8
  BlockParsingContext,
7
9
  LineParser,
8
10
  )
9
- from notionary.page.content.syntax import SyntaxRegistry
11
+ from notionary.page.content.syntax.definition import SyntaxDefinitionRegistry
10
12
 
11
13
 
12
14
  class ToggleParser(LineParser):
13
- def __init__(self, syntax_registry: SyntaxRegistry, rich_text_converter: MarkdownRichTextConverter) -> None:
15
+ def __init__(
16
+ self,
17
+ syntax_registry: SyntaxDefinitionRegistry,
18
+ rich_text_converter: MarkdownRichTextConverter,
19
+ ) -> None:
14
20
  super().__init__(syntax_registry)
15
21
  self._syntax = syntax_registry.get_toggle_syntax()
16
22
  self._heading_syntax = syntax_registry.get_toggleable_heading_syntax()
@@ -51,10 +57,14 @@ class ToggleParser(LineParser):
51
57
  title = match.group(1).strip()
52
58
  rich_text = await self._rich_text_converter.to_rich_text(title)
53
59
 
54
- toggle_content = CreateToggleData(rich_text=rich_text, color=BlockColor.DEFAULT, children=[])
60
+ toggle_content = CreateToggleData(
61
+ rich_text=rich_text, color=BlockColor.DEFAULT, children=[]
62
+ )
55
63
  return CreateToggleBlock(toggle=toggle_content)
56
64
 
57
- async def _process_nested_children(self, block: CreateToggleBlock, context: BlockParsingContext) -> None:
65
+ async def _process_nested_children(
66
+ self, block: CreateToggleBlock, context: BlockParsingContext
67
+ ) -> None:
58
68
  parent_indent_level = context.get_line_indentation_level()
59
69
  child_lines = context.collect_indented_child_lines(parent_indent_level)
60
70
 
@@ -2,12 +2,17 @@ from typing import override
2
2
 
3
3
  from notionary.blocks.schemas import CreateVideoBlock, ExternalFileWithCaption
4
4
  from notionary.page.content.parser.parsers.file_like_block import FileLikeBlockParser
5
- from notionary.page.content.syntax import SyntaxDefinition, SyntaxRegistry
5
+ from notionary.page.content.syntax.definition import (
6
+ SyntaxDefinition,
7
+ SyntaxDefinitionRegistry,
8
+ )
6
9
 
7
10
 
8
11
  class VideoParser(FileLikeBlockParser[CreateVideoBlock]):
9
12
  @override
10
- def _get_syntax(self, syntax_registry: SyntaxRegistry) -> SyntaxDefinition:
13
+ def _get_syntax(
14
+ self, syntax_registry: SyntaxDefinitionRegistry
15
+ ) -> SyntaxDefinition:
11
16
  return syntax_registry.get_video_syntax()
12
17
 
13
18
  @override