python-etcd3-async 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_etcd3_async-0.1.0/.coverage +0 -0
- python_etcd3_async-0.1.0/.gitignore +17 -0
- python_etcd3_async-0.1.0/.pylintrc +29 -0
- python_etcd3_async-0.1.0/.python-version +1 -0
- python_etcd3_async-0.1.0/AGENTS.md +138 -0
- python_etcd3_async-0.1.0/CLAUDE.md +257 -0
- python_etcd3_async-0.1.0/PKG-INFO +328 -0
- python_etcd3_async-0.1.0/README.md +318 -0
- python_etcd3_async-0.1.0/README_CN.md +318 -0
- python_etcd3_async-0.1.0/SKILL.md +105 -0
- python_etcd3_async-0.1.0/docs/assets/stylesheets/extra.css +53 -0
- python_etcd3_async-0.1.0/docs/en/getting-started/installation.md +35 -0
- python_etcd3_async-0.1.0/docs/en/guide/advanced_queries.md +43 -0
- python_etcd3_async-0.1.0/docs/en/guide/configuration.md +88 -0
- python_etcd3_async-0.1.0/docs/en/guide/usage.md +142 -0
- python_etcd3_async-0.1.0/docs/en/index.md +69 -0
- python_etcd3_async-0.1.0/docs/en/operations/async_error_handling.md +468 -0
- python_etcd3_async-0.1.0/docs/en/operations/auto_reconnection.md +34 -0
- python_etcd3_async-0.1.0/docs/en/operations/error_handling.md +37 -0
- python_etcd3_async-0.1.0/docs/en/operations/failover.md +54 -0
- python_etcd3_async-0.1.0/docs/en/operations/monitoring.md +67 -0
- python_etcd3_async-0.1.0/docs/en/operations/observability.md +225 -0
- python_etcd3_async-0.1.0/docs/en/resources/authors.md +13 -0
- python_etcd3_async-0.1.0/docs/en/resources/contributing.md +38 -0
- python_etcd3_async-0.1.0/docs/en/resources/history.md +18 -0
- python_etcd3_async-0.1.0/docs/zh/getting-started/installation.md +35 -0
- python_etcd3_async-0.1.0/docs/zh/guide/advanced_queries.md +43 -0
- python_etcd3_async-0.1.0/docs/zh/guide/configuration.md +88 -0
- python_etcd3_async-0.1.0/docs/zh/guide/usage.md +142 -0
- python_etcd3_async-0.1.0/docs/zh/index.md +69 -0
- python_etcd3_async-0.1.0/docs/zh/operations/async_error_handling.md +458 -0
- python_etcd3_async-0.1.0/docs/zh/operations/auto_reconnection.md +34 -0
- python_etcd3_async-0.1.0/docs/zh/operations/error_handling.md +37 -0
- python_etcd3_async-0.1.0/docs/zh/operations/failover.md +54 -0
- python_etcd3_async-0.1.0/docs/zh/operations/monitoring.md +67 -0
- python_etcd3_async-0.1.0/docs/zh/operations/observability.md +225 -0
- python_etcd3_async-0.1.0/docs/zh/resources/authors.md +13 -0
- python_etcd3_async-0.1.0/docs/zh/resources/contributing.md +38 -0
- python_etcd3_async-0.1.0/docs/zh/resources/history.md +18 -0
- python_etcd3_async-0.1.0/etcd3/__init__.py +90 -0
- python_etcd3_async-0.1.0/etcd3/async_client.py +1495 -0
- python_etcd3_async-0.1.0/etcd3/async_client_extensions.py +878 -0
- python_etcd3_async-0.1.0/etcd3/async_endpoint.py +140 -0
- python_etcd3_async-0.1.0/etcd3/async_managers.py +498 -0
- python_etcd3_async-0.1.0/etcd3/async_monitor.py +16 -0
- python_etcd3_async-0.1.0/etcd3/async_watch.py +462 -0
- python_etcd3_async-0.1.0/etcd3/client.py +2021 -0
- python_etcd3_async-0.1.0/etcd3/endpoint.py +79 -0
- python_etcd3_async-0.1.0/etcd3/events.py +40 -0
- python_etcd3_async-0.1.0/etcd3/exceptions.py +47 -0
- python_etcd3_async-0.1.0/etcd3/exporters/__init__.py +18 -0
- python_etcd3_async-0.1.0/etcd3/exporters/prometheus.py +365 -0
- python_etcd3_async-0.1.0/etcd3/leases.py +106 -0
- python_etcd3_async-0.1.0/etcd3/locks.py +593 -0
- python_etcd3_async-0.1.0/etcd3/log.py +146 -0
- python_etcd3_async-0.1.0/etcd3/log_formatters.py +228 -0
- python_etcd3_async-0.1.0/etcd3/log_sampling.py +221 -0
- python_etcd3_async-0.1.0/etcd3/members.py +44 -0
- python_etcd3_async-0.1.0/etcd3/observability.py +431 -0
- python_etcd3_async-0.1.0/etcd3/shared.py +486 -0
- python_etcd3_async-0.1.0/etcd3/trace.py +231 -0
- python_etcd3_async-0.1.0/etcd3/trace_attributes.py +434 -0
- python_etcd3_async-0.1.0/etcd3/transactions.py +280 -0
- python_etcd3_async-0.1.0/etcd3/utils.py +158 -0
- python_etcd3_async-0.1.0/etcd3/watch.py +270 -0
- python_etcd3_async-0.1.0/etcdrpc/__init__.py +16 -0
- python_etcd3_async-0.1.0/etcdrpc/auth.proto +49 -0
- python_etcd3_async-0.1.0/etcdrpc/kv.proto +43 -0
- python_etcd3_async-0.1.0/etcdrpc/rpc.proto +924 -0
- python_etcd3_async-0.1.0/examples/leader_election.py +285 -0
- python_etcd3_async-0.1.0/examples/leader_election_sync.py +300 -0
- python_etcd3_async-0.1.0/examples/service_discovery.py +204 -0
- python_etcd3_async-0.1.0/examples/service_discovery_sync.py +229 -0
- python_etcd3_async-0.1.0/examples/service_registration.py +226 -0
- python_etcd3_async-0.1.0/examples/service_registration_sync.py +195 -0
- python_etcd3_async-0.1.0/gen_protos.py +69 -0
- python_etcd3_async-0.1.0/mkdocs.yml +95 -0
- python_etcd3_async-0.1.0/pyproject.toml +50 -0
- python_etcd3_async-0.1.0/tests/__init__.py +0 -0
- python_etcd3_async-0.1.0/tests/test_async_client.py +394 -0
- python_etcd3_async-0.1.0/tests/test_async_error_handling.py +208 -0
- python_etcd3_async-0.1.0/tests/test_async_managers.py +88 -0
- python_etcd3_async-0.1.0/tests/test_batch_operations.py +466 -0
- python_etcd3_async-0.1.0/tests/test_client.py +117 -0
- python_etcd3_async-0.1.0/tests/test_events.py +252 -0
- python_etcd3_async-0.1.0/tests/test_kv_operations.py +523 -0
- python_etcd3_async-0.1.0/tests/test_lease_keepalive_retry.py +434 -0
- python_etcd3_async-0.1.0/tests/test_leases.py +242 -0
- python_etcd3_async-0.1.0/tests/test_leases_integration.py +229 -0
- python_etcd3_async-0.1.0/tests/test_locks.py +356 -0
- python_etcd3_async-0.1.0/tests/test_locks_integration.py +147 -0
- python_etcd3_async-0.1.0/tests/test_log_formatters.py +234 -0
- python_etcd3_async-0.1.0/tests/test_log_sampling.py +180 -0
- python_etcd3_async-0.1.0/tests/test_members.py +200 -0
- python_etcd3_async-0.1.0/tests/test_observability_integration.py +205 -0
- python_etcd3_async-0.1.0/tests/test_trace_attributes.py +311 -0
- python_etcd3_async-0.1.0/tests/test_transactions.py +240 -0
- python_etcd3_async-0.1.0/tests/test_transactions_integration.py +320 -0
- python_etcd3_async-0.1.0/tests/test_utils.py +280 -0
- python_etcd3_async-0.1.0/tests/test_watch.py +142 -0
- python_etcd3_async-0.1.0/usage_guide.md +223 -0
- python_etcd3_async-0.1.0/uv.lock +911 -0
|
Binary file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
etcdrpc/*_pb2.py
|
|
9
|
+
etcdrpc/*_pb2_grpc.py
|
|
10
|
+
etcdrpc/*_pb2.pyi
|
|
11
|
+
.trae/documents/*
|
|
12
|
+
.pytest_cache/
|
|
13
|
+
.ruff_cache/
|
|
14
|
+
htmlcov/
|
|
15
|
+
# Virtual environments
|
|
16
|
+
.venv
|
|
17
|
+
/site
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Pylint configuration file
|
|
2
|
+
|
|
3
|
+
[MASTER]
|
|
4
|
+
|
|
5
|
+
# Specify a score threshold to be exceeded before program exits with error.
|
|
6
|
+
score=no
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
[MESSAGES CONTROL]
|
|
10
|
+
|
|
11
|
+
# Disable specific messages
|
|
12
|
+
#disable=all
|
|
13
|
+
#enable=unused-import,unused-variable
|
|
14
|
+
; disable=C0302,R0902,R0913,R0917,C0116,W0212,R0914,R0904,R0903,E0202,W0718
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
[BASIC]
|
|
18
|
+
|
|
19
|
+
# Maximum line length.
|
|
20
|
+
max-line-length=100
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
[TYPECHECK]
|
|
24
|
+
|
|
25
|
+
# List of module names for which member attributes should not be checked
|
|
26
|
+
# (useful for modules/projects where namespaces are manipulated during runtime
|
|
27
|
+
# and thus existing member attributes cannot be deduced by static analysis).
|
|
28
|
+
# It supports qualified module names, as well as Unix pattern matching.
|
|
29
|
+
ignored-modules=etcdrpc
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# AGENTS.md - python-etcd3-async
|
|
2
|
+
|
|
3
|
+
AI coding agent guidelines for the python-etcd3-async project.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
- **Name**: python-etcd3-async
|
|
7
|
+
- **Python**: 3.12+
|
|
8
|
+
- **Package Manager**: uv
|
|
9
|
+
- **License**: Apache 2.0
|
|
10
|
+
|
|
11
|
+
## Build & Development Commands
|
|
12
|
+
|
|
13
|
+
### Setup
|
|
14
|
+
```bash
|
|
15
|
+
uv sync # Install dependencies
|
|
16
|
+
uv sync --extra dev # Install with dev dependencies
|
|
17
|
+
uv pip install -e . # Editable install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Testing (requires ETCD_ENDPOINT)
|
|
21
|
+
```bash
|
|
22
|
+
ETCD_ENDPOINT=192.168.31.15:12379 uv run pytest
|
|
23
|
+
ETCD_ENDPOINT=192.168.31.15:12379 uv run pytest tests/test_async_client.py::TestAsyncClient::test_client_init -v
|
|
24
|
+
ETCD_ENDPOINT=192.168.31.15:12379 uv run pytest --cov=etcd3 --cov=etcdrpc
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Linting
|
|
28
|
+
```bash
|
|
29
|
+
uv run ruff check etcd3/ etcdrpc/ # Check
|
|
30
|
+
uv run ruff format etcd3/ etcdrpc/ # Format
|
|
31
|
+
pylint etcd3/ # Static/ etcdrpc analysis
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Other
|
|
35
|
+
```bash
|
|
36
|
+
uv run python gen_protos.py # Regenerate protobuf
|
|
37
|
+
uv run mkdocs serve # Serve docs
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Code Style
|
|
41
|
+
|
|
42
|
+
### Formatting
|
|
43
|
+
- **Max line length**: 100 characters
|
|
44
|
+
- **Formatter**: ruff
|
|
45
|
+
- Follow PEP 8
|
|
46
|
+
|
|
47
|
+
### Naming
|
|
48
|
+
- Classes: `PascalCase` (e.g., `AsyncEtcd3Client`)
|
|
49
|
+
- Functions/Methods: `snake_case` (e.g., `async_client()`, `get_prefix()`)
|
|
50
|
+
- Constants: `UPPER_CASE` (e.g., `FILTER_PUT`)
|
|
51
|
+
- Private: `_leading_underscore` (e.g., `_get_channel()`)
|
|
52
|
+
|
|
53
|
+
### Imports (3 groups, sorted)
|
|
54
|
+
1. Standard library
|
|
55
|
+
2. Third-party (grpc, etcdrpc, pytest)
|
|
56
|
+
3. Internal modules
|
|
57
|
+
|
|
58
|
+
### Type Hints
|
|
59
|
+
- Use type hints for all parameters and returns
|
|
60
|
+
- Use `Optional[]` for nullable types, `Literal[]` for enums
|
|
61
|
+
|
|
62
|
+
### Docstrings
|
|
63
|
+
- Google-style
|
|
64
|
+
- Document all public methods/classes
|
|
65
|
+
- Include type info
|
|
66
|
+
|
|
67
|
+
### Error Handling
|
|
68
|
+
- Use custom exceptions from `etcd3/exceptions.py`:
|
|
69
|
+
- `Etcd3Exception` (base), `ConnectionFailedError`, `ConnectionTimeoutError`
|
|
70
|
+
- `RevisionCompactedError`, `LockReleaseError`, `BatchOperationError`
|
|
71
|
+
- Decorators: `_handle_errors`, `_async_handle_errors`
|
|
72
|
+
|
|
73
|
+
## Architecture
|
|
74
|
+
|
|
75
|
+
### Dual Client Design
|
|
76
|
+
- **Sync**: `Etcd3Client`, `MultiEndpointEtcd3Client` in `etcd3/client.py`
|
|
77
|
+
- **Async**: `AsyncEtcd3Client`, `AsyncMultiEndpointEtcd3Client` in `etcd3/async_client.py`
|
|
78
|
+
- Factory: `async_client()` function
|
|
79
|
+
|
|
80
|
+
### Extension Pattern (`etcd3/async_client_extensions.py`)
|
|
81
|
+
- `AsyncKVOperations`, `AsyncLeaseOperations`, `AsyncLockOperations`
|
|
82
|
+
- `AsyncClusterOperations`, `AsyncMaintenanceOperations`, `AsyncWatchOperations`
|
|
83
|
+
|
|
84
|
+
### Load Balancing
|
|
85
|
+
- `LoadBalancerStrategy` enum: `PRIORITY`, `ROUND_ROBIN`, `RANDOM`, `STICKY`
|
|
86
|
+
|
|
87
|
+
## Observability (Environment Variables)
|
|
88
|
+
|
|
89
|
+
All prefixed with `ETCD_OBS_`:
|
|
90
|
+
|
|
91
|
+
| Variable | Default | Description |
|
|
92
|
+
|----------|---------|-------------|
|
|
93
|
+
| `ETCD_OBS_AUTO_INIT` | true | Auto-init on client create |
|
|
94
|
+
| `ETCD_OBS_LOG_LEVEL` | INFO | DEBUG/INFO/WARNING/ERROR |
|
|
95
|
+
| `ETCD_OBS_LOG_FORMAT` | text | text/json/colored |
|
|
96
|
+
| `ETCD_OBS_LOG_SAMPLE_RATE` | 1.0 | 0.0-1.0 |
|
|
97
|
+
| `ETCD_OBS_LOG_SAMPLE_STRATEGY` | always | always/rate/dynamic/level_based |
|
|
98
|
+
| `ETCD_OBS_TRACING_ENABLED` | true | Enable OpenTelemetry |
|
|
99
|
+
| `ETCD_OBS_TRACING_SERVICE_NAME` | etcd3-client | Service name |
|
|
100
|
+
| `ETCD_OBS_TRACING_SAMPLE_RATE` | 1.0 | Trace sampling |
|
|
101
|
+
| `ETCD_OBS_OTLP_ENDPOINT` | - | OTLP collector endpoint |
|
|
102
|
+
| `ETCD_OBS_PROMETHEUS_ENABLED` | false | Enable Prometheus |
|
|
103
|
+
|
|
104
|
+
## Testing
|
|
105
|
+
- Tests require `ETCD_ENDPOINT` env var
|
|
106
|
+
- Unit tests: no etcd needed
|
|
107
|
+
- Integration tests: require running etcd server
|
|
108
|
+
- Test files: `tests/test_*.py`
|
|
109
|
+
|
|
110
|
+
## Common Patterns
|
|
111
|
+
```python
|
|
112
|
+
# Async client (auto-initializes observability)
|
|
113
|
+
from etcd3 import async_client
|
|
114
|
+
etcd = await async_client(host='localhost', port=2379)
|
|
115
|
+
|
|
116
|
+
# Sync client
|
|
117
|
+
from etcd3 import client
|
|
118
|
+
etcd = client(host='localhost', port=2379)
|
|
119
|
+
|
|
120
|
+
# Manual observability config
|
|
121
|
+
from etcd3 import ObservabilityConfig, configure_from_env
|
|
122
|
+
config = configure_from_env()
|
|
123
|
+
config.apply()
|
|
124
|
+
|
|
125
|
+
# Context tracking
|
|
126
|
+
from etcd3 import get_request_context
|
|
127
|
+
async with etcd.context(operation="batch_put", source="worker_1"):
|
|
128
|
+
await etcd.kv.batch_put(items)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Security
|
|
132
|
+
- TLS, username/password, token-based auth supported
|
|
133
|
+
- Never commit credentials
|
|
134
|
+
|
|
135
|
+
## References
|
|
136
|
+
- [python-etcd3](https://github.com/kragniz/python-etcd3)
|
|
137
|
+
- [Go etcd client v3](https://pkg.go.dev/go.etcd.io/etcd/client/v3)
|
|
138
|
+
- [etcd docs](https://etcd.io/docs/)
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
python-etcd3-async is an async Python client library for the etcd v3 API using `grpc.aio`. It provides both synchronous and asynchronous clients with full support for etcd operations including key-value operations, leases, locks, watches, transactions, and cluster management.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
### Development Setup
|
|
12
|
+
```bash
|
|
13
|
+
# Install dependencies
|
|
14
|
+
uv sync
|
|
15
|
+
|
|
16
|
+
# Install dev dependencies
|
|
17
|
+
uv sync --extra dev
|
|
18
|
+
|
|
19
|
+
# Run Python commands
|
|
20
|
+
uv run python <script.py>
|
|
21
|
+
|
|
22
|
+
# Install package in dev mode
|
|
23
|
+
uv pip install -e .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Testing
|
|
27
|
+
```bash
|
|
28
|
+
# Run all tests (requires ETCD_ENDPOINT environment variable)
|
|
29
|
+
ETCD_ENDPOINT=192.168.31.15:12379 uv run pytest
|
|
30
|
+
|
|
31
|
+
# Run a single test file
|
|
32
|
+
ETCD_ENDPOINT=192.168.31.15:12379 uv run pytest tests/test_async_client.py
|
|
33
|
+
|
|
34
|
+
# Run a specific test method
|
|
35
|
+
ETCD_ENDPOINT=192.168.31.15:12379 uv run pytest tests/test_locks.py::TestAsyncLock::test_lock_acquire -v
|
|
36
|
+
|
|
37
|
+
# Run with coverage
|
|
38
|
+
ETCD_ENDPOINT=192.168.31.15:12379 uv run pytest --cov=etcd3 --cov=etcdrpc
|
|
39
|
+
|
|
40
|
+
# Run with verbose output
|
|
41
|
+
ETCD_ENDPOINT=192.168.31.15:12379 uv run pytest -v
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Linting & Formatting
|
|
45
|
+
```bash
|
|
46
|
+
# Check with ruff
|
|
47
|
+
uv run ruff check etcd3/ etcdrpc/
|
|
48
|
+
|
|
49
|
+
# Format with ruff
|
|
50
|
+
uv run ruff format etcd3/ etcdrpc/
|
|
51
|
+
|
|
52
|
+
# Run pylint
|
|
53
|
+
pylint etcd3/ etcdrpc/
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Protobuf Generation
|
|
57
|
+
```bash
|
|
58
|
+
# Protobuf files are auto-generated during build via hatchling hook
|
|
59
|
+
# To manually regenerate:
|
|
60
|
+
uv run python gen_protos.py
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Environment Variables
|
|
64
|
+
| Variable | Description |
|
|
65
|
+
|----------|-------------|
|
|
66
|
+
| `ETCD3_LOG_LEVEL` | Set logging level (DEBUG, INFO, WARNING, ERROR) |
|
|
67
|
+
| `ETCD_ENDPOINT` | etcd server address for testing (e.g., 192.168.31.15:12379) |
|
|
68
|
+
|
|
69
|
+
## Project Rules
|
|
70
|
+
|
|
71
|
+
1. Use `uv` for Python environment management, `hatchling` as build tool
|
|
72
|
+
2. Use `uv run python` to execute Python commands
|
|
73
|
+
3. Follow PEP8规范, use `pylint` for static analysis
|
|
74
|
+
4. Use `pytest` and `pytest-asyncio` for sync and async tests
|
|
75
|
+
5. Use context7 MCP to query official documentation
|
|
76
|
+
|
|
77
|
+
## Architecture
|
|
78
|
+
|
|
79
|
+
### Core Client Classes
|
|
80
|
+
|
|
81
|
+
**Sync client (`etcd3/client.py`):**
|
|
82
|
+
- `MultiEndpointEtcd3Client` - Base class with multiple endpoints and failover support
|
|
83
|
+
- `Etcd3Client` - Single endpoint client, inherits from `MultiEndpointEtcd3Client`
|
|
84
|
+
- `Endpoint` - Single etcd cluster endpoint with gRPC channel
|
|
85
|
+
|
|
86
|
+
**Async client (`etcd3/async_client.py`):**
|
|
87
|
+
- `AsyncMultiEndpointEtcd3Client` - Main async client with failover support
|
|
88
|
+
- `AsyncEtcd3Client` - Alias for backward compatibility
|
|
89
|
+
- `async_client()` - Factory function
|
|
90
|
+
|
|
91
|
+
### Configuration Classes
|
|
92
|
+
|
|
93
|
+
**`RangeRequestConfig`** - Dataclass for range query options (limit, revision, sort_order, etc.)
|
|
94
|
+
|
|
95
|
+
**`ClientConfig`** / **`AsyncClientConfig`** - Client connection configuration (host, port, timeout, TLS, auth)
|
|
96
|
+
|
|
97
|
+
**`AsyncMultiEndpointConfig`** - Multi-endpoint failover configuration
|
|
98
|
+
|
|
99
|
+
### Async Operation Extensions (`etcd3/async_client_extensions.py`)
|
|
100
|
+
|
|
101
|
+
Operation classes that wrap async functionality with error handling decorators:
|
|
102
|
+
- `AsyncKVOperations` - Key-value CRUD operations
|
|
103
|
+
- `AsyncLeaseOperations` - Lease creation, revocation, refresh
|
|
104
|
+
- `AsyncLockOperations` - Distributed lock operations
|
|
105
|
+
- `AsyncClusterOperations` - Cluster operations
|
|
106
|
+
- `AsyncMaintenanceOperations` - Maintenance operations
|
|
107
|
+
- `AsyncWatchOperations` - Watch operations
|
|
108
|
+
|
|
109
|
+
### Async Managers (`etcd3/async_managers.py`)
|
|
110
|
+
|
|
111
|
+
- `AsyncWatchManager` - Watch operations with callbacks and prefixes
|
|
112
|
+
- `AsyncClusterManager` - Cluster membership operations
|
|
113
|
+
- `AsyncMaintenanceManager` - Status, defragmentation, alarms, snapshots
|
|
114
|
+
|
|
115
|
+
### Endpoint Pattern
|
|
116
|
+
|
|
117
|
+
**`etcd3/endpoint.py`** - Base endpoint with shared logic:
|
|
118
|
+
- `BaseEndpoint` - Common endpoint functionality (fail state, health check)
|
|
119
|
+
|
|
120
|
+
**`etcd3/async_endpoint.py`** (async `AsyncEndpoint` class):
|
|
121
|
+
- Async gRPC channel with `is_healthy()` and `rebuild_channel()`
|
|
122
|
+
|
|
123
|
+
**`etcd3/client.py`** (sync `Endpoint` class):
|
|
124
|
+
- Sync gRPC channel with `is_healthy()` and `rebuild_channel()`
|
|
125
|
+
|
|
126
|
+
### Shared Components
|
|
127
|
+
|
|
128
|
+
**`etcd3/shared.py`:**
|
|
129
|
+
- `Transactions` - Transaction operation builders
|
|
130
|
+
- `KVMetadata` - Key-value metadata wrapper
|
|
131
|
+
- `Status`, `Alarm` - Status information classes
|
|
132
|
+
- `EtcdTokenCallCredentials` - Authentication credentials
|
|
133
|
+
- `RequestBuilder` - gRPC request builder utility
|
|
134
|
+
- `_handle_errors` / `_async_handle_errors` - Error handling decorators
|
|
135
|
+
- `_make_sync_handle_generator_errors_with_tracing` - Generator error decorator with `propagate_errors` support
|
|
136
|
+
|
|
137
|
+
**`etcd3/trace.py`:** Request tracing and monitoring utilities
|
|
138
|
+
|
|
139
|
+
**`etcd3/monitor.py` / `etcd3/async_monitor.py`:** Request monitoring decorators
|
|
140
|
+
|
|
141
|
+
**`etcd3/exceptions.py`:** Exception classes (`Etcd3Exception` and subclasses)
|
|
142
|
+
|
|
143
|
+
**`etcd3/utils.py`:** Key encoding, prefix ranges, lease conversion utilities, filter constants, load balancer strategies
|
|
144
|
+
|
|
145
|
+
**`etcd3/transactions.py`:** Transaction comparison and operation classes
|
|
146
|
+
|
|
147
|
+
**`etcd3/async_client_extensions.py`:**
|
|
148
|
+
- `get_request_context()` / `set_request_context()` - Context variable utilities for request tracking
|
|
149
|
+
- `AsyncKVOperations` - KV operations with `batch_put()`, `batch_delete()`, `put_many()` methods
|
|
150
|
+
|
|
151
|
+
**`etcd3/async_client.py`:**
|
|
152
|
+
- `client.context()` - Context manager for request tracking with `asyncio.Semaphore` concurrency control
|
|
153
|
+
|
|
154
|
+
**`etcd3/leases.py`:** `Lease` and `AsyncLease` classes
|
|
155
|
+
|
|
156
|
+
**`etcd3/locks.py`:** `Lock` and `AsyncLock` classes
|
|
157
|
+
|
|
158
|
+
**`etcd3/events.py`:** Watch event classes
|
|
159
|
+
|
|
160
|
+
**`etcd3/watch.py`** / **`etcd3/async_watch.py`:** Watch builder and iterator implementations
|
|
161
|
+
|
|
162
|
+
**`etcd3/members.py`:** `Member` class for cluster representation
|
|
163
|
+
|
|
164
|
+
### Protobuf Layer (`etcdrpc/`)
|
|
165
|
+
|
|
166
|
+
Generated gRPC/Python bindings from etcd proto files:
|
|
167
|
+
- `rpc_pb2.py`, `rpc_pb2_grpc.py` - Main RPC definitions
|
|
168
|
+
- `kv_pb2.py`, `kv_pb2_grpc.py` - Key-value service
|
|
169
|
+
- `auth_pb2.py`, `auth_pb2_grpc.py` - Authentication service
|
|
170
|
+
|
|
171
|
+
Compiled during build via `gen_protos.py` (hatchling build hook).
|
|
172
|
+
|
|
173
|
+
### Examples (`examples/`)
|
|
174
|
+
|
|
175
|
+
| File | Description |
|
|
176
|
+
|------|-------------|
|
|
177
|
+
| `leader_election.py` | Async leader election with lease-based lock |
|
|
178
|
+
| `leader_election_sync.py` | Sync version using threading |
|
|
179
|
+
| `service_registration.py` | Async service registration with auto-renewal |
|
|
180
|
+
| `service_registration_sync.py` | Sync version using threads |
|
|
181
|
+
| `service_discovery.py` | Async service discovery with watch callbacks |
|
|
182
|
+
| `service_discovery_sync.py` | Sync version using polling |
|
|
183
|
+
|
|
184
|
+
## Key Design Patterns
|
|
185
|
+
|
|
186
|
+
1. **Dual sync/async implementations:** Same API for sync (`client.py`) and async (`async_client.py`)
|
|
187
|
+
|
|
188
|
+
2. **Error handling decorators:**
|
|
189
|
+
- `_handle_errors` / `_async_handle_errors` - Standard error handling
|
|
190
|
+
- `_sync_handle_keepalive_errors` / `_async_handle_keepalive_errors` - Lease keepalive with `propagate_errors=True`
|
|
191
|
+
|
|
192
|
+
3. **Endpoint failover:** `MultiEndpointEtcd3Client` tracks failed endpoints with retry on `failover=True`
|
|
193
|
+
|
|
194
|
+
4. **Load balancing:** Multiple strategies supported via `LoadBalancerStrategy`:
|
|
195
|
+
- `PRIORITY` (default): Keep current endpoint if healthy, failover on failure
|
|
196
|
+
- `ROUND_ROBIN`: Cycle through endpoints sequentially
|
|
197
|
+
- `RANDOM`: Random endpoint selection
|
|
198
|
+
- `STICKY`: Maintain connection to the same endpoint
|
|
199
|
+
|
|
200
|
+
5. **Auto-reconnection:** Async has `_get_channel()`, sync has matching implementation with health check
|
|
201
|
+
|
|
202
|
+
6. **Lazy authentication:** Async uses `_init_auth()` with `asyncio.Lock()`, sync initializes in `__init__`
|
|
203
|
+
|
|
204
|
+
7. **Watch pattern:** Iterator + cancel function returns for both sync and async
|
|
205
|
+
|
|
206
|
+
8. **Request context tracking:** Use `client.context()` to track operations across async tasks:
|
|
207
|
+
```python
|
|
208
|
+
async with etcd.context(operation="batch_put", source="worker_1"):
|
|
209
|
+
await etcd.kv.batch_put(items)
|
|
210
|
+
ctx = get_request_context() # Get context in callbacks
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Common Operations
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
# KV Operations
|
|
217
|
+
client.get(key), client.put(key, value), client.delete(key)
|
|
218
|
+
client.get_prefix(prefix), client.get_range(start, end), client.get_all()
|
|
219
|
+
|
|
220
|
+
# Batch Operations (async only)
|
|
221
|
+
await client.kv.batch_put([('/key1', 'value1'), ('/key2', 'value2')])
|
|
222
|
+
await client.kv.batch_delete(['/key1', '/key2'])
|
|
223
|
+
await client.kv.put_many({'/key1': 'value1', '/key2': 'value2'})
|
|
224
|
+
|
|
225
|
+
# Watch with filters (only receive PUT events)
|
|
226
|
+
from etcd3 import FILTER_DELETE
|
|
227
|
+
events, cancel = await client.watch('/key', filters=[FILTER_DELETE])
|
|
228
|
+
|
|
229
|
+
# Leases
|
|
230
|
+
lease = client.lease(ttl)
|
|
231
|
+
async for response in lease.refresh(): pass
|
|
232
|
+
lease.revoke()
|
|
233
|
+
|
|
234
|
+
# Locks
|
|
235
|
+
lock = client.lock('/name', ttl=ttl)
|
|
236
|
+
await lock.acquire() / lock.release()
|
|
237
|
+
# or use context manager
|
|
238
|
+
|
|
239
|
+
# Watches
|
|
240
|
+
events_iter, cancel = client.watch(key)
|
|
241
|
+
async for event in events_iter: pass
|
|
242
|
+
cancel()
|
|
243
|
+
|
|
244
|
+
# Transactions
|
|
245
|
+
client.transaction(
|
|
246
|
+
compare=[client.transactions.value('/key') == 'expected'],
|
|
247
|
+
success=[client.transactions.put('/key', 'new')],
|
|
248
|
+
failure=[]
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
# Cluster
|
|
252
|
+
members = client.members()
|
|
253
|
+
client.add_member(urls), client.remove_member(id), client.update_member(id, urls)
|
|
254
|
+
|
|
255
|
+
# Maintenance
|
|
256
|
+
client.status(), client.compact(revision), client.defragment()
|
|
257
|
+
```
|