notionary 0.2.13__py3-none-any.whl → 0.2.14__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 (82) hide show
  1. notionary/__init__.py +3 -16
  2. notionary/{notion_client.py → base_notion_client.py} +92 -98
  3. notionary/blocks/__init__.py +61 -0
  4. notionary/{elements → blocks}/audio_element.py +6 -3
  5. notionary/{elements → blocks}/bookmark_element.py +3 -5
  6. notionary/{elements → blocks}/bulleted_list_element.py +5 -6
  7. notionary/{elements → blocks}/callout_element.py +4 -6
  8. notionary/{elements → blocks}/code_block_element.py +4 -5
  9. notionary/{elements → blocks}/column_element.py +3 -5
  10. notionary/{elements → blocks}/divider_element.py +3 -5
  11. notionary/{elements → blocks}/embed_element.py +4 -5
  12. notionary/{elements → blocks}/heading_element.py +4 -7
  13. notionary/{elements → blocks}/image_element.py +4 -5
  14. notionary/{elements → blocks}/mention_element.py +3 -6
  15. notionary/blocks/notion_block_client.py +26 -0
  16. notionary/{elements → blocks}/notion_block_element.py +2 -3
  17. notionary/{elements → blocks}/numbered_list_element.py +4 -6
  18. notionary/{elements → blocks}/paragraph_element.py +4 -6
  19. notionary/{prompting/element_prompt_content.py → blocks/prompts/element_prompt_builder.py} +1 -40
  20. notionary/blocks/prompts/element_prompt_content.py +41 -0
  21. notionary/{elements → blocks}/qoute_element.py +4 -5
  22. notionary/{elements → blocks}/registry/block_registry.py +4 -26
  23. notionary/{elements → blocks}/registry/block_registry_builder.py +26 -25
  24. notionary/{elements → blocks}/table_element.py +5 -6
  25. notionary/{elements → blocks}/text_inline_formatter.py +1 -4
  26. notionary/{elements → blocks}/todo_element.py +5 -6
  27. notionary/{elements → blocks}/toggle_element.py +3 -5
  28. notionary/{elements → blocks}/toggleable_heading_element.py +4 -6
  29. notionary/{elements → blocks}/video_element.py +4 -5
  30. notionary/cli/main.py +157 -128
  31. notionary/cli/onboarding.py +10 -9
  32. notionary/database/__init__.py +0 -0
  33. notionary/database/client.py +132 -0
  34. notionary/database/database_exceptions.py +13 -0
  35. notionary/database/factory.py +0 -0
  36. notionary/database/filter_builder.py +175 -0
  37. notionary/database/notion_database.py +339 -126
  38. notionary/database/notion_database_provider.py +230 -0
  39. notionary/elements/__init__.py +0 -0
  40. notionary/models/notion_database_response.py +294 -13
  41. notionary/models/notion_page_response.py +9 -31
  42. notionary/models/search_response.py +0 -0
  43. notionary/page/__init__.py +0 -0
  44. notionary/page/client.py +110 -0
  45. notionary/page/content/page_content_retriever.py +5 -20
  46. notionary/page/content/page_content_writer.py +3 -4
  47. notionary/page/formatting/markdown_to_notion_converter.py +1 -3
  48. notionary/{prompting → page}/markdown_syntax_prompt_generator.py +1 -2
  49. notionary/page/notion_page.py +354 -317
  50. notionary/page/notion_to_markdown_converter.py +1 -4
  51. notionary/page/properites/property_value_extractor.py +0 -64
  52. notionary/page/{properites/property_formatter.py → property_formatter.py} +7 -4
  53. notionary/page/search_filter_builder.py +131 -0
  54. notionary/page/utils.py +60 -0
  55. notionary/util/__init__.py +12 -3
  56. notionary/util/factory_decorator.py +33 -0
  57. notionary/util/fuzzy_matcher.py +82 -0
  58. notionary/util/page_id_utils.py +0 -21
  59. notionary/util/singleton_metaclass.py +22 -0
  60. notionary/workspace.py +69 -0
  61. {notionary-0.2.13.dist-info → notionary-0.2.14.dist-info}/METADATA +4 -1
  62. notionary-0.2.14.dist-info/RECORD +72 -0
  63. notionary/database/database_discovery.py +0 -142
  64. notionary/database/notion_database_factory.py +0 -190
  65. notionary/exceptions/database_exceptions.py +0 -76
  66. notionary/exceptions/page_creation_exception.py +0 -9
  67. notionary/page/metadata/metadata_editor.py +0 -150
  68. notionary/page/metadata/notion_icon_manager.py +0 -77
  69. notionary/page/metadata/notion_page_cover_manager.py +0 -56
  70. notionary/page/notion_page_factory.py +0 -328
  71. notionary/page/properites/database_property_service.py +0 -302
  72. notionary/page/properites/page_property_manager.py +0 -152
  73. notionary/page/relations/notion_page_relation_manager.py +0 -350
  74. notionary/page/relations/notion_page_title_resolver.py +0 -104
  75. notionary/page/relations/page_database_relation.py +0 -68
  76. notionary/util/warn_direct_constructor_usage.py +0 -54
  77. notionary-0.2.13.dist-info/RECORD +0 -67
  78. /notionary/util/{singleton.py → singleton_decorator.py} +0 -0
  79. {notionary-0.2.13.dist-info → notionary-0.2.14.dist-info}/WHEEL +0 -0
  80. {notionary-0.2.13.dist-info → notionary-0.2.14.dist-info}/entry_points.txt +0 -0
  81. {notionary-0.2.13.dist-info → notionary-0.2.14.dist-info}/licenses/LICENSE +0 -0
  82. {notionary-0.2.13.dist-info → notionary-0.2.14.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,13 @@
1
+ class NotionDatabaseException(Exception):
2
+ """Base exception for all Notion database operations."""
3
+
4
+ pass
5
+
6
+
7
+ class DatabaseNotFoundException(NotionDatabaseException):
8
+ """Exception raised when a database is not found."""
9
+
10
+ def __init__(self, identifier: str, message: str = None):
11
+ self.identifier = identifier
12
+ self.message = message or f"Database not found: {identifier}"
13
+ super().__init__(self.message)
File without changes
@@ -0,0 +1,175 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Dict, List
4
+ from datetime import datetime, timedelta
5
+ from dataclasses import dataclass, field
6
+
7
+
8
+ @dataclass
9
+ class FilterConfig:
10
+ """Einfache Konfiguration für Notion Database Filter."""
11
+
12
+ conditions: List[Dict[str, Any]] = field(default_factory=list)
13
+ page_size: int = 100
14
+
15
+ def to_filter_dict(self) -> Dict[str, Any]:
16
+ """Konvertiert zu einem Notion-Filter-Dictionary."""
17
+ if len(self.conditions) == 0:
18
+ return {}
19
+ if len(self.conditions) == 1:
20
+ return self.conditions[0]
21
+
22
+ return {"and": self.conditions}
23
+
24
+
25
+ class FilterBuilder:
26
+ """
27
+ Builder class for creating complex Notion filters with comprehensive property type support.
28
+ """
29
+
30
+ def __init__(self, config: FilterConfig = None):
31
+ self.config = config or FilterConfig()
32
+
33
+ def with_page_object_filter(self) -> FilterBuilder:
34
+ """Filter: Nur Datenbank-Objekte (Notion API search)."""
35
+ self.config.conditions.append({"value": "page", "property": "object"})
36
+ return self
37
+
38
+ def with_database_object_filter(self) -> FilterBuilder:
39
+ """Filter: Nur Datenbank-Objekte (Notion API search)."""
40
+ self.config.conditions.append({"value": "database", "property": "object"})
41
+ return self
42
+
43
+ # TIMESTAMP FILTERS (Created/Updated)
44
+ def with_created_after(self, date: datetime) -> FilterBuilder:
45
+ """Add condition: created after specific date."""
46
+ self.config.conditions.append(
47
+ {"timestamp": "created_time", "created_time": {"after": date.isoformat()}}
48
+ )
49
+ return self
50
+
51
+ def with_created_before(self, date: datetime) -> FilterBuilder:
52
+ """Add condition: created before specific date."""
53
+ self.config.conditions.append(
54
+ {"timestamp": "created_time", "created_time": {"before": date.isoformat()}}
55
+ )
56
+ return self
57
+
58
+ def with_updated_after(self, date: datetime) -> FilterBuilder:
59
+ """Add condition: updated after specific date."""
60
+ self.config.conditions.append(
61
+ {
62
+ "timestamp": "last_edited_time",
63
+ "last_edited_time": {"after": date.isoformat()},
64
+ }
65
+ )
66
+ return self
67
+
68
+ def with_created_last_n_days(self, days: int) -> FilterBuilder:
69
+ """In den letzten N Tagen erstellt."""
70
+ cutoff = datetime.now() - timedelta(days=days)
71
+ return self.with_created_after(cutoff)
72
+
73
+ def with_updated_last_n_hours(self, hours: int) -> FilterBuilder:
74
+ """In den letzten N Stunden bearbeitet."""
75
+ cutoff = datetime.now() - timedelta(hours=hours)
76
+ return self.with_updated_after(cutoff)
77
+
78
+ # RICH TEXT FILTERS
79
+ def with_text_contains(self, property_name: str, value: str) -> FilterBuilder:
80
+ """Rich text contains value."""
81
+ self.config.conditions.append(
82
+ {"property": property_name, "rich_text": {"contains": value}}
83
+ )
84
+ return self
85
+
86
+ def with_text_equals(self, property_name: str, value: str) -> FilterBuilder:
87
+ """Rich text equals value."""
88
+ self.config.conditions.append(
89
+ {"property": property_name, "rich_text": {"equals": value}}
90
+ )
91
+ return self
92
+
93
+ # TITLE FILTERS
94
+ def with_title_contains(self, value: str) -> FilterBuilder:
95
+ """Title contains value."""
96
+ self.config.conditions.append(
97
+ {"property": "title", "title": {"contains": value}}
98
+ )
99
+ return self
100
+
101
+ def with_title_equals(self, value: str) -> FilterBuilder:
102
+ """Title equals value."""
103
+ self.config.conditions.append({"property": "title", "title": {"equals": value}})
104
+ return self
105
+
106
+ # SELECT FILTERS (Single Select)
107
+ def with_select_equals(self, property_name: str, value: str) -> FilterBuilder:
108
+ """Select equals value."""
109
+ self.config.conditions.append(
110
+ {"property": property_name, "select": {"equals": value}}
111
+ )
112
+ return self
113
+
114
+ def with_select_is_empty(self, property_name: str) -> FilterBuilder:
115
+ """Select is empty."""
116
+ self.config.conditions.append(
117
+ {"property": property_name, "select": {"is_empty": True}}
118
+ )
119
+ return self
120
+
121
+ def with_multi_select_contains(
122
+ self, property_name: str, value: str
123
+ ) -> FilterBuilder:
124
+ """Multi-select contains value."""
125
+ self.config.conditions.append(
126
+ {"property": property_name, "multi_select": {"contains": value}}
127
+ )
128
+ return self
129
+
130
+ def with_status_equals(self, property_name: str, value: str) -> FilterBuilder:
131
+ """Status equals value."""
132
+ self.config.conditions.append(
133
+ {"property": property_name, "status": {"equals": value}}
134
+ )
135
+ return self
136
+
137
+ def with_page_size(self, size: int) -> FilterBuilder:
138
+ """Set page size for pagination."""
139
+ self.config.page_size = size
140
+ return self
141
+
142
+ def with_or_condition(self, *builders: FilterBuilder) -> FilterBuilder:
143
+ """Add OR condition with multiple sub-conditions."""
144
+ or_conditions = []
145
+ for builder in builders:
146
+ filter_dict = builder.build()
147
+ if filter_dict:
148
+ or_conditions.append(filter_dict)
149
+
150
+ if len(or_conditions) > 1:
151
+ self.config.conditions.append({"or": or_conditions})
152
+ elif len(or_conditions) == 1:
153
+ self.config.conditions.append(or_conditions[0])
154
+
155
+ return self
156
+
157
+ def build(self) -> Dict[str, Any]:
158
+ """Build the final filter dictionary."""
159
+ return self.config.to_filter_dict()
160
+
161
+ def get_config(self) -> FilterConfig:
162
+ """Get the underlying FilterConfig."""
163
+ return self.config
164
+
165
+ def copy(self) -> FilterBuilder:
166
+ """Create a copy of the builder."""
167
+ new_config = FilterConfig(
168
+ conditions=self.config.conditions.copy(), page_size=self.config.page_size
169
+ )
170
+ return FilterBuilder(new_config)
171
+
172
+ def reset(self) -> FilterBuilder:
173
+ """Reset all conditions."""
174
+ self.config = FilterConfig()
175
+ return self