better-notion 1.4.0__py3-none-any.whl → 1.5.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.
- better_notion/_api/collections/databases.py +32 -0
- better_notion/_cli/commands/databases.py +147 -24
- better_notion/_cli/commands/pages.py +270 -293
- better_notion/_sdk/models/database.py +12 -7
- better_notion/plugins/official/agents.py +22 -2
- better_notion/plugins/official/agents_cli.py +29 -4
- better_notion/plugins/official/agents_sdk/managers.py +29 -1
- better_notion/utils/agents/schemas.py +91 -68
- better_notion/utils/agents/workspace.py +43 -29
- better_notion/utils/validators.py +132 -0
- {better_notion-1.4.0.dist-info → better_notion-1.5.1.dist-info}/METADATA +1 -1
- {better_notion-1.4.0.dist-info → better_notion-1.5.1.dist-info}/RECORD +15 -14
- {better_notion-1.4.0.dist-info → better_notion-1.5.1.dist-info}/WHEEL +0 -0
- {better_notion-1.4.0.dist-info → better_notion-1.5.1.dist-info}/entry_points.txt +0 -0
- {better_notion-1.4.0.dist-info → better_notion-1.5.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -5,6 +5,7 @@ required databases for the workflow management system.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
|
+
import logging
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
from typing import Any, Dict, Optional
|
|
10
11
|
|
|
@@ -22,6 +23,8 @@ from better_notion.utils.agents.schemas import (
|
|
|
22
23
|
WorkIssueSchema,
|
|
23
24
|
)
|
|
24
25
|
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
25
28
|
|
|
26
29
|
class WorkspaceInitializer:
|
|
27
30
|
"""Initialize a new workspace with workflow databases.
|
|
@@ -64,38 +67,48 @@ class WorkspaceInitializer:
|
|
|
64
67
|
Dict mapping database names to their IDs
|
|
65
68
|
|
|
66
69
|
Raises:
|
|
67
|
-
Exception: If database creation fails
|
|
70
|
+
Exception: If database creation fails with detailed error message
|
|
68
71
|
"""
|
|
72
|
+
logger.info(f"Initializing workspace '{workspace_name}' in page {parent_page_id}")
|
|
73
|
+
|
|
69
74
|
# Get parent page
|
|
70
|
-
|
|
75
|
+
try:
|
|
76
|
+
parent = await Page.get(parent_page_id, client=self._client)
|
|
77
|
+
logger.info(f"Parent page found: {parent.id}")
|
|
78
|
+
except Exception as e:
|
|
79
|
+
error_msg = f"Failed to get parent page '{parent_page_id}': {str(e)}"
|
|
80
|
+
logger.error(error_msg)
|
|
81
|
+
raise Exception(error_msg) from e
|
|
71
82
|
|
|
72
83
|
# Create databases in order (independent first, then dependent)
|
|
73
84
|
self._database_ids = {}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
85
|
+
databases_order = [
|
|
86
|
+
("Organizations", "organizations", self._create_organizations_db),
|
|
87
|
+
("Tags", "tags", self._create_tags_db),
|
|
88
|
+
("Projects", "projects", self._create_projects_db),
|
|
89
|
+
("Versions", "versions", self._create_versions_db),
|
|
90
|
+
("Tasks", "tasks", self._create_tasks_db),
|
|
91
|
+
("Ideas", "ideas", self._create_ideas_db),
|
|
92
|
+
("Work Issues", "work_issues", self._create_work_issues_db),
|
|
93
|
+
("Incidents", "incidents", self._create_incidents_db),
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
for display_name, key, create_func in databases_order:
|
|
97
|
+
try:
|
|
98
|
+
logger.info(f"Creating {display_name} database...")
|
|
99
|
+
await create_func(parent)
|
|
100
|
+
logger.info(f"✓ {display_name} database created: {self._database_ids[key]}")
|
|
101
|
+
except Exception as e:
|
|
102
|
+
error_msg = (
|
|
103
|
+
f"Failed to create {display_name} database: {str(e)}\n"
|
|
104
|
+
f"Databases created so far: {list(self._database_ids.keys())}\n"
|
|
105
|
+
f"Parent page: {parent_page_id}\n"
|
|
106
|
+
f"Workspace name: {workspace_name}"
|
|
107
|
+
)
|
|
108
|
+
logger.error(error_msg)
|
|
109
|
+
raise Exception(error_msg) from e
|
|
110
|
+
|
|
111
|
+
logger.info(f"Workspace initialization complete. Created {len(self._database_ids)} databases")
|
|
99
112
|
return self._database_ids
|
|
100
113
|
|
|
101
114
|
async def _create_organizations_db(self, parent: Page) -> None:
|
|
@@ -208,8 +221,8 @@ class WorkspaceInitializer:
|
|
|
208
221
|
# Update relations
|
|
209
222
|
if "projects" in self._database_ids:
|
|
210
223
|
schema["Project"]["relation"]["database_id"] = self._database_ids["projects"]
|
|
211
|
-
|
|
212
|
-
|
|
224
|
+
if "tasks" in self._database_ids:
|
|
225
|
+
schema["Related Task"]["relation"]["database_id"] = self._database_ids["tasks"]
|
|
213
226
|
db = await self._client.databases.create(
|
|
214
227
|
parent=parent,
|
|
215
228
|
title="Ideas",
|
|
@@ -234,6 +247,7 @@ class WorkspaceInitializer:
|
|
|
234
247
|
schema["Project"]["relation"]["database_id"] = self._database_ids["projects"]
|
|
235
248
|
if "tasks" in self._database_ids:
|
|
236
249
|
schema["Task"]["relation"]["database_id"] = self._database_ids["tasks"]
|
|
250
|
+
schema["Fix Tasks"]["relation"]["database_id"] = self._database_ids["tasks"]
|
|
237
251
|
if "ideas" in self._database_ids:
|
|
238
252
|
schema["Related Idea"]["relation"]["database_id"] = self._database_ids["ideas"]
|
|
239
253
|
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Validation helpers for CLI commands.
|
|
2
|
+
|
|
3
|
+
This module provides reusable validation functions for CLI parameters.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ValidationError(Exception):
|
|
8
|
+
"""Custom exception for validation errors."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, message: str):
|
|
11
|
+
self.message = message
|
|
12
|
+
super().__init__(self.message)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Validators:
|
|
16
|
+
"""Reusable validation functions for CLI parameters."""
|
|
17
|
+
|
|
18
|
+
@staticmethod
|
|
19
|
+
def positive_int(value: int, name: str = "value") -> None:
|
|
20
|
+
"""
|
|
21
|
+
Validate that a value is a positive integer.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
value: The value to validate
|
|
25
|
+
name: Parameter name for error messages
|
|
26
|
+
|
|
27
|
+
Raises:
|
|
28
|
+
ValidationError: If value is not positive
|
|
29
|
+
"""
|
|
30
|
+
if not isinstance(value, int):
|
|
31
|
+
raise ValidationError(f"{name} must be an integer (got: {type(value).__name__})")
|
|
32
|
+
if value <= 0:
|
|
33
|
+
raise ValidationError(f"{name} must be positive (greater than 0, got: {value})")
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def non_negative_int(value: int, name: str = "value") -> None:
|
|
37
|
+
"""
|
|
38
|
+
Validate that a value is a non-negative integer.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
value: The value to validate
|
|
42
|
+
name: Parameter name for error messages
|
|
43
|
+
|
|
44
|
+
Raises:
|
|
45
|
+
ValidationError: If value is negative
|
|
46
|
+
"""
|
|
47
|
+
if not isinstance(value, int):
|
|
48
|
+
raise ValidationError(f"{name} must be an integer (got: {type(value).__name__})")
|
|
49
|
+
if value < 0:
|
|
50
|
+
raise ValidationError(f"{name} must be non-negative (0 or greater, got: {value})")
|
|
51
|
+
|
|
52
|
+
@staticmethod
|
|
53
|
+
def non_negative_float(value: float, name: str = "value") -> None:
|
|
54
|
+
"""
|
|
55
|
+
Validate that a value is a non-negative float.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
value: The value to validate
|
|
59
|
+
name: Parameter name for error messages
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
ValidationError: If value is negative
|
|
63
|
+
"""
|
|
64
|
+
if not isinstance(value, (int, float)):
|
|
65
|
+
raise ValidationError(f"{name} must be a number (got: {type(value).__name__})")
|
|
66
|
+
if value < 0:
|
|
67
|
+
raise ValidationError(f"{name} must be non-negative (0 or greater, got: {value})")
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
def enum(value: str, name: str, allowed: list, case_sensitive: bool = False) -> None:
|
|
71
|
+
"""
|
|
72
|
+
Validate that a value is in the allowed list.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
value: The value to validate
|
|
76
|
+
name: Parameter name for error messages
|
|
77
|
+
allowed: List of allowed values
|
|
78
|
+
case_sensitive: Whether comparison should be case-sensitive
|
|
79
|
+
|
|
80
|
+
Raises:
|
|
81
|
+
ValidationError: If value is not in allowed list
|
|
82
|
+
"""
|
|
83
|
+
if not case_sensitive:
|
|
84
|
+
value_lower = value.lower()
|
|
85
|
+
allowed_lower = [a.lower() for a in allowed]
|
|
86
|
+
if value_lower not in allowed_lower:
|
|
87
|
+
raise ValidationError(
|
|
88
|
+
f"{name} must be one of {allowed} (got: {value})"
|
|
89
|
+
)
|
|
90
|
+
else:
|
|
91
|
+
if value not in allowed:
|
|
92
|
+
raise ValidationError(
|
|
93
|
+
f"{name} must be one of {allowed} (got: {value})"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def range_int(value: int, name: str, min_val: int, max_val: int) -> None:
|
|
98
|
+
"""
|
|
99
|
+
Validate that a value is within a specified range.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
value: The value to validate
|
|
103
|
+
name: Parameter name for error messages
|
|
104
|
+
min_val: Minimum allowed value (inclusive)
|
|
105
|
+
max_val: Maximum allowed value (inclusive)
|
|
106
|
+
|
|
107
|
+
Raises:
|
|
108
|
+
ValidationError: If value is outside the range
|
|
109
|
+
"""
|
|
110
|
+
if not isinstance(value, int):
|
|
111
|
+
raise ValidationError(f"{name} must be an integer (got: {type(value).__name__})")
|
|
112
|
+
if value < min_val or value > max_val:
|
|
113
|
+
raise ValidationError(
|
|
114
|
+
f"{name} must be between {min_val} and {max_val} (got: {value})"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
def required(value: Any, name: str) -> None:
|
|
119
|
+
"""
|
|
120
|
+
Validate that a value is not None or empty.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
value: The value to validate
|
|
124
|
+
name: Parameter name for error messages
|
|
125
|
+
|
|
126
|
+
Raises:
|
|
127
|
+
ValidationError: If value is None or empty
|
|
128
|
+
"""
|
|
129
|
+
if value is None:
|
|
130
|
+
raise ValidationError(f"{name} is required")
|
|
131
|
+
if isinstance(value, str) and not value.strip():
|
|
132
|
+
raise ValidationError(f"{name} cannot be empty")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: better-notion
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.1
|
|
4
4
|
Summary: A high-level Python SDK for the Notion API with developer experience in mind.
|
|
5
5
|
Project-URL: Homepage, https://github.com/nesalia-inc/better-notion
|
|
6
6
|
Project-URL: Documentation, https://github.com/nesalia-inc/better-notion#readme
|
|
@@ -6,7 +6,7 @@ better_notion/_api/oauth.py,sha256=pDQFtwJzb90zroFSLQleNEwMwVsNwlsO7MIieaegPz4,4
|
|
|
6
6
|
better_notion/_api/collections/__init__.py,sha256=snBRDpUOWxKR-w6FjNtfRddclO1LF2LNy65T7dbv57A,539
|
|
7
7
|
better_notion/_api/collections/blocks.py,sha256=Ka8HbVk9NCDh1zMJeKvP1XCjxJI_1yuGzYyzSxFgYGY,3703
|
|
8
8
|
better_notion/_api/collections/comments.py,sha256=Qkl2pOxqiti1ALJpBi1TE1arQoSc8Y6cuOkqpsXrzpE,3222
|
|
9
|
-
better_notion/_api/collections/databases.py,sha256=
|
|
9
|
+
better_notion/_api/collections/databases.py,sha256=eUpNSwSWn8J5AkCq1uZEBPb7rNmrrzvNMqFTsfFCcDc,3084
|
|
10
10
|
better_notion/_api/collections/pages.py,sha256=qX_QwNJsq8jPvWp91A44zfais69gIXNSRjeH7NL8ha0,3174
|
|
11
11
|
better_notion/_api/collections/users.py,sha256=h-J5fQbXQSj7ZgMfHRDoXLKUv1lP3On6uWO-3YO4dlc,1309
|
|
12
12
|
better_notion/_api/entities/__init__.py,sha256=QYSgFMr5kC94M6nzpkr_KSjUZcCpdZBObBod7XOrhU4,521
|
|
@@ -41,8 +41,8 @@ better_notion/_cli/commands/auth.py,sha256=d1-g8SKCrC8Di4yM36hafVlF9YZQ9pypRYU9I
|
|
|
41
41
|
better_notion/_cli/commands/blocks.py,sha256=ErcR-SHhPoz6B9uy0xOG6CGZB-bhvny5lxBYufmYHbw,15711
|
|
42
42
|
better_notion/_cli/commands/comments.py,sha256=dBdxvpkjk_yA_1WUivXl1Nt8Ig-uYD5-k4XtenHU_cI,4981
|
|
43
43
|
better_notion/_cli/commands/config.py,sha256=3bOCmcRnpTb5SHB2TJPXdxrRshy84nZRAsULxfbSqk0,5360
|
|
44
|
-
better_notion/_cli/commands/databases.py,sha256=
|
|
45
|
-
better_notion/_cli/commands/pages.py,sha256=
|
|
44
|
+
better_notion/_cli/commands/databases.py,sha256=SRfUi74Cm7YVvdwPjbcwP1g__DiZsMyY0YLQTY-skx4,12953
|
|
45
|
+
better_notion/_cli/commands/pages.py,sha256=NZwrWDOim43FzIdtqubbXarsflnjQo2T4BGB1TJsco0,13068
|
|
46
46
|
better_notion/_cli/commands/plugins.py,sha256=mBYSVciwwgnCRXYOuJfSYDV2UMAr_9P8KwPuiC-pY2A,27067
|
|
47
47
|
better_notion/_cli/commands/search.py,sha256=JM20W5TiohsOKLyEUABEaWr0yB82W2_qAGQ1w64_pGk,4671
|
|
48
48
|
better_notion/_cli/commands/update.py,sha256=NfmijzTpCbVTEY2h0QdcJZXEiGmWkk-iyEtZCqrgmAk,4997
|
|
@@ -65,7 +65,7 @@ better_notion/_sdk/managers/user_manager.py,sha256=AfFWhxKbaWhMCqJmRoU55JwfZNJHh
|
|
|
65
65
|
better_notion/_sdk/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
66
66
|
better_notion/_sdk/models/block.py,sha256=4Wpx46zVUy0LrwE2eEvUof37iyflmY-nL-NttC7o8tI,15163
|
|
67
67
|
better_notion/_sdk/models/comment.py,sha256=R82jfAhQODNCdvVywv8dIrmA9lfKgkI8ZSKThQFvG98,8485
|
|
68
|
-
better_notion/_sdk/models/database.py,sha256=
|
|
68
|
+
better_notion/_sdk/models/database.py,sha256=NaplivKjbbxnpYtB19f80yY6075tHZWuvimCPA9j0h4,16746
|
|
69
69
|
better_notion/_sdk/models/page.py,sha256=KVGTdt-xuhEYlb1snmZ0VdjMZAQDSWcUwZ18oK5me4g,20541
|
|
70
70
|
better_notion/_sdk/models/user.py,sha256=1yo4F7horPDf7m9Z1Xl1VGxcmgG7vCn_pEFj_oiPyVo,10261
|
|
71
71
|
better_notion/_sdk/models/blocks/__init__.py,sha256=8kykYs4cvuBlgn6R1tq7b5RMJu7ng7IcWA-0y7kww6A,1928
|
|
@@ -107,26 +107,27 @@ better_notion/plugins/base.py,sha256=3h9jOZzS--UqmVW3RREtcQ2h1GTWWPUryTencsJKhTM
|
|
|
107
107
|
better_notion/plugins/loader.py,sha256=zCWsMdJyvZs1IHFm0zjEiqm_l_5jB1Uw4x30Kq8rLS4,9527
|
|
108
108
|
better_notion/plugins/state.py,sha256=jH_tZWvC35hqLO4qwl2Kwq9ziWVavwCEUcCqy3s5wMY,3780
|
|
109
109
|
better_notion/plugins/official/__init__.py,sha256=rPg5vdk1cEANVstMPzxcWmImtsOpdSR40JSml7h1uUk,426
|
|
110
|
-
better_notion/plugins/official/agents.py,sha256=
|
|
111
|
-
better_notion/plugins/official/agents_cli.py,sha256=
|
|
110
|
+
better_notion/plugins/official/agents.py,sha256=HDCAQOq7za00_YZXLftU5cBaeK3VSgutFWkXwwvtRxs,26636
|
|
111
|
+
better_notion/plugins/official/agents_cli.py,sha256=8l6e1zJCAT4DdAO-QfdjK_vrrrik3pmrojwakE32ZNY,53048
|
|
112
112
|
better_notion/plugins/official/productivity.py,sha256=_-whP4pYA4HufE1aUFbIdhrjU-O9njI7xUO_Id2M1J8,8726
|
|
113
113
|
better_notion/plugins/official/agents_sdk/__init__.py,sha256=luQBzZLsJ7fC5U0jFu8dfzMviiXj2SBZXcTohM53wkQ,725
|
|
114
|
-
better_notion/plugins/official/agents_sdk/managers.py,sha256=
|
|
114
|
+
better_notion/plugins/official/agents_sdk/managers.py,sha256=0zMZPu63zhdyqiudO2gKsmM3YOJh0nFAR9FrMlwkV2A,31186
|
|
115
115
|
better_notion/plugins/official/agents_sdk/models.py,sha256=gwGw9t-Z17NxddzmRKWiD9Noje86sxgPNlLJGARI0KA,75448
|
|
116
116
|
better_notion/plugins/official/agents_sdk/plugin.py,sha256=bs9O8Unv6SARGj4lBU5Gj9HGbLTUNqTacJ3RLUhdbI4,4479
|
|
117
117
|
better_notion/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
118
118
|
better_notion/utils/helpers.py,sha256=HgFuUQlG_HzBOB0z2GA9RxPLoXgwRc0DIxa9Fg6C-Jk,2337
|
|
119
119
|
better_notion/utils/retry.py,sha256=9WJDNitiIfVTL18hIlipvOKn41ukePrOwtAwx-LevpQ,7479
|
|
120
|
+
better_notion/utils/validators.py,sha256=RyAGcYJexKOq1YepF6insoBu4QEOVPoAMWqi8Mt_5Xk,4583
|
|
120
121
|
better_notion/utils/agents/__init__.py,sha256=Zu32q0abbimrJY5dczjWNEastE-IrtGPQjpxD4JS4IU,1715
|
|
121
122
|
better_notion/utils/agents/auth.py,sha256=_SBcqBjXmX8CJMCPpRWM-UuaDg7-OOtMWbhnYEiIBTs,6568
|
|
122
123
|
better_notion/utils/agents/dependency_resolver.py,sha256=PfHHDIQztGih4LwylMb0_MyhDFbOYPjvUxcxY52mSEs,12033
|
|
123
124
|
better_notion/utils/agents/project_context.py,sha256=aJlzy5H2rL4sAfW2jHL_3K2VkBJ4ihUhCRVolkpuO78,7477
|
|
124
125
|
better_notion/utils/agents/rbac.py,sha256=8ZA8Y7wbOiVZDbpjpH7iC35SZrZ0jl4fcJ3xWCm3SsE,11820
|
|
125
|
-
better_notion/utils/agents/schemas.py,sha256=
|
|
126
|
+
better_notion/utils/agents/schemas.py,sha256=eHfGhY90FAPXA3E8qE6gP75dgNzn-9z5Ju1FMwBKnQQ,22120
|
|
126
127
|
better_notion/utils/agents/state_machine.py,sha256=xUBEeDTbU1Xq-rsRo2sbr6AUYpYrV9DTHOtZT2cWES8,6699
|
|
127
|
-
better_notion/utils/agents/workspace.py,sha256=
|
|
128
|
-
better_notion-1.
|
|
129
|
-
better_notion-1.
|
|
130
|
-
better_notion-1.
|
|
131
|
-
better_notion-1.
|
|
132
|
-
better_notion-1.
|
|
128
|
+
better_notion/utils/agents/workspace.py,sha256=FYarHj8eD2OeUG0KMPelqpBavm4RnYBoW2PVuwYkKI4,13614
|
|
129
|
+
better_notion-1.5.1.dist-info/METADATA,sha256=lLDjood4wOkoyNlgmc7IUY9doLnTz6u_6tluC4rgQG4,11096
|
|
130
|
+
better_notion-1.5.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
131
|
+
better_notion-1.5.1.dist-info/entry_points.txt,sha256=D0bUcP7Z00Zyjxw7r2p29T95UrwioDO0aGDoHe9I6fo,55
|
|
132
|
+
better_notion-1.5.1.dist-info/licenses/LICENSE,sha256=BAdN3JpgMY_y_fWqZSCFSvSbC2mTHP-BKDAzF5FXQAI,1069
|
|
133
|
+
better_notion-1.5.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|