Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/api/exceptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,31 @@ Exception classes used throughout the Bloomy SDK.
show_root_heading: true
show_root_full_path: false

## Authentication Errors

::: bloomy.exceptions.AuthenticationError
options:
show_source: true
show_root_heading: true
show_root_full_path: false

Raised when username/password authentication fails. This typically occurs when using `Configuration.configure_api_key()` with invalid credentials.

**Example:**

```python
from bloomy import Configuration, AuthenticationError

try:
config = Configuration()
config.configure_api_key(
username="user@example.com",
password="wrong_password"
)
except AuthenticationError as e:
print(f"Authentication failed: {e}")
```

## API Errors

::: bloomy.exceptions.APIError
Expand Down
17 changes: 16 additions & 1 deletion docs/api/operations/goals.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The async version `AsyncGoalOperations` provides the same methods as above, but
show_inheritance_diagram: false

!!! info "Async Usage"
All methods have the same parameters and return types as their sync counterparts. Simply add `await` before each method call.
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.

## Goal Status Enum

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

# Delete a goal (returns None)
client.goal.delete(goal_id=new_goal.id)

# Bulk create multiple goals
goals_data = [
{"title": "Increase revenue by 20%", "meeting_id": 123},
{"title": "Launch new product", "meeting_id": 123, "user_id": 456},
]
result = client.goal.create_many(goals_data)

print(f"Created {len(result.successful)} goals")
for error in result.failed:
print(f"Failed at index {error.index}: {error.error}")
```

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

# Bulk create with concurrency control
result = await client.goal.create_many(goals_data, max_concurrent=10)

asyncio.run(main())
```

Expand All @@ -137,6 +151,7 @@ client.goal.update(goal_id=123, status="on")
|--------|-------------|------------|
| `list()` | Get goals for a user | `user_id`, `archived` |
| `create()` | Create a new goal | `title`, `meeting_id`, `user_id` |
| `create_many()` | Create multiple goals in bulk | `goals` (sync); `goals`, `max_concurrent` (async) |
| `update()` | Update an existing goal | `goal_id`, `title`, `accountable_user`, `status` |
| `delete()` | Delete a goal | `goal_id` |
| `archive()` | Archive a goal | `goal_id` |
Expand Down
17 changes: 10 additions & 7 deletions docs/api/operations/headlines.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,16 +104,19 @@ The async version `AsyncHeadlineOperations` provides the same methods as above,

## Available Methods

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

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

!!! tip "Default Behavior"
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.

!!! note "Return Values"
The `update()` and `delete()` methods return `None` instead of boolean values.
114 changes: 111 additions & 3 deletions docs/api/operations/issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,9 @@ The async version `AsyncIssueOperations` provides the same methods as above, but
| Method | Description | Parameters | Returns |
|--------|-------------|------------|---------|
| `details()` | Get detailed issue information | `issue_id` | `IssueDetails` |
| `list()` | Get issues | `user_id`, `meeting_id` | `list[IssueDetails]` |
| `create()` | Create a new issue | `meeting_id`, `title`, `user_id`, `notes` | `IssueDetails` |
| `list()` | Get issues | `user_id`, `meeting_id` | `list[IssueListItem]` |
| `create()` | Create a new issue | `meeting_id`, `title`, `user_id`, `notes` | `CreatedIssue` |
| `create_many()` | Create multiple issues | `issues` | `BulkCreateResult[CreatedIssue]` |
| `update()` | Update an existing issue | `issue_id`, `title`, `notes` | `IssueDetails` |
| `complete()` | Mark an issue as solved | `issue_id` | `IssueDetails` |

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

!!! note "Update Requirements"
At least one of `title` or `notes` must be provided when calling `update()`. If neither is provided, a `ValueError` will be raised.
At least one of `title` or `notes` must be provided when calling `update()`. If neither is provided, a `ValueError` will be raised.

## Bulk Operations

### Creating Multiple Issues

=== "Sync"

```python
from bloomy import Client

with Client(api_key="your-api-key") as client:
# Create multiple issues at once
issues = [
{
"meeting_id": 123,
"title": "Server performance degradation",
"notes": "Response times increased by 50%"
},
{
"meeting_id": 123,
"title": "Database connection pool exhausted",
"user_id": 456,
"notes": "Max connections reached during peak hours"
},
{
"meeting_id": 789,
"title": "Authentication service timeout"
}
]

result = client.issue.create_many(issues)

# Check results
print(f"Successfully created {len(result.successful)} issues")
for issue in result.successful:
print(f"- Issue #{issue.id}: {issue.title}")

# Handle failures
if result.failed:
print(f"Failed to create {len(result.failed)} issues")
for error in result.failed:
print(f"- Index {error.index}: {error.error}")
print(f" Input: {error.input_data}")
```

=== "Async"

```python
import asyncio
from bloomy import AsyncClient

async def main():
async with AsyncClient(api_key="your-api-key") as client:
# Create multiple issues concurrently
issues = [
{
"meeting_id": 123,
"title": "Server performance degradation",
"notes": "Response times increased by 50%"
},
{
"meeting_id": 123,
"title": "Database connection pool exhausted",
"user_id": 456,
"notes": "Max connections reached during peak hours"
},
{
"meeting_id": 789,
"title": "Authentication service timeout"
}
]

# Control concurrency with max_concurrent parameter
result = await client.issue.create_many(issues, max_concurrent=5)

# Check results
print(f"Successfully created {len(result.successful)} issues")
for issue in result.successful:
print(f"- Issue #{issue.id}: {issue.title}")

# Handle failures
if result.failed:
print(f"Failed to create {len(result.failed)} issues")
for error in result.failed:
print(f"- Index {error.index}: {error.error}")
print(f" Input: {error.input_data}")

asyncio.run(main())
```

!!! info "Async Rate Limiting"
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.

```python
# Process more items concurrently for better performance
result = await client.issue.create_many(issues, max_concurrent=10)

# Process items more slowly to avoid rate limits
result = await client.issue.create_many(issues, max_concurrent=2)
```

!!! tip "Bulk Operation Best Practices"
- **Best-effort approach**: `create_many()` continues processing even if some issues fail to create
- **Check both lists**: Always inspect both `result.successful` and `result.failed` to handle partial failures
- **Required fields**: Each issue dict must include `meeting_id` and `title`
- **Optional fields**: `user_id` defaults to the authenticated user if not provided
- **Error handling**: Failed creations include the original input data and error message for debugging
Loading