Metadata-Version: 2.3
Name: timingapp
Version: 0.2.0
Summary: Python client for the Timing macOS app SQLite database
Requires-Dist: sqlalchemy>=2.0
Requires-Dist: pytest>=8.0 ; extra == 'dev'
Requires-Dist: pytest-cov>=5.0 ; extra == 'dev'
Requires-Dist: mypy>=1.10 ; extra == 'dev'
Requires-Dist: sqlalchemy[mypy]>=2.0 ; extra == 'dev'
Requires-Python: >=3.12
Provides-Extra: dev
Description-Content-Type: text/markdown

# timingapp-python

Python client for the [Timing](https://timingapp.com) macOS app SQLite database.

Provides read-only access to Timing's SQLite database (`~/Library/Application Support/info.eurocomp.Timing2/SQLite.db`) via SQLAlchemy 2.x ORM.

> **Credit:** This is a Python port of [timingapp-ruby](https://github.com/marcoroth/timingapp-ruby) by [@marcoroth](https://github.com/marcoroth). The Ruby gem provides the same read-only database access via ActiveRecord; this library reimplements it idiomatically in Python using SQLAlchemy 2.x.

> **Note:** This library was mostly generated by [Claude Sonnet 4.6](https://www.anthropic.com/claude).

## Requirements

- Python 3.12+
- SQLAlchemy 2.0+
- macOS with Timing app installed (for real usage)

## Installation

```bash
pip install timingapp
```

## Usage

```python
from timingapp import open_database, AppActivity, Project, TaskActivity
from sqlalchemy import select

# Open the default Timing database (read-only)
db = open_database()

with db.session() as sess:
    # Query all projects
    projects = sess.scalars(select(Project)).all()
    for p in projects:
        print(p.title)

    # Get archived projects
    archived = sess.scalars(Project.archived()).all()

    # Get running task activities
    running = sess.scalars(TaskActivity.running()).all()

    # Get deleted app activities
    deleted = sess.scalars(AppActivity.deleted()).all()

    # Access relationships
    activity = sess.get(AppActivity, 1)
    if activity:
        print(activity.application.name)
        print(activity.project.title)
        print(activity.startDate)  # UTC datetime
```

## Models

| Model | Table | Notes |
|-------|-------|-------|
| `AppActivity` | `AppActivity` | Scopes: `deleted()` |
| `AppActivityWithStrings` | `AppActivityWithStrings` | SQLite VIEW |
| `Application` | `Application` | |
| `Device` | `Device` | PK: `localID` |
| `Event` | `Event` | |
| `EventSource` | `EventSource` | Scopes: `templates()`, `favorites()` |
| `EventSourceTaskActivity` | `EventSourceTaskActivity` | Scopes: `deleted()` |
| `Filter` | `Filter` | Scopes: `samples()`, self-referential |
| `Integration` | `Integration` | |
| `IntegrationLogResult` | `integration_log_result` | |
| `IntegrationProject` | `IntegrationProject` | |
| `Path` | `Path` | |
| `Project` | `Project` | Scopes: `archived()`, self-referential |
| `TaskActivity` | `TaskActivity` | Scopes: `running()`, `deleted()` |
| `Title` | `Title` | |

## Export Script

The `timing-export` CLI script exports app activity for a given day as newline-delimited JSON (one JSON object per line) to stdout.

```bash
# Export today's activity
timing-export

# Export a specific date
timing-export 2026-03-15
```

Each line is a JSON object with the following fields:

| Field | Type | Description |
|-------|------|-------------|
| `startDate` | ISO 8601 string or null | Activity start time (UTC) |
| `endDate` | ISO 8601 string or null | Activity end time (UTC) |
| `appName` | string or null | Application name |
| `windowTitle` | string or null | Window/document title |
| `path` | string or null | File path of the active document |
| `device` | string or null | Device display name |

Example output:

```json
{"startDate": "2026-03-15T09:00:00+00:00", "endDate": "2026-03-15T09:12:34+00:00", "appName": "Code", "windowTitle": "README.md — timingapp-python", "path": "/Users/steven/tmp/timing/timingapp-python/README.md", "device": "My Mac"}
{"startDate": "2026-03-15T09:12:35+00:00", "endDate": "2026-03-15T09:45:00+00:00", "appName": "Safari", "windowTitle": "SQLAlchemy 2.0 Documentation", "path": null, "device": "My Mac"}
```

## Development

```bash
# Install dev dependencies
uv sync --extra dev

# Run tests
uv run pytest

# Type check
uv run mypy src/
```
