Skip to content

Commit 946317a

Browse files
committed
initial commit
1 parent 77d2014 commit 946317a

9 files changed

Lines changed: 1364 additions & 0 deletions

File tree

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.11

README.md

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# Aptabase Python SDK
2+
3+
Python SDK for [Aptabase](https://aptabase.com/) - privacy-first analytics for mobile, desktop and web applications.
4+
5+
## Features
6+
7+
- 🚀 **Fully async** - Built with `httpx` and `asyncio`
8+
- 🔒 **Privacy-first** - No personal data collection
9+
- 🏃 **Modern Python** - Requires Python 3.11+
10+
- 📦 **Type-safe** - Full typing support
11+
- 🔄 **Auto-batching** - Efficient event batching and flushing
12+
-**Lightweight** - Minimal dependencies
13+
14+
## Installation
15+
16+
```bash
17+
uv add aptabase
18+
# or
19+
pip install aptabase
20+
```
21+
22+
## Quick Start
23+
24+
```python
25+
import asyncio
26+
from aptabase import Aptabase
27+
28+
async def main():
29+
async with Aptabase("A-EU-1234567890") as client:
30+
# Track a simple event
31+
await client.track("app_started")
32+
33+
# Track an event with properties
34+
await client.track("user_action", {
35+
"action": "button_click",
36+
"button_id": "login",
37+
"screen": "home"
38+
})
39+
40+
# Events are automatically flushed, but you can force it
41+
await client.flush()
42+
43+
asyncio.run(main())
44+
```
45+
46+
## Configuration
47+
48+
```python
49+
client = Aptabase(
50+
app_key="A-EU-1234567890", # Your Aptabase app key
51+
app_version="1.2.3", # Your app version
52+
is_debug=False, # Enable debug mode
53+
max_batch_size=25, # Max events per batch (max 25)
54+
flush_interval=10.0, # Auto-flush interval in seconds
55+
timeout=30.0 # HTTP timeout in seconds
56+
)
57+
```
58+
59+
## App Key Format
60+
61+
Your app key determines the server region:
62+
- `A-EU-*` - European servers
63+
- `A-US-*` - US servers
64+
65+
Get your app key from the [Aptabase dashboard](https://aptabase.com/).
66+
67+
## Event Tracking
68+
69+
### Simple Events
70+
71+
```python
72+
await client.track("page_view")
73+
```
74+
75+
### Events with Properties
76+
77+
```python
78+
await client.track("purchase", {
79+
"product_id": "abc123",
80+
"price": 29.99,
81+
"currency": "USD"
82+
})
83+
```
84+
85+
### Session Management
86+
87+
```python
88+
# Set a custom session ID
89+
client.set_session_id("my-custom-session-id")
90+
91+
# Track events with specific session
92+
await client.track("login", session_id="user-session-123")
93+
```
94+
95+
## Context Manager vs Manual Lifecycle
96+
97+
### Recommended: Context Manager
98+
99+
```python
100+
async with Aptabase("A-EU-1234567890") as client:
101+
await client.track("event")
102+
# Automatically handles start/stop and flushing
103+
```
104+
105+
### Manual Lifecycle
106+
107+
```python
108+
client = Aptabase("A-EU-1234567890")
109+
await client.start()
110+
try:
111+
await client.track("event")
112+
finally:
113+
await client.stop() # Ensures all events are flushed
114+
```
115+
116+
## Error Handling
117+
118+
```python
119+
from aptabase import Aptabase, AptabaseError, NetworkError
120+
121+
try:
122+
async with Aptabase("A-EU-1234567890") as client:
123+
await client.track("event")
124+
except NetworkError as e:
125+
print(f"Network error: {e}, status: {e.status_code}")
126+
except AptabaseError as e:
127+
print(f"Aptabase error: {e}")
128+
```
129+
130+
## Development
131+
132+
Install development dependencies:
133+
134+
```bash
135+
uv sync --dev
136+
```
137+
138+
Run tests:
139+
140+
```bash
141+
uv run pytest
142+
```
143+
144+
Code formatting:
145+
146+
```bash
147+
uv run black .
148+
uv run ruff check .
149+
```
150+
151+
Type checking:
152+
153+
```bash
154+
uv run mypy .
155+
```
156+
157+
## License
158+
159+
MIT License - see [LICENSE](LICENSE) file for details.

pyproject.toml

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
[project]
2+
name = "aptabase"
3+
version = "0.0.1"
4+
description = "Python SDK for Aptabase analytics"
5+
readme = "README.md"
6+
requires-python = ">=3.11"
7+
license = "MIT"
8+
keywords = ["analytics", "aptabase", "async", "privacy"]
9+
authors = [
10+
{ name = "Aptabase", email = "support@aptabase.com" },
11+
]
12+
dependencies = [
13+
"httpx>=0.28.1",
14+
]
15+
classifiers = [
16+
"Intended Audience :: Developers",
17+
"Topic :: Software Development :: Build Tools",
18+
"Programming Language :: Python :: 3.11",
19+
"Programming Language :: Python :: 3.12",
20+
"Programming Language :: Python :: 3.13",
21+
]
22+
23+
[dependency-groups]
24+
dev = [
25+
"pytest>=9.0.2",
26+
"pytest-asyncio>=1.0.0",
27+
"pytest-httpx>=0.35.0",
28+
"pytest-trio>=0.8.0",
29+
"pytest-cov>=4.1.0",
30+
"pytest-mock>=3.11.1",
31+
"black>=25.12.0",
32+
"ruff>=0.14.9",
33+
"mypy>=1.19.0",
34+
]
35+
36+
[project.urls]
37+
Documentation = "https://github.com/aptabase/aptabase-python"
38+
Issues = "https://github.com/aptabase/aptabase-python/issues"
39+
Source = "https://github.com/aptabase/aptabase-python"
40+
41+
[build-system]
42+
requires = ["hatchling"]
43+
build-backend = "hatchling.build"
44+
45+
[tool.hatch.build.targets.wheel]
46+
packages = ["src/aptabase"]
47+
48+
[tool.ruff]
49+
line-length = 88
50+
indent-width = 4
51+
exclude = ["samples/**", "testcases/**"]
52+
53+
[tool.ruff.lint]
54+
select = ["E", "F", "B", "I", "D"]
55+
ignore = ["D417"]
56+
57+
[tool.ruff.lint.pydocstyle]
58+
convention = "google"
59+
ignore-decorators = []
60+
61+
[tool.ruff.lint.per-file-ignores]
62+
"*" = ["E501"]
63+
"tests/**" = ["D"]
64+
"*_test.py" = ["D"]
65+
66+
[tool.ruff.format]
67+
quote-style = "double"
68+
indent-style = "space"
69+
skip-magic-trailing-comma = false
70+
line-ending = "auto"
71+
72+
[tool.mypy]
73+
plugins = ["pydantic.mypy"]
74+
mypy_path = "src"
75+
explicit_package_bases = true
76+
namespace_packages = true
77+
follow_imports = "silent"
78+
warn_redundant_casts = true
79+
warn_unused_ignores = true
80+
disallow_any_generics = true
81+
check_untyped_defs = true
82+
no_implicit_reexport = true
83+
disallow_untyped_defs = false
84+
85+
[tool.pydantic-mypy]
86+
init_forbid_extra = true
87+
init_typed = true
88+
warn_required_dynamic_aliases = true
89+
90+
[tool.pytest.ini_options]
91+
testpaths = ["tests"]
92+
python_files = "test_*.py"
93+
addopts = "-ra -q --cov=src/uipath --cov-report=term-missing"
94+
asyncio_default_fixture_loop_scope = "function"
95+
asyncio_mode = "auto"
96+
97+
[tool.coverage.report]
98+
show_missing = true
99+
100+
[tool.coverage.run]
101+
source = ["src"]

samples/simple-script/example.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/usr/bin/env python3
2+
"""Example usage of the Aptabase Python SDK."""
3+
4+
import asyncio
5+
import logging
6+
7+
from aptabase import Aptabase, AptabaseError
8+
9+
# Enable logging to see what's happening
10+
logging.basicConfig(level=logging.DEBUG)
11+
12+
13+
async def main():
14+
"""Example demonstrating various SDK features."""
15+
16+
# Replace with your actual app key
17+
app_key = "A-EU-0000000000" # This is a fake key for demo purposes
18+
19+
try:
20+
# Method 1: Using context manager (recommended)
21+
print("🚀 Starting Aptabase example...")
22+
23+
async with Aptabase(
24+
app_key=app_key,
25+
app_version="1.0.0",
26+
is_debug=True,
27+
max_batch_size=10,
28+
flush_interval=5.0,
29+
) as client:
30+
# Track simple events
31+
await client.track("app_started")
32+
await client.track("example_run")
33+
34+
# Track events with properties
35+
await client.track(
36+
"user_action",
37+
{
38+
"action": "button_click",
39+
"button_id": "demo_button",
40+
"screen": "main",
41+
"timestamp": "2023-12-12T10:00:00Z",
42+
},
43+
)
44+
45+
await client.track(
46+
"feature_used",
47+
{"feature": "analytics", "user_type": "developer", "success": True},
48+
)
49+
50+
# Set a custom session ID
51+
client.set_session_id("demo-session-123")
52+
53+
await client.track("session_event", {"event_type": "demo", "duration": 120})
54+
55+
# Track multiple events quickly
56+
for i in range(5):
57+
await client.track(
58+
"batch_event", {"batch_number": i, "data": f"item_{i}"}
59+
)
60+
61+
# Manual flush (optional - happens automatically)
62+
print("📤 Flushing events...")
63+
await client.flush()
64+
65+
# Wait a bit to see periodic flushing in action
66+
await asyncio.sleep(2)
67+
68+
await client.track("final_event", {"status": "completed"})
69+
70+
print("✅ Example completed successfully!")
71+
72+
except AptabaseError as e:
73+
print(f"❌ Aptabase error: {e}")
74+
except Exception as e:
75+
print(f"❌ Unexpected error: {e}")
76+
77+
78+
async def manual_lifecycle_example():
79+
"""Example showing manual client lifecycle management."""
80+
print("\n🔧 Manual lifecycle example...")
81+
82+
client = Aptabase("A-EU-0000000000", app_version="1.0.0")
83+
84+
try:
85+
await client.start()
86+
await client.track("manual_start")
87+
await client.track("manual_event", {"method": "manual"})
88+
print("📤 Manually flushing...")
89+
await client.flush()
90+
finally:
91+
await client.stop()
92+
93+
print("✅ Manual lifecycle example completed!")
94+
95+
96+
if __name__ == "__main__":
97+
print("Aptabase Python SDK Example")
98+
print("=" * 40)
99+
100+
# Run the examples
101+
asyncio.run(main())
102+
asyncio.run(manual_lifecycle_example())

src/aptabase/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""Aptabase Python SDK - Async analytics for privacy-conscious developers."""
2+
3+
__version__ = "0.1.0"
4+
5+
from .client import Aptabase
6+
from .exceptions import AptabaseError, ConfigurationError, NetworkError
7+
from .models import Event, SystemProperties
8+
9+
__all__ = [
10+
"Aptabase",
11+
"Event",
12+
"SystemProperties",
13+
"AptabaseError",
14+
"ConfigurationError",
15+
"NetworkError",
16+
]

0 commit comments

Comments
 (0)