Timeback Caliper client for learning analytics events
Project description
timeback-caliper
Python client for sending Caliper learning analytics events to Timeback.
Installation
# pip
pip install timeback-caliper
# uv (add to a project)
uv add timeback-caliper
# uv (install into current environment)
uv pip install timeback-caliper
Quick Start
from timeback_caliper import (
CaliperClient,
ActivityCompletedInput,
TimebackUser,
TimebackActivityContext,
TimebackApp,
TimebackActivityMetric,
)
# Initialize client
client = CaliperClient(
env="staging", # or "production"
client_id="your-client-id",
client_secret="your-client-secret",
)
# Send an activity completed event
result = await client.events.send_activity(
sensor_id="https://myapp.example.com/sensors/main",
input=ActivityCompletedInput(
actor=TimebackUser(
id="https://example.edu/users/123",
email="student@example.edu",
),
object=TimebackActivityContext(
id="https://myapp.example.com/activities/456",
subject="Math",
app=TimebackApp(name="My Learning App"),
),
metrics=[
TimebackActivityMetric(type="totalQuestions", value=10),
TimebackActivityMetric(type="correctQuestions", value=8),
TimebackActivityMetric(type="xpEarned", value=150),
],
),
)
# Wait for processing
status = await client.jobs.wait_for_completion(result.job_id)
print(f"Processed {status.events_processed} events")
FastAPI Integration
from fastapi import FastAPI, HTTPException
from timeback_caliper import (
CaliperClient,
ActivityCompletedInput,
APIError,
)
app = FastAPI()
# Initialize client (reuse across requests)
caliper = CaliperClient(
env="staging",
client_id="...",
client_secret="...",
)
@app.post("/api/activity")
async def submit_activity(input: ActivityCompletedInput):
"""Submit a learning activity event."""
try:
result = await caliper.events.send_activity(
sensor_id="https://myapp.example.com/sensors/main",
input=input,
)
return {"success": True, "job_id": result.job_id}
except APIError as e:
raise HTTPException(status_code=e.status_code or 500, detail=str(e))
@app.on_event("shutdown")
async def shutdown():
await caliper.close()
Event Types
ActivityCompletedEvent
Records when a student completes an activity with performance metrics:
from timeback_caliper import (
ActivityCompletedInput,
TimebackUser,
TimebackActivityContext,
TimebackApp,
TimebackCourse,
TimebackActivityMetric,
)
input = ActivityCompletedInput(
actor=TimebackUser(
id="https://example.edu/users/123",
email="student@example.edu",
name="Jane Doe",
role="student",
),
object=TimebackActivityContext(
id="https://myapp.example.com/activities/456",
subject="Math",
app=TimebackApp(name="My Learning App"),
course=TimebackCourse(name="Algebra 101"),
),
metrics=[
TimebackActivityMetric(type="totalQuestions", value=10),
TimebackActivityMetric(type="correctQuestions", value=8),
TimebackActivityMetric(type="xpEarned", value=150),
TimebackActivityMetric(type="masteredUnits", value=1),
],
)
result = await client.events.send_activity(sensor_id, input)
TimeSpentEvent
Records time spent on an activity:
from timeback_caliper import TimeSpentInput, TimeSpentMetric
input = TimeSpentInput(
actor=TimebackUser(id="...", email="..."),
object=TimebackActivityContext(id="...", subject="Reading", app=TimebackApp(name="...")),
metrics=[
TimeSpentMetric(type="active", value=1800), # 30 minutes
TimeSpentMetric(type="inactive", value=300), # 5 minutes
],
)
result = await client.events.send_time_spent(sensor_id, input)
Job Tracking
Events are processed asynchronously. Track processing status:
# Get job status
status = await client.jobs.get_status(job_id)
print(f"Status: {status.status}")
# Wait for completion (with timeout)
status = await client.jobs.wait_for_completion(
job_id,
timeout=60.0, # Max wait time
poll_interval=1.0, # Check every second
)
if status.status == "completed":
print(f"Processed {status.events_processed} events")
elif status.status == "failed":
print(f"Failed: {status.error}")
Context Manager
Use the client as an async context manager for automatic cleanup:
async with CaliperClient(client_id="...", client_secret="...") as client:
await client.events.send_activity(sensor_id, input)
# Client is automatically closed
Error Handling
from timeback_caliper import (
CaliperClient,
AuthenticationError,
APIError,
)
try:
result = await client.events.send_activity(sensor_id, input)
except AuthenticationError:
print("Invalid credentials")
except APIError as e:
print(f"API error ({e.status_code}): {e}")
Configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
env |
str |
None |
"staging" or "production" |
base_url |
str |
auto | Override API URL |
auth_url |
str |
auto | Override auth URL |
client_id |
str |
env var | OAuth2 client ID |
client_secret |
str |
env var | OAuth2 client secret |
timeout |
float |
30.0 |
Request timeout in seconds |
Environment Variables
CALIPER_CLIENT_ID=your-client-id
CALIPER_CLIENT_SECRET=your-client-secret
CALIPER_BASE_URL=https://api.staging.timeback.com
CALIPER_TOKEN_URL=https://auth.staging.timeback.com/oauth2/token
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file timeback_caliper-0.1.4.tar.gz.
File metadata
- Download URL: timeback_caliper-0.1.4.tar.gz
- Upload date:
- Size: 25.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6d5111744494b4e99738f0640e96a22b4e99745ee73317e238dc639869691cc
|
|
| MD5 |
7bca35192ab5c30d3f43e37e74d0bf01
|
|
| BLAKE2b-256 |
b38c038a906a2fb247a62bd9041ef60fcf11484614dea5b0ef8b8ff533dd642d
|
File details
Details for the file timeback_caliper-0.1.4-py3-none-any.whl.
File metadata
- Download URL: timeback_caliper-0.1.4-py3-none-any.whl
- Upload date:
- Size: 24.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
669fcac40698016329b880e31b2e3bd399c34e783e76b3b792a3ef1e220b917d
|
|
| MD5 |
7deafc7fe37f32ccf56eb4eb9adb2562
|
|
| BLAKE2b-256 |
26095b8ac67ca2e7daa7932fe1bcc4199a03addd0f1fb25e4c64eccd764bccf1
|