# Snail Orbit Python Client Library
A modern, type-safe Python client for the Snail Orbit project management system. Focused on data access and read operations with comprehensive error handling and automatic schema validation.
## 🚀 Features
- **Dual Client Architecture**: Full-featured synchronous and asynchronous clients
- **Type Safety**: Complete type hints with Pydantic v2 models and mypy compatibility
- **Authentication**: Bearer token and JWT authentication support
- **Error Handling**: Comprehensive exception hierarchy with context
- **Pagination**: Automatic pagination with iterator pattern
- **Search & Filtering**: Advanced search and filtering capabilities
## 📦 Installation
```bash
# Using uv (recommended)
uv add snail-orbit-client
# Using pip
pip install snail-orbit-client
```
## 🔧 Quick Start
### Basic Usage
```python
from snail_orbit_client import SnailOrbitClient
# Initialize client
client = SnailOrbitClient(
base_url="https://your-snail-orbit.example.com",
token="your-api-token"
)
# Get user profile
profile = client.auth.get_profile()
print(f"Logged in as: {profile.name} ({profile.email})")
# List users with search
for user in client.users.list(search="john"):
print(f"User: {user.name} ({user.email})")
# List projects with filtering
for project in client.projects.list(filter="is_active___eq:true"):
print(f"Active project: {project.name}")
# List issues with query language
for issue in client.issues.list(q="priority:high and status:open"):
print(f"Urgent issue: {issue.id_readable} - {issue.subject}")
print(f"Time spent: {issue.hours_spent} hours")
# Get specific records
user = client.users.get("user-id")
project = client.projects.get("project-id")
specific_issue = client.issues.get("issue-id")
# Access custom fields
priority_field = specific_issue.fields.get('priority')
if priority_field:
print(f"Priority: {priority_field.value}")
```
### Async Usage
```python
import asyncio
from snail_orbit_client import SnailOrbitAsyncClient
async def main():
async with SnailOrbitAsyncClient(
base_url="https://your-snail-orbit.example.com",
token="your-api-token"
) as client:
# Get user profile
profile = await client.auth.get_profile()
print(f"Logged in as: {profile.name} ({profile.email})")
# List projects
projects = []
async for project in client.projects.list():
projects.append(project)
# Search issues
urgent_issues = []
async for issue in client.issues.list(q="priority:high and status:open"):
urgent_issues.append(issue)
asyncio.run(main())
```
## 💪 Available Operations
### **Authentication**
- ✅ `auth.get_profile()` - Get current user profile
### **Users**
- ✅ `users.list(search=None, filter=None)` - List/search users
- ✅ `users.get(user_id)` - Get user by ID
### **Projects**
- ✅ `projects.list(search=None, filter=None)` - List/search projects
- ✅ `projects.get(project_id)` - Get project by ID
### **Issues**
- ✅ `issues.list(q=None, search=None)` - List/query issues
- ✅ `issues.get(issue_id)` - Get issue by ID
- ✅ `issues.get_by_readable_id(readable_id)` - Get issue by readable ID (e.g., "PRJ-123")
- ✅ `issues.create(issue_data)` - Create new issue
- ✅ `issues.update(issue_id, issue_data)` - Update issue
- ✅ `issues.delete(issue_id)` - Delete issue
- ✅ `issues.subscribe(issue_id)` - Subscribe to notifications
- ✅ `issues.unsubscribe(issue_id)` - Unsubscribe from notifications
### **Issue Comments**
- ✅ `issues.get_comments(issue_id)` - List comments for issue
- ✅ `issues.get_comment(issue_id, comment_id)` - Get specific comment
- ✅ `issues.create_comment(issue_id, comment_data)` - Create comment
- ✅ `issues.update_comment(issue_id, comment_id, comment_data)` - Update comment
- ✅ `issues.delete_comment(issue_id, comment_id)` - Delete comment
### **Issue Tags**
- ✅ `issues.add_tag(issue_id, tag_id)` - Add tag to issue
- ✅ `issues.remove_tag(issue_id, tag_id)` - Remove tag from issue
### **Custom Fields**
- ✅ `custom_fields.list_groups()` - List custom field groups
- ✅ `custom_fields.get_group(group_gid)` - Get custom field group
- ✅ `custom_fields.get_field(field_id)` - Get custom field
### **Activity Tracking**
- ✅ `activity.list(start, end, user_id=None)` - List activities by time range
## 🎯 Search & Filtering
### Users & Projects
Use `search` and `filter` parameters:
```python
# Text search
client.users.list(search="john doe")
client.projects.list(search="api project")
# Query language filtering
client.users.list(filter="is_active___eq:true and name___contains:developer")
client.projects.list(filter="created_at___gte:2024-01-01")
# Combined search and filter
client.users.list(search="john", filter="is_admin___eq:false")
```
### Issues
Use `q` (query language) and `search` parameters:
```python
# Query language (structured queries)
client.issues.list(q="priority:high and status:open")
client.issues.list(q="assignee:me and project:myproject")
# Text search
client.issues.list(search="database bug")
# Combined query and search
client.issues.list(q="status:open", search="authentication")
```
## 🔧 Advanced Configuration
```python
from snail_orbit_client import SnailOrbitClient, ClientConfig
config = ClientConfig(
timeout=30.0, # Request timeout in seconds
max_retries=3, # Maximum retry attempts
retry_delay=1.0, # Base delay between retries
user_agent="MyApp/1.0.0" # Custom user agent
)
client = SnailOrbitClient(
base_url="https://your-snail-orbit.example.com",
token="your-token",
config=config
)
```
### JWT Authentication
```python
# JWT signing with service credentials
# Requires backend configuration in API_SERVICE_TOKEN_KEYS
client = SnailOrbitClient(
base_url="https://api.snail-orbit.com",
token=("test", "test", "user-id") # (kid, secret, user_id)
)
```
## 🏗️ Architecture
### **Pure API Client Design**
- **Direct API Access**: Models mirror API responses without abstraction
- **Generated Models**: Auto-synchronized with OpenAPI schema
- **Type-Safe**: Full mypy compatibility with strict type checking
- **Iterator Pattern**: Efficient pagination for large datasets
### **Resource Organization**
```python
client.auth # Authentication and profile management
client.users # User read operations
client.projects # Project read operations
client.issues # Issue management (full CRUD)
client.custom_fields # Custom field read operations
client.activity # Activity tracking and audit logs
```
## 🔒 Security & Reliability
- **Secure Token Handling**: Safe storage and transmission of credentials
- **JWT Signing**: Request-specific JWT with method/path hashing
- **Structured Exceptions**: Comprehensive error hierarchy with context
- **HTTP Status Mapping**: Specific exceptions for 401, 403, 404, 422, 429, 5xx
- **Retry Logic**: Exponential backoff with configurable limits
- **Schema Validation**: Automatic validation against API schema
Raw data
{
"_id": null,
"home_page": null,
"name": "snail-orbit-client",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "api-client, project-management, snail-orbit, task-tracking",
"author": null,
"author_email": "Snail Orbit Team <dev@snorbit.app>",
"download_url": null,
"platform": null,
"description": "# Snail Orbit Python Client Library\n\nA modern, type-safe Python client for the Snail Orbit project management system. Focused on data access and read operations with comprehensive error handling and automatic schema validation.\n\n## \ud83d\ude80 Features\n\n- **Dual Client Architecture**: Full-featured synchronous and asynchronous clients\n- **Type Safety**: Complete type hints with Pydantic v2 models and mypy compatibility\n- **Authentication**: Bearer token and JWT authentication support\n- **Error Handling**: Comprehensive exception hierarchy with context\n- **Pagination**: Automatic pagination with iterator pattern\n- **Search & Filtering**: Advanced search and filtering capabilities\n\n## \ud83d\udce6 Installation\n\n```bash\n# Using uv (recommended)\nuv add snail-orbit-client\n\n# Using pip\npip install snail-orbit-client\n```\n\n## \ud83d\udd27 Quick Start\n\n### Basic Usage\n\n```python\nfrom snail_orbit_client import SnailOrbitClient\n\n# Initialize client\nclient = SnailOrbitClient(\n base_url=\"https://your-snail-orbit.example.com\",\n token=\"your-api-token\"\n)\n\n# Get user profile\nprofile = client.auth.get_profile()\nprint(f\"Logged in as: {profile.name} ({profile.email})\")\n\n# List users with search\nfor user in client.users.list(search=\"john\"):\n print(f\"User: {user.name} ({user.email})\")\n\n# List projects with filtering\nfor project in client.projects.list(filter=\"is_active___eq:true\"):\n print(f\"Active project: {project.name}\")\n\n# List issues with query language\nfor issue in client.issues.list(q=\"priority:high and status:open\"):\n print(f\"Urgent issue: {issue.id_readable} - {issue.subject}\")\n print(f\"Time spent: {issue.hours_spent} hours\")\n\n# Get specific records\nuser = client.users.get(\"user-id\")\nproject = client.projects.get(\"project-id\")\nspecific_issue = client.issues.get(\"issue-id\")\n\n# Access custom fields\npriority_field = specific_issue.fields.get('priority')\nif priority_field:\n print(f\"Priority: {priority_field.value}\")\n```\n\n### Async Usage\n\n```python\nimport asyncio\nfrom snail_orbit_client import SnailOrbitAsyncClient\n\nasync def main():\n async with SnailOrbitAsyncClient(\n base_url=\"https://your-snail-orbit.example.com\",\n token=\"your-api-token\"\n ) as client:\n\n # Get user profile\n profile = await client.auth.get_profile()\n print(f\"Logged in as: {profile.name} ({profile.email})\")\n\n # List projects\n projects = []\n async for project in client.projects.list():\n projects.append(project)\n\n # Search issues\n urgent_issues = []\n async for issue in client.issues.list(q=\"priority:high and status:open\"):\n urgent_issues.append(issue)\n\nasyncio.run(main())\n```\n\n## \ud83d\udcaa Available Operations\n\n### **Authentication**\n- \u2705 `auth.get_profile()` - Get current user profile\n\n### **Users**\n- \u2705 `users.list(search=None, filter=None)` - List/search users\n- \u2705 `users.get(user_id)` - Get user by ID\n\n### **Projects**\n- \u2705 `projects.list(search=None, filter=None)` - List/search projects\n- \u2705 `projects.get(project_id)` - Get project by ID\n\n### **Issues**\n- \u2705 `issues.list(q=None, search=None)` - List/query issues\n- \u2705 `issues.get(issue_id)` - Get issue by ID\n- \u2705 `issues.get_by_readable_id(readable_id)` - Get issue by readable ID (e.g., \"PRJ-123\")\n- \u2705 `issues.create(issue_data)` - Create new issue\n- \u2705 `issues.update(issue_id, issue_data)` - Update issue\n- \u2705 `issues.delete(issue_id)` - Delete issue\n- \u2705 `issues.subscribe(issue_id)` - Subscribe to notifications\n- \u2705 `issues.unsubscribe(issue_id)` - Unsubscribe from notifications\n\n### **Issue Comments**\n- \u2705 `issues.get_comments(issue_id)` - List comments for issue\n- \u2705 `issues.get_comment(issue_id, comment_id)` - Get specific comment\n- \u2705 `issues.create_comment(issue_id, comment_data)` - Create comment\n- \u2705 `issues.update_comment(issue_id, comment_id, comment_data)` - Update comment\n- \u2705 `issues.delete_comment(issue_id, comment_id)` - Delete comment\n\n### **Issue Tags**\n- \u2705 `issues.add_tag(issue_id, tag_id)` - Add tag to issue\n- \u2705 `issues.remove_tag(issue_id, tag_id)` - Remove tag from issue\n\n### **Custom Fields**\n- \u2705 `custom_fields.list_groups()` - List custom field groups\n- \u2705 `custom_fields.get_group(group_gid)` - Get custom field group\n- \u2705 `custom_fields.get_field(field_id)` - Get custom field\n\n### **Activity Tracking**\n- \u2705 `activity.list(start, end, user_id=None)` - List activities by time range\n\n## \ud83c\udfaf Search & Filtering\n\n### Users & Projects\nUse `search` and `filter` parameters:\n\n```python\n# Text search\nclient.users.list(search=\"john doe\")\nclient.projects.list(search=\"api project\")\n\n# Query language filtering\nclient.users.list(filter=\"is_active___eq:true and name___contains:developer\")\nclient.projects.list(filter=\"created_at___gte:2024-01-01\")\n\n# Combined search and filter\nclient.users.list(search=\"john\", filter=\"is_admin___eq:false\")\n```\n\n### Issues\nUse `q` (query language) and `search` parameters:\n\n```python\n# Query language (structured queries)\nclient.issues.list(q=\"priority:high and status:open\")\nclient.issues.list(q=\"assignee:me and project:myproject\")\n\n# Text search\nclient.issues.list(search=\"database bug\")\n\n# Combined query and search\nclient.issues.list(q=\"status:open\", search=\"authentication\")\n```\n\n## \ud83d\udd27 Advanced Configuration\n\n```python\nfrom snail_orbit_client import SnailOrbitClient, ClientConfig\n\nconfig = ClientConfig(\n timeout=30.0, # Request timeout in seconds\n max_retries=3, # Maximum retry attempts\n retry_delay=1.0, # Base delay between retries\n user_agent=\"MyApp/1.0.0\" # Custom user agent\n)\n\nclient = SnailOrbitClient(\n base_url=\"https://your-snail-orbit.example.com\",\n token=\"your-token\",\n config=config\n)\n```\n\n### JWT Authentication\n\n```python\n# JWT signing with service credentials\n# Requires backend configuration in API_SERVICE_TOKEN_KEYS\nclient = SnailOrbitClient(\n base_url=\"https://api.snail-orbit.com\",\n token=(\"test\", \"test\", \"user-id\") # (kid, secret, user_id)\n)\n```\n\n\n## \ud83c\udfd7\ufe0f Architecture\n\n### **Pure API Client Design**\n- **Direct API Access**: Models mirror API responses without abstraction\n- **Generated Models**: Auto-synchronized with OpenAPI schema\n- **Type-Safe**: Full mypy compatibility with strict type checking\n- **Iterator Pattern**: Efficient pagination for large datasets\n\n### **Resource Organization**\n```python\nclient.auth # Authentication and profile management\nclient.users # User read operations\nclient.projects # Project read operations\nclient.issues # Issue management (full CRUD)\nclient.custom_fields # Custom field read operations\nclient.activity # Activity tracking and audit logs\n```\n\n## \ud83d\udd12 Security & Reliability\n\n- **Secure Token Handling**: Safe storage and transmission of credentials\n- **JWT Signing**: Request-specific JWT with method/path hashing\n- **Structured Exceptions**: Comprehensive error hierarchy with context\n- **HTTP Status Mapping**: Specific exceptions for 401, 403, 404, 422, 429, 5xx\n- **Retry Logic**: Exponential backoff with configurable limits\n- **Schema Validation**: Automatic validation against API schema\n",
"bugtrack_url": null,
"license": null,
"summary": "Type-safe Python client for Snail Orbit project management system with read operations and issue management",
"version": "0.5.1",
"project_urls": null,
"split_keywords": [
"api-client",
" project-management",
" snail-orbit",
" task-tracking"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "fb62bfc4350302eaeea0d74a10c9141ffc2867c12c23a9562ae74904d4c9148f",
"md5": "a1c71672c6fc2455a4401aeb8f23dfdd",
"sha256": "564625b6f75483cb69c684a31464b5d04fad39a6e517abf353c5dbaf94fb1dcc"
},
"downloads": -1,
"filename": "snail_orbit_client-0.5.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "a1c71672c6fc2455a4401aeb8f23dfdd",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 47224,
"upload_time": "2025-08-22T00:38:13",
"upload_time_iso_8601": "2025-08-22T00:38:13.149233Z",
"url": "https://files.pythonhosted.org/packages/fb/62/bfc4350302eaeea0d74a10c9141ffc2867c12c23a9562ae74904d4c9148f/snail_orbit_client-0.5.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-22 00:38:13",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "snail-orbit-client"
}