Metadata-Version: 2.4
Name: dsa-tracker
Version: 0.7.1
Summary: Log DSA prep solves from a Colab/Jupyter notebook to your DSA Tracker instance.
Project-URL: Homepage, https://github.com/yourusername/dsa-tracker
Project-URL: Issues, https://github.com/yourusername/dsa-tracker/issues
Author-email: DSA Tracker <noreply@example.com>
License: MIT
Keywords: colab,dsa,interview-prep,leetcode,spaced-repetition
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Education
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.9
Requires-Dist: httpx>=0.27
Description-Content-Type: text/markdown

# dsa-tracker

Tiny Python client for [DSA Tracker](https://github.com/yourusername/dsa-tracker). Log a solve from a Colab/Jupyter notebook in one call — same SM-2 scheduling and GitHub auto-push you get from the web app.

## Install

```bash
pip install dsa-tracker
```

## Get an API key

In your DSA Tracker dashboard → **Settings → API keys → Generate new key**. The plaintext value is shown exactly once — copy it and treat it like a password. You can name keys per device/notebook so revoking one doesn't break the others.

## Use it

```python
from dsa_tracker import Tracker

tracker = Tracker(
    api_url="https://your-dsa-tracker.com",
    api_key="dsa_xxxxxxxxxxxxxxxxxxxxxx",
)

# Solve the problem like you always do
def two_sum(nums, target):
    seen = {}
    for i, n in enumerate(nums):
        if target - n in seen:
            return [seen[target - n], i]
        seen[n] = i

# Log it without leaving the notebook
import inspect

result = tracker.log(
    title="Two Sum",
    confidence=4,                            # 1 (Forgot) → 5 (Easy)
    code=inspect.getsource(two_sum),
    language="python",
    difficulty="easy",
    topics=["Array", "HashMap"],
    pattern="Hash Lookup",
    time_complexity="O(n)",
    space_complexity="O(n)",
    playlist="leetcode-75",                  # optional: push to this playlist's GitHub config
)

print(f"→ next review: {result['next_review_at']} · status: {result['status']}")
if result.get('git_push_queued'):
    print("→ pushed to GitHub via playlist 'leetcode-75'")
elif result.get('git_push_skip_reason'):
    print(f"→ no GitHub push: {result['git_push_skip_reason']}")
```

## What happens on the server

1. `Two Sum` is looked up by slug. Created if new, otherwise reused.
2. A new `Solution` row captures your code, language, complexities.
3. A new `Review` row runs through SM-2 with your confidence rating.
4. `problem.next_review_at` and `problem.status` are updated.
5. If you have GitHub auto-push enabled, the solution is committed to your repo in the background.

The return value tells you exactly what happened:

```python
{
    'problem_id': 42,
    'solution_id': 87,
    'review_id': 105,
    'created': True,                # False if you've logged this title before
    'next_review_at': '2026-05-27',
    'status': 'learning',
    'reps': 1,
    'interval_days': 1,
}
```

## All parameters

| Required | Optional |
|---|---|
| `title`, `confidence` | `code`, `language`, `difficulty`, `topics`, `pattern`, `platform`, `problem_url`, `approach`, `time_complexity`, `space_complexity`, `notes` |

Defaults: `language="python"`, `difficulty="medium"`, `approach="optimal"`. Anything you omit just isn't sent.

## Errors

The client raises `TrackerError` on any non-2xx response with the server's reason attached:

```python
from dsa_tracker import TrackerError

try:
    tracker.log(title="X", confidence=4)
except TrackerError as e:
    print(f"Couldn't log: {e}")
```

Common cases: `401` (bad/revoked API key), `422` (missing required field), connection timeout.

## Context manager

For scripts that make many calls, use it as a context manager to clean up the underlying connection pool:

```python
with Tracker(api_url=..., api_key=...) as tracker:
    for problem in queue:
        tracker.log(title=problem.name, confidence=problem.rating, code=problem.code)
```

## License

MIT.
