Skip to content

Commit dd98f36

Browse files
authored
Merge pull request #13 from franccesco/fix/documentation-validation
fix(docs): validate documentation against implementation
2 parents 47b58fa + d5f04da commit dd98f36

15 files changed

Lines changed: 430 additions & 97 deletions

File tree

docs/api/exceptions.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,31 @@ Exception classes used throughout the Bloomy SDK.
1010
show_root_heading: true
1111
show_root_full_path: false
1212

13+
## Authentication Errors
14+
15+
::: bloomy.exceptions.AuthenticationError
16+
options:
17+
show_source: true
18+
show_root_heading: true
19+
show_root_full_path: false
20+
21+
Raised when username/password authentication fails. This typically occurs when using `Configuration.configure_api_key()` with invalid credentials.
22+
23+
**Example:**
24+
25+
```python
26+
from bloomy import Configuration, AuthenticationError
27+
28+
try:
29+
config = Configuration()
30+
config.configure_api_key(
31+
username="user@example.com",
32+
password="wrong_password"
33+
)
34+
except AuthenticationError as e:
35+
print(f"Authentication failed: {e}")
36+
```
37+
1338
## API Errors
1439

1540
::: bloomy.exceptions.APIError

docs/api/operations/goals.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ The async version `AsyncGoalOperations` provides the same methods as above, but
2626
show_inheritance_diagram: false
2727

2828
!!! info "Async Usage"
29-
All methods have the same parameters and return types as their sync counterparts. Simply add `await` before each method call.
29+
All methods have the same parameters and return types as their sync counterparts. Simply add `await` before each method call. The `create_many()` method has an additional `max_concurrent` parameter in the async version for controlling concurrency.
3030

3131
## Goal Status Enum
3232

@@ -86,6 +86,17 @@ client.goal.update(goal_id=123, status="on")
8686

8787
# Delete a goal (returns None)
8888
client.goal.delete(goal_id=new_goal.id)
89+
90+
# Bulk create multiple goals
91+
goals_data = [
92+
{"title": "Increase revenue by 20%", "meeting_id": 123},
93+
{"title": "Launch new product", "meeting_id": 123, "user_id": 456},
94+
]
95+
result = client.goal.create_many(goals_data)
96+
97+
print(f"Created {len(result.successful)} goals")
98+
for error in result.failed:
99+
print(f"Failed at index {error.index}: {error.error}")
89100
```
90101

91102
=== "Async"
@@ -128,6 +139,9 @@ client.goal.update(goal_id=123, status="on")
128139
# Delete a goal (returns None)
129140
await client.goal.delete(goal_id=new_goal.id)
130141

142+
# Bulk create with concurrency control
143+
result = await client.goal.create_many(goals_data, max_concurrent=10)
144+
131145
asyncio.run(main())
132146
```
133147

@@ -137,6 +151,7 @@ client.goal.update(goal_id=123, status="on")
137151
|--------|-------------|------------|
138152
| `list()` | Get goals for a user | `user_id`, `archived` |
139153
| `create()` | Create a new goal | `title`, `meeting_id`, `user_id` |
154+
| `create_many()` | Create multiple goals in bulk | `goals` (sync); `goals`, `max_concurrent` (async) |
140155
| `update()` | Update an existing goal | `goal_id`, `title`, `accountable_user`, `status` |
141156
| `delete()` | Delete a goal | `goal_id` |
142157
| `archive()` | Archive a goal | `goal_id` |

docs/api/operations/headlines.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,16 +104,19 @@ The async version `AsyncHeadlineOperations` provides the same methods as above,
104104

105105
## Available Methods
106106

107-
| Method | Description | Parameters |
108-
|--------|-------------|------------|
109-
| `create()` | Create a new headline | `meeting_id`, `title`, `owner_id`, `notes` |
110-
| `update()` | Update a headline title | `headline_id`, `title` |
111-
| `details()` | Get detailed headline information | `headline_id` |
112-
| `list()` | Get headlines | `user_id`, `meeting_id` |
113-
| `delete()` | Delete a headline | `headline_id` |
107+
| Method | Description | Required Parameters | Optional Parameters |
108+
|--------|-------------|---------------------|---------------------|
109+
| `create()` | Create a new headline | `meeting_id` (int), `title` (str) | `owner_id` (int, defaults to current user), `notes` (str) |
110+
| `update()` | Update a headline title | `headline_id` (int), `title` (str) | None |
111+
| `details()` | Get detailed headline information | `headline_id` (int) | None |
112+
| `list()` | Get headlines (defaults to current user) | None | `user_id` (int), `meeting_id` (int) |
113+
| `delete()` | Delete a headline | `headline_id` (int) | None |
114114

115115
!!! note "Filtering"
116116
Like todos, headlines can be filtered by either `user_id` or `meeting_id`, but not both.
117117

118+
!!! tip "Default Behavior"
119+
When calling `list()` without parameters, it returns headlines for the current authenticated user. The `create()` method also defaults `owner_id` to the current user if not specified.
120+
118121
!!! note "Return Values"
119122
The `update()` and `delete()` methods return `None` instead of boolean values.

docs/api/operations/issues.md

Lines changed: 111 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,9 @@ The async version `AsyncIssueOperations` provides the same methods as above, but
113113
| Method | Description | Parameters | Returns |
114114
|--------|-------------|------------|---------|
115115
| `details()` | Get detailed issue information | `issue_id` | `IssueDetails` |
116-
| `list()` | Get issues | `user_id`, `meeting_id` | `list[IssueDetails]` |
117-
| `create()` | Create a new issue | `meeting_id`, `title`, `user_id`, `notes` | `IssueDetails` |
116+
| `list()` | Get issues | `user_id`, `meeting_id` | `list[IssueListItem]` |
117+
| `create()` | Create a new issue | `meeting_id`, `title`, `user_id`, `notes` | `CreatedIssue` |
118+
| `create_many()` | Create multiple issues | `issues` | `BulkCreateResult[CreatedIssue]` |
118119
| `update()` | Update an existing issue | `issue_id`, `title`, `notes` | `IssueDetails` |
119120
| `complete()` | Mark an issue as solved | `issue_id` | `IssueDetails` |
120121

@@ -170,4 +171,111 @@ The async version `AsyncIssueOperations` provides the same methods as above, but
170171
```
171172

172173
!!! note "Update Requirements"
173-
At least one of `title` or `notes` must be provided when calling `update()`. If neither is provided, a `ValueError` will be raised.
174+
At least one of `title` or `notes` must be provided when calling `update()`. If neither is provided, a `ValueError` will be raised.
175+
176+
## Bulk Operations
177+
178+
### Creating Multiple Issues
179+
180+
=== "Sync"
181+
182+
```python
183+
from bloomy import Client
184+
185+
with Client(api_key="your-api-key") as client:
186+
# Create multiple issues at once
187+
issues = [
188+
{
189+
"meeting_id": 123,
190+
"title": "Server performance degradation",
191+
"notes": "Response times increased by 50%"
192+
},
193+
{
194+
"meeting_id": 123,
195+
"title": "Database connection pool exhausted",
196+
"user_id": 456,
197+
"notes": "Max connections reached during peak hours"
198+
},
199+
{
200+
"meeting_id": 789,
201+
"title": "Authentication service timeout"
202+
}
203+
]
204+
205+
result = client.issue.create_many(issues)
206+
207+
# Check results
208+
print(f"Successfully created {len(result.successful)} issues")
209+
for issue in result.successful:
210+
print(f"- Issue #{issue.id}: {issue.title}")
211+
212+
# Handle failures
213+
if result.failed:
214+
print(f"Failed to create {len(result.failed)} issues")
215+
for error in result.failed:
216+
print(f"- Index {error.index}: {error.error}")
217+
print(f" Input: {error.input_data}")
218+
```
219+
220+
=== "Async"
221+
222+
```python
223+
import asyncio
224+
from bloomy import AsyncClient
225+
226+
async def main():
227+
async with AsyncClient(api_key="your-api-key") as client:
228+
# Create multiple issues concurrently
229+
issues = [
230+
{
231+
"meeting_id": 123,
232+
"title": "Server performance degradation",
233+
"notes": "Response times increased by 50%"
234+
},
235+
{
236+
"meeting_id": 123,
237+
"title": "Database connection pool exhausted",
238+
"user_id": 456,
239+
"notes": "Max connections reached during peak hours"
240+
},
241+
{
242+
"meeting_id": 789,
243+
"title": "Authentication service timeout"
244+
}
245+
]
246+
247+
# Control concurrency with max_concurrent parameter
248+
result = await client.issue.create_many(issues, max_concurrent=5)
249+
250+
# Check results
251+
print(f"Successfully created {len(result.successful)} issues")
252+
for issue in result.successful:
253+
print(f"- Issue #{issue.id}: {issue.title}")
254+
255+
# Handle failures
256+
if result.failed:
257+
print(f"Failed to create {len(result.failed)} issues")
258+
for error in result.failed:
259+
print(f"- Index {error.index}: {error.error}")
260+
print(f" Input: {error.input_data}")
261+
262+
asyncio.run(main())
263+
```
264+
265+
!!! info "Async Rate Limiting"
266+
The async version of `create_many()` supports a `max_concurrent` parameter (default: 5) to control the maximum number of concurrent requests. This helps prevent rate limiting issues when creating large batches of issues.
267+
268+
```python
269+
# Process more items concurrently for better performance
270+
result = await client.issue.create_many(issues, max_concurrent=10)
271+
272+
# Process items more slowly to avoid rate limits
273+
result = await client.issue.create_many(issues, max_concurrent=2)
274+
```
275+
276+
!!! tip "Bulk Operation Best Practices"
277+
- **Best-effort approach**: `create_many()` continues processing even if some issues fail to create
278+
- **Check both lists**: Always inspect both `result.successful` and `result.failed` to handle partial failures
279+
- **Required fields**: Each issue dict must include `meeting_id` and `title`
280+
- **Optional fields**: `user_id` defaults to the authenticated user if not provided
281+
- **Error handling**: Failed creations include the original input data and error message for debugging

0 commit comments

Comments
 (0)