Implement Phase 9: client libraries (Go, Rust, Lisp, Python)
- clients/README.md: canonical API surface and error type reference - clients/testdata/: shared JSON response fixtures - clients/go/: mciasgoclient package; net/http + TLS 1.2+; sync.RWMutex token state; DisallowUnknownFields on all decoders; 25 tests pass - clients/rust/: async mcias-client crate; reqwest+rustls (no OpenSSL); thiserror MciasError enum; Arc<RwLock> token state; 22+1 tests pass; cargo clippy -D warnings clean - clients/lisp/: ASDF mcias-client; dexador HTTP, yason JSON; mcias-error condition hierarchy; Hunchentoot mock-dispatcher; 37 fiveam checks pass on SBCL 2.6.1; yason boolean normalisation in validate-token - clients/python/: mcias_client package (Python 3.11+); httpx sync; py.typed; dataclasses; 32 pytest tests; mypy --strict + ruff clean - test/mock/mockserver.go: in-memory mock server for Go client tests - ARCHITECTURE.md §19: updated per-language notes to match implementation - PROGRESS.md: Phase 9 marked complete - .gitignore: exclude clients/rust/target/, python .venv, .pytest_cache, .fasl files Security: token never logged or exposed in error messages in any library; TLS enforced in all four languages; token stored under lock/mutex/RwLock
This commit is contained in:
91
clients/python/README.md
Normal file
91
clients/python/README.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# mcias-client (Python)
|
||||
|
||||
Python client library for the [MCIAS](../../README.md) identity and access management API.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.11+
|
||||
- `httpx >= 0.27`
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
pip install .
|
||||
# or in development mode:
|
||||
pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from mcias_client import Client
|
||||
|
||||
# Connect to the MCIAS server.
|
||||
with Client("https://auth.example.com") as client:
|
||||
# Authenticate.
|
||||
token, expires_at = client.login("alice", "s3cret")
|
||||
print(f"token expires at {expires_at}")
|
||||
|
||||
# The token is stored in the client automatically.
|
||||
accounts = client.list_accounts()
|
||||
|
||||
# Revoke the token when done (also called automatically on context exit).
|
||||
client.logout()
|
||||
```
|
||||
|
||||
## Custom CA Certificate
|
||||
|
||||
```python
|
||||
client = Client(
|
||||
"https://auth.example.com",
|
||||
ca_cert_path="/etc/mcias/ca.pem",
|
||||
)
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
All methods raise typed exceptions on error:
|
||||
|
||||
```python
|
||||
from mcias_client import (
|
||||
MciasAuthError,
|
||||
MciasForbiddenError,
|
||||
MciasNotFoundError,
|
||||
MciasInputError,
|
||||
MciasConflictError,
|
||||
MciasServerError,
|
||||
)
|
||||
|
||||
try:
|
||||
client.login("alice", "wrongpass")
|
||||
except MciasAuthError as e:
|
||||
print(f"auth failed ({e.status_code}): {e.message}")
|
||||
except MciasForbiddenError as e:
|
||||
print(f"forbidden: {e.message}")
|
||||
except MciasNotFoundError as e:
|
||||
print(f"not found: {e.message}")
|
||||
except MciasInputError as e:
|
||||
print(f"bad input: {e.message}")
|
||||
except MciasConflictError as e:
|
||||
print(f"conflict: {e.message}")
|
||||
except MciasServerError as e:
|
||||
print(f"server error {e.status_code}: {e.message}")
|
||||
```
|
||||
|
||||
All exception types are subclasses of `MciasError`, which has attributes:
|
||||
- `status_code: int` — HTTP status code
|
||||
- `message: str` — server error message
|
||||
|
||||
## Thread Safety
|
||||
|
||||
`Client` is **not** thread-safe. Each thread should use its own `Client`
|
||||
instance.
|
||||
|
||||
## Running Tests
|
||||
|
||||
```sh
|
||||
pip install -e ".[dev]"
|
||||
pytest tests/ -q
|
||||
mypy mcias_client/ tests/
|
||||
ruff check mcias_client/ tests/
|
||||
```
|
||||
Reference in New Issue
Block a user