# wraplib

A complete wrapper around `tinylib`, a fictional C library with the three
features that make wrapping interesting: an opaque handle with an explicit
close, integer error codes, and a callback.

```bash
python -m pip install -e . --no-build-isolation -v
python -m pytest -q
```

```python
import wraplib

with wraplib.Conn("session") as c:
    c.callback = print
    c.push(5)
    c.push(7)
    print(c.total)     # 12
```

## What to look for in `wraplib.c`

| Pattern | Where |
|---|---|
| One error-translation point | `check_rc` |
| Handle validity check in every method | `get_handle` |
| Idempotent close, `__enter__`/`__exit__` | `conn_do_close`, `Conn_enter`, `Conn_exit` |
| `ResourceWarning` backstop | `Conn_finalize` |
| Callback trampoline from a foreign thread | `conn_trampoline` |
| Module state reached from a slot function | `state_of` via `PyType_GetModuleByDef` |
| Capsule with a checked name | `Conn_capsule` |

## Things to try

1. Delete the `get_handle` check from `Conn_push` and call `push` after `close`.
2. Remove `Py_VISIT(self->callback)` from `Conn_traverse`, then run
   `test_callback_cycle_is_collected`.
3. Remove the `Py_XNewRef(self->callback)` in the trampoline and reason about
   what a concurrent `c.callback = None` could now do.
4. Move `conn_do_close` from `Conn_finalize` into `Conn_clear` and explain why
   that is wrong.
