# Quickstart

> SmashTable for Python

```bash
pip install smashtable
```

The wheel ships type stubs, so an editor completes the container methods and a checker rejects a misspelled isolation level or key layout before the call ever runs.

Two indexes over the same entities have to move together, or a lookup by name finds an identifier that no longer resolves:

```python
import smashtable as st

by_id = st.SortedMap(key=int)     # entity id → record
by_name = st.SortedMap(key=str)   # name      → entity id

with st.transaction(by_id, by_name) as (ids, names):
    ids[42] = "carol"
    names["carol"] = 42
# both indexes have changed
```

Each container is a mapping in its own right, so the usual vocabulary works:

```python
list(by_id)                  # [42]           — keys, in order
dict(by_name)                # {'carol': 42}
by_id.items()                # a lazy view, not a copy
by_id.scan(0, 100)           # the half-open window [0, 100)
```

If the block raises, nothing was applied:

```python
try:
    with st.transaction(by_id, by_name) as (ids, names):
        ids[43] = "dave"
        names["dave"] = 43
        raise ValueError("failed validation")
except ValueError:
    pass

assert 43 not in by_id and "dave" not in by_name
```

Without this, the alternative is an O(n) defensive copy that every alias to the container can still read through mid-update:

```python
backup = dict(cache)                      # copies the whole thing
try:
    for key, value in updates.items():
        cache[key] = transform(value)     # raises on item 40 of 100
except Exception:
    cache.clear(); cache.update(backup)   # O(n) again, and readers already saw the torn state
```

`import smashtable`

## SmashTableError

Base of every refusal this module raises, so one `except` catches the family.

```python
class SmashTableError(Exception)
```

Also raised on its own for a failure no caller can act on, such as a staged version
missing when a transaction unwound. Retrying one of those cannot help.

