Metadata-Version: 2.4
Name: capyy
Version: 0.3.0
Summary: Tiny encrypted JSON-over-TCP APIs: call a function in another program, on your Wi-Fi or across the internet
Author: Izac
License-Expression: MIT
Project-URL: Homepage, https://libs.zazac.link/capy/
Project-URL: Documentation, https://libs.zazac.link/capy/
Keywords: rpc,api,tcp,json,tls,lan,discovery,relay,nat
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: OS Independent
Classifier: Natural Language :: French
Classifier: Topic :: Internet
Classifier: Topic :: System :: Networking
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# capyy — tiny encrypted JSON-over-TCP APIs

Call a function in another Python program — on the same machine, on your Wi-Fi, or across the internet —
with one line of code. Zero dependencies, Python 3.9+, encrypted with TLS by default.

```bash
pip install capyy
```

The package is published as **capyy**, but you import it as **`capy`**.
Error messages are in French (the library was written for French speakers), and the full documentation,
with examples, is at **[libs.zazac.link/capy](https://libs.zazac.link/capy/)**.

## Quick start

```python
# server.py
import capy

api = capy.Server(4000)

@api.action("hello")
def hello(name="you"):
    return {"message": f"Hello {name}!"}

api.run()
```

```python
# client.py
import capy

print(capy.call("localhost", 4000, "hello", name="Alice"))   # {'message': 'Hello Alice!'}
```

- An action returns a `dict`, or JSON written as text with `capy.json('{"text": "Hello"}')`.
- Errors raised on the server come back as `{"erreur": "..."}` (unknown action, bad parameters, exceptions).
- `capy.call` raises `ConnectionError` when the server does not answer.

## Reading a response

```python
reply = {"city": "Paris", "temp": "18.5", "days": [{"name": "monday"}, {"name": "tuesday"}]}

capy.get(reply, "days.1.name")          # "tuesday"  (paths go through dicts and lists)
capy.get(reply, "wind", default=0)      # 0
capy.to_float(reply, "temp")            # 18.5
capy.to_int("42"), capy.to_bool("yes")  # 42, True
```

`to_str`, `to_int`, `to_float`, `to_bool`, `to_list` and `to_dict` raise a `ValueError` that says exactly
what could not be converted.

## Encryption (TLS)

Everything is encrypted by default, with nothing to configure.

- Each machine running a server creates its own certificate on first launch (`~/.capy`, using `openssl`)
  and prints its **fingerprint**.
- Like SSH, a client **remembers a server's fingerprint** the first time (`~/.capy/known_hosts.json`)
  and raises `capy.SecurityError` if it ever changes.
- Use `tls=False` on **both** sides to talk in clear (faster on localhost).

## `capy.wifi` — find each other on the same network

```python
import capy.wifi

api = capy.wifi.Server("living-room")   # announces itself on the LAN, port chosen automatically
...
capy.wifi.call("living-room", "light", on=False)   # from any device on the same Wi-Fi
capy.wifi.scan()                                    # {'living-room': ('192.168.1.42', 51234)}
```

## `capy.network` — across the internet, through a relay

A machine behind a home router cannot be reached from the internet, so `capy.network` goes through a
**relay** running on a machine with a public IP (a VPS). Servers connect to it and register a name;
clients call that name. Everything is encrypted, and the connection is kept open between calls.

```bash
python3 -m capy.network 3879 my-secret-key      # on the VPS (open the port in its firewall)
```

```python
import capy.network

capy.network.use("my-vps.example:3879", key="my-secret-key")
capy.network.Server("home").run()        # at home, even behind a router
capy.network.call("home", "temperature") # from anywhere
```

## License

MIT
