Metadata-Version: 2.4
Name: lange-python
Version: 0.3.9
Summary: A bundeld set of tools, clients for the lange-suite of tools and more.
Author: contact@robertlange.me
Requires-Python: >=3.10
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: click (>=8.3.1,<9.0.0)
Requires-Dist: httpx (>=0.28.1,<0.29.0)
Requires-Dist: pydantic (>=2.12.5,<3.0.0)
Requires-Dist: websockets (>=12.0,<20.0)
Description-Content-Type: text/markdown

# lange-python

Python helpers and clients for Lange services.

## Distribution CLI

Publish a distribution artifact to the app services distribution system:

```bash
export LANGE_LABS_API_KEY="your-api-key"
lange distribution publish \
  --path ./dist/app.dmg \
  --version 1.2.3 \
  --distribution-name desktop-app \
  --os macos
```

Apply a macOS app update after downloading the published zip artifact:

```python
from pathlib import Path

from lange.distribution import DistributionClient

client = DistributionClient(distribution_name="desktop-app", api_key="your-api-key")

update_metadata = client.update(
    current_version="1.2.3",
    installed_app_path=Path("/Applications/Desktop App.app"),
)

print(update_metadata["version"])
# The caller should now shut down so the detached helper can replace the app bundle.
```

The distribution client also exposes `status` and `reload()` for refresh-aware integrations:

```python
client = DistributionClient(distribution_name="desktop-app", api_key="your-api-key")

latest_version = client.search_for_update("1.2.3")
print(client.status)  # connected

client.reload()  # repeats the last update check
client.reload(api_key=None)  # clears authentication and marks the client unauthenticated
```

## Tunnel worker

```python
from lange.tunnel import Tunnel

tunnel = Tunnel(
    host="wss://tunnel.lange-labs.com",
    api_key="your-bearer-token",
    target="http://localhost:3000",
)

tunnel.start()
# ...
tunnel.reload()  # restarts the connection flow with the current API key
tunnel.reload(api_key=None)  # clears authentication and leaves the client unauthenticated
tunnel.stop()
```

Tunnel clients also expose a `status` property with one of:
`"unauthenticated"`, `"off"`, `"pending"`, `"connected"`, or `"failed"`.

