Metadata-Version: 2.5
Name: lapviz
Version: 1.0.0
Summary: Official Python client of the LapViz API: lap timing sessions, telemetry, imports, webhooks and circuits.
Project-URL: Homepage, https://lapviz.com/developers
Project-URL: Documentation, https://lapviz.com/developers/docs
Project-URL: Reference, https://lapviz.com/swagger
Project-URL: Changelog, https://lapviz.com/developers/docs#changelog
Author-email: Mengal SRL <support@lapviz.com>
License-Expression: MIT
License-File: LICENSE
Keywords: api,karting,lap timing,lapviz,motorsport,telemetry
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# LapViz for Python

The official Python client of the [LapViz API](https://lapviz.com/developers): lap timing sessions, telemetry, file
imports, the change feed of a library, webhooks and circuits. Standard library only, Python 3.10+, MIT licensed.

```bash
pip install lapviz
```

## Quickstart

Create a personal API key in [Account › API keys](https://lapviz.com/Identity/Account/Manage/ApiKeys) and put it in
the `LAPVIZ_API_KEY` environment variable (never in your code).

```python
from lapviz import LapViz

lapviz = LapViz()  # reads LAPVIZ_API_KEY; or LapViz(api_key="lvz_...")
print(lapviz.me()["username"])

for session in lapviz.sessions.iterate(mine=True):
    print(session["shareId"], session["start"], session["best"])
```

Responses are the JSON of the API, as dicts with the camelCase names of the
[reference](https://lapviz.com/swagger): new fields appear without a new version of this package.

## Telemetry

```python
session = lapviz.sessions.get("7e2b5e")
speed = lapviz.sessions.channel("7e2b5e", lap=3, channel="GPS Speed")  # [{"s": seconds, "d": value}, ...]
everything = lapviz.sessions.telemetry("7e2b5e", lap=3)                 # laps and every channel
lapviz.sessions.export("7e2b5e", "csv", "session.csv")
lapviz.sessions.download("7e2b5e", "session.lvz")                       # LapViz format, every sample
```

Reading public sessions (like the demo sessions of the guides) works without a key; exports need one.

## Import a file

```python
job = lapviz.imports.upload("run.xrk")            # AiM, Alfano, Unipro, RaceBox, RaceChrono, MyChron...
status = lapviz.imports.wait(job["jobId"])        # polls until Success or Failed
print(status["state"], status.get("shareIds"))
```

## Keep a copy of a library

```python
changed, deleted, cursor = lapviz.sessions.sync(saved_cursor)  # None the first time: the whole library
save(cursor)
```

## Webhooks

```python
hook = lapviz.webhooks.create("https://example.com/lapviz", events=["session.created"])
secret = hook["secret"]  # shown once: store it
```

In your receiver, check the signature on the raw body before parsing it:

```python
from lapviz import verify_signature, SIGNATURE_HEADER

if not verify_signature(secret, request.headers.get(SIGNATURE_HEADER), request.get_data()):
    abort(400)
```

## Errors and limits

Errors raise `LapVizError` (with `status`, `title`, `detail` and the `problem` details), or one of its subclasses
`AuthenticationError` (401), `PermissionDeniedError` (403), `NotFoundError` (404) and `RateLimitError` (429, with
`retry_after`). The client waits and retries twice on 429 and 503; `lapviz.rate_limit` holds the RateLimit headers of
the last response.

## Anything else

Every operation of the reference is one call away:

```python
lapviz.request("PUT", f"api/teams/{key}/share", json_body={"share": True})
```

OAuth applications pass `LapViz(access_token="lvzat_...")` instead of a key. Guides:
[lapviz.com/developers/docs](https://lapviz.com/developers/docs).
