Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
31bb30d
Refactor: Streamline client API (e.g., client.create_template), clean…
jithu-keyvalue Jun 5, 2025
ab7925a
feat: Add update_template method and related assets
jithu-keyvalue Jun 5, 2025
d45857b
feat: Implement delete_template method
jithu-keyvalue Jun 5, 2025
1033ddc
feat: Add publish_template method and update docs
jithu-keyvalue Jun 5, 2025
af958e7
feat: Implement create_channel_configurations API method
jithu-keyvalue Jun 5, 2025
46d83b9
feat: Implement get_channel_templates method
jithu-keyvalue Jun 5, 2025
06a7646
feat: Add trigger_workflow API method
jithu-keyvalue Jun 5, 2025
4f5767b
feat: Improve test coverage and update README
jithu-keyvalue Jun 5, 2025
23475b2
chore: Configure license and PyPI release details
jithu-keyvalue Jun 5, 2025
3011e32
refactor: refer to channel templates correctly
jithu-keyvalue Jun 9, 2025
d3f897a
feat: Add send_message API method
jithu-keyvalue Jun 9, 2025
be7d9b6
feat: add get_replies API
jithu-keyvalue Jun 9, 2025
b81b1d2
feat: Add get_message_status endpoint
jithu-keyvalue Jun 9, 2025
e5a182d
feat: add webhook config API
jithu-keyvalue Jun 9, 2025
473e5ea
feat: add schedule workflow api
jithu-keyvalue Jun 9, 2025
480546e
feat: add user API
jithu-keyvalue Jun 9, 2025
35be94a
refactor add_user method by introducing models, custom exceptions
jithu-keyvalue Jun 10, 2025
40eb35b
add update user method
jithu-keyvalue Jun 10, 2025
6ffdec2
feat: add delete_user() method
jithu-keyvalue Jun 10, 2025
dae4cee
refactor
jithu-keyvalue Jun 11, 2025
7e3f08a
refactor: introduce base manager class
jithu-keyvalue Jun 11, 2025
24db752
refactor: message methods
jithu-keyvalue Jun 11, 2025
8c5b9e1
tests: for messaging methods
jithu-keyvalue Jun 11, 2025
4ace86d
refactor webhook methods
jithu-keyvalue Jun 11, 2025
f816fa7
refactor: migrate templates to use basemanager
jithu-keyvalue Jun 11, 2025
5f48746
refactor: migrate workflow apis to use base manager
jithu-keyvalue Jun 11, 2025
bd0f0c8
doc: update Readme
jithu-keyvalue Jun 11, 2025
8375645
chore: handle env selection
jithu-keyvalue Jun 12, 2025
8b93b42
update doc
jithu-keyvalue Jun 12, 2025
68402b7
Merge pull request #1 from KeyValueSoftwareSystems/chore/handle-env
jithu-keyvalue Jun 12, 2025
25b002f
chore: group methods using namespaces
jithu-keyvalue Jun 12, 2025
460c2cf
refactor: split channel template methods into different namespace
jithu-keyvalue Jun 12, 2025
6c4472a
Merge pull request #2 from KeyValueSoftwareSystems/chore/namespace-me…
jithu-keyvalue Jun 12, 2025
0224432
init transport classes, async client, asyncwebhookclient
jithu-keyvalue Jun 12, 2025
aa59eee
feat: support async
jithu-keyvalue Jun 12, 2025
9edf5aa
Merge pull request #3 from KeyValueSoftwareSystems/feat/add-async-sup…
jithu-keyvalue Jun 12, 2025
d0b3d9a
doc: update Readme
jithu-keyvalue Jun 12, 2025
5bda33d
refactor: read env, api_key from environment
jithu-keyvalue Jun 13, 2025
a78d740
refactor: update to Pydantic V2 field_validator
jithu-keyvalue Jun 13, 2025
321e8fe
Update Readme
jithu-keyvalue Jun 16, 2025
609c66b
feat: add support for sending messages using awesome templates
ranjith-keyvalue Jun 25, 2025
5ede557
Release 0.1.0 (#5)
jithu-keyvalue Jun 25, 2025
68ee9ff
chore: support manual package publish also (#6)
jithu-keyvalue Jun 25, 2025
4075f79
chore: update repo home page
jithu-keyvalue Jun 25, 2025
2c1908e
Merge branch 'develop' of https://github.com/KeyValueSoftwareSystems/…
jithu-keyvalue Jun 25, 2025
69e85b7
doc: update Readme
jithu-keyvalue Jun 25, 2025
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
69 changes: 69 additions & 0 deletions .cursor/rules/general.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
description:
globs:
alwaysApply: false
---
Development Approach:
- Make small, focused changes incrementally
- Break complex problems into manageable pieces
- Give concise responses, avoid verbosity
- Don't change code unless explicitly asked
- Follow existing patterns and conventions

Code Quality:
- Write clean, self-documenting code
- Single responsibility per function/class
- Make code easily unit testable
- Consider future developers
- Use consistent type hints

Organization:
- Use logical file structure matching domain
- Keep files focused on single concerns
- Follow consistent naming conventions
- Prefer composition over inheritance

Method Structure:
- Each method should do one thing well
- Include proper docstrings with purpose, parameters, returns, exceptions
- Use type hints consistently
- Handle errors explicitly and predictably
- Keep methods small and focused

Error Handling:
- Be explicit, avoid implicit behavior
- Use custom exception classes with clear hierarchy
- Include enough context for debugging
- Fail fast, detect and report errors early
- Handle errors appropriately for the use case

Testing:
- Test success cases to verify happy path
- Test error cases for proper error handling
- Test edge cases and boundary conditions
- Use realistic data resembling production scenarios
- Keep tests focused on one concept per method

Documentation:
- Write concise, clear docstrings for public APIs
- Comment complex logic to explain why, not what
- Keep comments current, remove outdated ones
- Focus on intent and reasoning behind decisions
- Be minimal but helpful, avoid noise

Code Style:
- Follow language conventions like PEP 8 for Python
- Use automated formatters for consistency
- Prefer descriptive names over comments
- Use named constants, avoid magic numbers
- Keep code flat, avoid deep nesting

Response Guidelines:
- Start response with '<hi>'
- Answer what's asked, don't over-engineer
- Provide immediately runnable solutions
- Explain trade-offs when multiple approaches exist
- Be helpful but concise
- Work within established architecture patterns
- When you make structural, architectural, or functional changes, (or model changes, new decisions/gotchas, etc.) ask whether to update @project_context.mdc
- End response with '</hi>'
129 changes: 129 additions & 0 deletions .cursor/rules/project_context.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
---
description:
globs:
alwaysApply: false
---
# Project Context: Siren AI Python SDK

## Project Summary

Official Python SDK for the [Siren notification platform](mdc:https:/docs.trysiren.io). Provides type-safe interface for managing templates, workflows, users, messaging, and webhooks. Built with Pydantic validation, structured error handling, and modular client-based architecture.

## Key Features / Functional Modules

- **Templates** - Create, update, delete, publish templates and channel configurations → `siren/clients/templates.py`
- **Users** - Add, update, delete users → `siren/clients/users.py`
- **Messaging** - Send messages, get replies, track status → `siren/clients/messaging.py`
- **Webhooks** - Configure notification and inbound webhooks → `siren/clients/webhooks.py`
- **Workflows** - Trigger single/bulk workflows and scheduling → `siren/clients/workflows.py`
- **Client** - Unified API entry point → `siren/client.py`

## Codebase Structure Overview

```
siren-ai/
├── siren/ # Main SDK package
│ ├── client.py # Main SirenClient - unified API entry point
│ ├── exceptions.py # Custom exception classes (SirenAPIError, SirenSDKError)
│ ├── clients/ # Domain client implementations (core pattern)
│ │ ├── base.py # BaseClient - shared HTTP/error handling
│ │ ├── templates.py # TemplateClient - template operations
│ │ ├── users.py # UserClient - user management
│ │ ├── messaging.py # MessageClient - message operations
│ │ ├── webhooks.py # WebhookClient - webhook configuration
│ │ └── workflows.py # WorkflowClient - workflow operations
│ └── models/ # Pydantic data models
│ ├── base.py # Base response models and common patterns
│ ├── templates.py # Template-specific models
│ ├── user.py # User-specific models
│ ├── messaging.py # Messaging models
│ ├── webhooks.py # Webhook models
│ └── workflows.py # Workflow models
├── tests/ # Comprehensive test suite with ~92% coverage
├── examples/ # Usage examples for each module
├── pyproject.toml # Project configuration, dependencies, tools
└── README.md # Installation, usage, and API documentation
```

## Architecture & Data Flow

**Layered Architecture**:
- **Client** (`SirenClient`) - Thin facade delegating to domain clients
- **Domain Clients** (`TemplateClient`, `UserClient`, etc.) - Domain-specific API handlers, inherit from `BaseClient` for unified HTTP/error handling
- **Models** (Pydantic) - Request/response validation, field aliasing (snake_case ↔ camelCase)
- **Exceptions** - `SirenAPIError` (API errors: 400/401/404) vs `SirenSDKError` (SDK issues: network/validation)

**BaseClient Pattern** (Core Architecture):
- All domain clients inherit from `BaseClient` for consistent HTTP handling
- Requires both `request_model` and `response_model` for JSON operations
- Automatic Pydantic validation, error handling, and response parsing
- Common patterns: `DeleteResponse[None]` for 204 responses, flexible models with optional fields

**Request Flow**: Client → Domain Client → HTTP Request → API → Response → Model → Client
- Domain clients prepare requests with Pydantic validation → HTTP to Siren API → Responses parsed through models → Errors become structured exceptions

**Implementation Details**:
- **HTTP Client**: `requests` library with 10s timeout (hardcoded, TODO: make configurable)
- **Authentication**: Bearer token in `Authorization` header
- **Status Handling**: Explicit `if status_code == 200` checks instead of `response.ok`
- **API Versioning**: Templates/Users/Messaging/Webhooks use `/api/v1/public/`, Workflows use `/api/v2/`
- **Environment Support**: Both `SirenClient` *and* `AsyncSirenClient` automatically read `SIREN_API_KEY` and optional `SIREN_ENV` on instantiation. Production (`https://api.trysiren.io`) is the default; switch to dev (`https://api.dev.trysiren.io`) by setting `SIREN_ENV=dev` or passing `env="dev"` explicitly.

## Tech Stack

**Core**: Python 3.8+, `requests`, `pydantic[email]`
**Dev Tools**: `pytest` + mocking, `ruff`, `pyright`, `pre-commit`, `uv`

## Testing

**Strategy**: `requests-mock` with realistic API data
**Organization**: One test file per domain client, shared `client` fixture
**Philosophy**: SDK testing focuses on request formatting, response parsing, error propagation - not API business logic

## Key Files

- **`siren/client.py`** - Main client interface
- **`siren/clients/base.py`** - BaseClient with unified HTTP/error handling (core pattern)
- **`siren/clients/templates.py`** - Most complex domain client, full BaseClient patterns
- **`siren/models/base.py`** - Core models and error handling
- **`siren/exceptions.py`** - Exception patterns

## Gotchas

**Field Serialization**: Always use `by_alias=True` when calling `model_dump()`
**BaseClient Requirements**: Both request_model and response_model needed for JSON operations

## TODO / Future Areas

**Architecture Enhancements**:
- Add retry logic for transient network failures
- Add request/response logging capabilities

**Testing Gaps**:
- Integration tests against live API (currently only unit tests with mocks)

## Documentation / Examples

**Example Script Guidelines**:
- Call `dotenv.load_dotenv()` first so environment variables from a `.env` file are available.
- Instantiate the sync (`SirenClient()`) or async (`AsyncSirenClient()`) client **without arguments** – the constructor will pick up `SIREN_API_KEY` & `SIREN_ENV` automatically.
- Wrap core SDK calls in minimal error handling:
```python
try:
... # SDK call(s)
except SirenAPIError as e:
print(f"API error: {e.error_code} - {e.api_message}")
except SirenSDKError as e:
print(f"SDK error: {e.message}")
```
- Print only the key fields from responses (e.g., `id`, `url`, `status`) to keep output concise.
- Scripts should demonstrate one or two primary operations per domain—avoid extra verbosity.

## HTTP Transport & Sync/Async Support
- Under the hood the SDK now uses a pluggable transport layer (`siren/http/transport.py`).
- **Sync** clients delegate to `SyncTransport` (currently wraps `requests`, easy to flip to `httpx.Client`).
- **Async** clients delegate to `AsyncTransport` which wraps `httpx.AsyncClient`.
- Every domain client has a 1-to-1 async counterpart; `AsyncSirenClient` exposes them.
- Sync and async share identical method names and signatures—just `await` the async version.
- Testing: existing sync tests use `requests-mock`; async tests use **respx** for `httpx`.
- Examples: each domain has both `*_async.py` and sync counterpart in `examples/` demonstrating identical flows.
31 changes: 31 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Publish to PyPI

on:
workflow_dispatch:
push:
tags:
- "v*.*.*" # e.g. v1.2.3

jobs:
build-and-upload:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.11" # choose what you like

- name: Install build tools
run: python -m pip install --upgrade build twine

- name: Build wheel & sdist
run: python -m build # outputs to ./dist

- name: Upload to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: python -m twine upload dist/* --non-interactive
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ Thumbs.db
secrets.yaml
*.pem
*.key

# windsurf rules
.windsurfrules
22 changes: 22 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
MIT License

Copyright (c) 2025 KeyValue Software Systems


Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading