Metadata-Version: 2.4
Name: capyy
Version: 0.5.1
Summary: Easy, encrypted networking for Python: programs that talk (local, Wi-Fi, internet), home automation, and projects run with cy
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 — easy, encrypted networking for Python

Make Python programs talk to each other — on the same machine, on your Wi-Fi, or across the internet —
control your smart lights and plugs, and run your projects with one command (`cy`).
Zero dependencies, Python 3.9+, encrypted with TLS by default.

At its core: a **server** exposes *actions* (Python functions) and **clients** call them by name, with one line of code.
Everything else (Wi-Fi discovery, internet relay, home automation, project files) is built on top of that.

```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.

## Project file: capy.config.json

Describe the whole project once, then never repeat ports or hosts:

```bash
python3 -m capy new my-game     # folder + capy.config.json + server.py + client.py
cd my-game
cy run             # starts the server, runs the client, stops the server
```

```json
{"name": "my-game", "version": "1.0", "mode": "local", "url": "127.0.0.1:2388", "tls": true,
 "files": {"server": "server.py", "client": "client.py"}}
```

```python
app = capy.project()            # finds capy.config.json next to the script, or in a parent folder
server = app.server()           # server side
app.call("hello", nom="Izac")   # client side
```

`mode` can be `local`, `wifi` or `network` (with `relay`, `key`, `fingerprint`). Strings starting with `$` are read
from environment variables, e.g. `"key": "$CAPY_KEY"`. Inside a project, the `cy` command runs its `scripts` like `npm run` (`cy test`, `cy start`) and its files (`cy server`); create a project with `python3 -m capy new`.

## 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.
- The server logs every request, but **never secrets**: parameters whose name contains
  `password`, `pwd`, `mdp`, `secret` or `token` are shown as `"***"`.
- 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
```

## `capy.domo` — home automation

One way to drive lights and plugs from Philips Hue, WiZ, Shelly, Yeelight and Home Assistant (and everything
Home Assistant supports), on your local network, with zero dependencies:

```python
import capy.domo

home = capy.domo.Home()        # devices, groups and scenes live in capy.domo.json
home.scan()                    # find devices on the network
home["salon"].color("orange")  # a device, a group, or "tout" (everything)
home.scene("film")
capy.domo.serve(home)          # control it remotely through capy / capy.wifi / capy.network
```

```bash
python3 -m capy.domo scan
python3 -m capy.domo pair hue
python3 -m capy.domo salon on 30% orange
```

## License

MIT
