cvt-sdk 0.1.3__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.
- cvt_sdk-0.1.3/LICENSE +21 -0
- cvt_sdk-0.1.3/PKG-INFO +439 -0
- cvt_sdk-0.1.3/README.md +410 -0
- cvt_sdk-0.1.3/cvt_sdk/__init__.py +1082 -0
- cvt_sdk-0.1.3/cvt_sdk/adapters/__init__.py +48 -0
- cvt_sdk-0.1.3/cvt_sdk/adapters/mock_adapter.py +358 -0
- cvt_sdk-0.1.3/cvt_sdk/adapters/requests_adapter.py +238 -0
- cvt_sdk-0.1.3/cvt_sdk/adapters/types.py +62 -0
- cvt_sdk-0.1.3/cvt_sdk/auto_register.py +222 -0
- cvt_sdk-0.1.3/cvt_sdk/producer/__init__.py +107 -0
- cvt_sdk-0.1.3/cvt_sdk/producer/adapters/__init__.py +11 -0
- cvt_sdk-0.1.3/cvt_sdk/producer/adapters/fastapi.py +344 -0
- cvt_sdk-0.1.3/cvt_sdk/producer/adapters/flask.py +304 -0
- cvt_sdk-0.1.3/cvt_sdk/producer/config.py +118 -0
- cvt_sdk-0.1.3/cvt_sdk/producer/producer.py +322 -0
- cvt_sdk-0.1.3/cvt_sdk/producer/testing.py +478 -0
- cvt_sdk-0.1.3/cvt_sdk/proto/__init__.py +73 -0
- cvt_sdk-0.1.3/cvt_sdk/proto/cvt_pb2.py +127 -0
- cvt_sdk-0.1.3/cvt_sdk/proto/cvt_pb2.pyi +472 -0
- cvt_sdk-0.1.3/cvt_sdk/proto/cvt_pb2_grpc.py +588 -0
- cvt_sdk-0.1.3/cvt_sdk.egg-info/PKG-INFO +439 -0
- cvt_sdk-0.1.3/cvt_sdk.egg-info/SOURCES.txt +29 -0
- cvt_sdk-0.1.3/cvt_sdk.egg-info/dependency_links.txt +1 -0
- cvt_sdk-0.1.3/cvt_sdk.egg-info/requires.txt +8 -0
- cvt_sdk-0.1.3/cvt_sdk.egg-info/top_level.txt +1 -0
- cvt_sdk-0.1.3/pyproject.toml +66 -0
- cvt_sdk-0.1.3/setup.cfg +4 -0
- cvt_sdk-0.1.3/tests/test_auto_register.py +377 -0
- cvt_sdk-0.1.3/tests/test_contract_validator.py +460 -0
- cvt_sdk-0.1.3/tests/test_producer.py +571 -0
- cvt_sdk-0.1.3/tests/test_producer_testing.py +205 -0
cvt_sdk-0.1.3/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 CVT Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
cvt_sdk-0.1.3/PKG-INFO
ADDED
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cvt-sdk
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Contract Validator Toolkit - Python SDK for validating HTTP interactions against OpenAPI schemas
|
|
5
|
+
Author: sahina
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/sahina/cvt
|
|
8
|
+
Project-URL: Documentation, https://github.com/sahina/cvt/tree/main/sdks/python
|
|
9
|
+
Project-URL: Repository, https://github.com/sahina/cvt
|
|
10
|
+
Project-URL: Issues, https://github.com/sahina/cvt/issues
|
|
11
|
+
Keywords: openapi,contract-testing,grpc,api-validation
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Testing
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: grpcio>=1.76.0
|
|
23
|
+
Requires-Dist: protobuf>=6.33.2
|
|
24
|
+
Provides-Extra: requests
|
|
25
|
+
Requires-Dist: requests>=2.32.0; extra == "requests"
|
|
26
|
+
Provides-Extra: all
|
|
27
|
+
Requires-Dist: requests>=2.32.0; extra == "all"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# Contract Validator Toolkit (CVT) - Python SDK
|
|
31
|
+
|
|
32
|
+
The **CVT Python SDK** allows you to validate HTTP interactions (requests and responses) against OpenAPI schemas using the CVT gRPC service.
|
|
33
|
+
|
|
34
|
+
> **Status**: Fully Implemented
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
### From PyPI (recommended)
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install cvt-sdk
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Or with uv:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
uv add cvt-sdk
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
With the optional requests adapter:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install "cvt-sdk[requests]"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### From local source (development)
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# From the project root
|
|
60
|
+
pip install -e sdks/python
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Usage
|
|
64
|
+
|
|
65
|
+
### Initialize and Register Schema
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from cvt_sdk import ContractValidator
|
|
69
|
+
|
|
70
|
+
validator = ContractValidator(host="localhost:9550")
|
|
71
|
+
|
|
72
|
+
# Register from local file
|
|
73
|
+
validator.register_schema("my-schema", "path/to/openapi.json")
|
|
74
|
+
|
|
75
|
+
# Register from URL
|
|
76
|
+
validator.register_schema("petstore", "https://petstore.swagger.io/v2/swagger.json")
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Validate Interactions
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from cvt_sdk import ContractValidator
|
|
83
|
+
|
|
84
|
+
validator = ContractValidator()
|
|
85
|
+
|
|
86
|
+
request = {
|
|
87
|
+
"method": "POST",
|
|
88
|
+
"path": "/users",
|
|
89
|
+
"body": {"username": "alice", "email": "alice@example.com"}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
response = {
|
|
93
|
+
"status_code": 201
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
result = validator.validate(request, response)
|
|
97
|
+
|
|
98
|
+
if result.valid:
|
|
99
|
+
print("✅ Valid interaction")
|
|
100
|
+
else:
|
|
101
|
+
print(f"❌ Validation errors: {result.errors}")
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## HTTP Adapter (Requests)
|
|
105
|
+
|
|
106
|
+
The SDK includes a Requests adapter for automatic HTTP traffic validation:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from cvt_sdk import ContractValidator
|
|
110
|
+
from cvt_sdk.adapters import ContractValidatingSession
|
|
111
|
+
|
|
112
|
+
validator = ContractValidator(host="localhost:9550")
|
|
113
|
+
validator.register_schema("petstore", "./openapi.json")
|
|
114
|
+
|
|
115
|
+
# Create a validating session (drop-in replacement for requests.Session)
|
|
116
|
+
session = ContractValidatingSession(
|
|
117
|
+
validator=validator,
|
|
118
|
+
schema_id="petstore",
|
|
119
|
+
auto_validate=True,
|
|
120
|
+
exclude_paths=["/health", "/metrics"],
|
|
121
|
+
on_validation_failure=lambda result, interaction: print(f"Failed: {result.errors}")
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# All requests are now automatically validated
|
|
125
|
+
response = session.post("https://api.example.com/pets", json={"name": "Fluffy"})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Adapter Options
|
|
129
|
+
|
|
130
|
+
- `auto_validate`: Enable/disable automatic validation (default: True)
|
|
131
|
+
- `include_paths`: List of paths/regex to include
|
|
132
|
+
- `exclude_paths`: List of paths/regex to exclude
|
|
133
|
+
- `on_validation_failure`: Custom error handler
|
|
134
|
+
- `get_interactions()`: Retrieve captured interactions
|
|
135
|
+
- `clear_interactions()`: Reset captured data
|
|
136
|
+
|
|
137
|
+
## Producer Validation (Server-Side Middleware)
|
|
138
|
+
|
|
139
|
+
Validate incoming requests and outgoing responses against your OpenAPI contract on the server side.
|
|
140
|
+
|
|
141
|
+
> **Full documentation:** See [Validation Modes](../../docs/guides/validation-modes.mdx) for detailed behavior, rollout strategy, and metrics information.
|
|
142
|
+
|
|
143
|
+
### Validation Modes
|
|
144
|
+
|
|
145
|
+
| Mode | Request Violation | Response Violation | Use Case |
|
|
146
|
+
| ----------------------- | ----------------- | ------------------ | ---------------------- |
|
|
147
|
+
| `ValidationMode.STRICT` | Reject with 400 | Log error | Production enforcement |
|
|
148
|
+
| `ValidationMode.WARN` | Log, continue | Log, continue | Gradual rollout |
|
|
149
|
+
| `ValidationMode.SHADOW` | Metrics only | Metrics only | Initial deployment |
|
|
150
|
+
|
|
151
|
+
**Recommended rollout:** `SHADOW` → `WARN` → `STRICT`. See [Recommended Rollout Strategy](../../docs/guides/validation-modes.mdx#recommended-rollout-strategy).
|
|
152
|
+
|
|
153
|
+
### FastAPI / ASGI Middleware
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from cvt_sdk import ContractValidator
|
|
157
|
+
from cvt_sdk.producer import ProducerConfig, ValidationMode
|
|
158
|
+
from cvt_sdk.producer.adapters import ASGIMiddleware
|
|
159
|
+
|
|
160
|
+
validator = ContractValidator(host="localhost:9550")
|
|
161
|
+
validator.register_schema("my-api", "./openapi.json")
|
|
162
|
+
|
|
163
|
+
config = ProducerConfig(
|
|
164
|
+
schema_id="my-api",
|
|
165
|
+
validator=validator,
|
|
166
|
+
mode=ValidationMode.STRICT,
|
|
167
|
+
exclude_paths=["/health", "/metrics"],
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
app.add_middleware(ASGIMiddleware, config=config)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Flask / WSGI Middleware
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from cvt_sdk.producer.adapters import WSGIMiddleware
|
|
177
|
+
|
|
178
|
+
app.wsgi_app = WSGIMiddleware(app.wsgi_app, config=config)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Configuration Options
|
|
182
|
+
|
|
183
|
+
| Option | Type | Description |
|
|
184
|
+
| --------------------- | ---------------- | ------------------------------------------ |
|
|
185
|
+
| `schema_id` | `str` | Schema ID to validate against |
|
|
186
|
+
| `validator` | `Validator` | ContractValidator instance |
|
|
187
|
+
| `mode` | `ValidationMode` | `STRICT`, `WARN`, or `SHADOW` |
|
|
188
|
+
| `exclude_paths` | `list[str]` | Paths to skip validation (e.g., `/health`) |
|
|
189
|
+
| `include_paths` | `list[str]` | Only validate matching paths |
|
|
190
|
+
| `validate_response` | `bool` | Enable response validation (default: True) |
|
|
191
|
+
| `on_validation_error` | `Callable` | Custom error handler callback |
|
|
192
|
+
|
|
193
|
+
## Breaking Change Detection
|
|
194
|
+
|
|
195
|
+
Detect breaking changes between OpenAPI schema versions before deployment:
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
from cvt_sdk import ContractValidator
|
|
199
|
+
|
|
200
|
+
validator = ContractValidator(host="localhost:9550")
|
|
201
|
+
|
|
202
|
+
# Register both schema versions
|
|
203
|
+
validator.register_schema_with_version("my-api", "./openapi-v1.json", "1.0.0")
|
|
204
|
+
validator.register_schema_with_version("my-api", "./openapi-v2.json", "2.0.0")
|
|
205
|
+
|
|
206
|
+
# Compare versions
|
|
207
|
+
result = validator.compare_schemas("my-api", "1.0.0", "2.0.0")
|
|
208
|
+
|
|
209
|
+
if not result.compatible:
|
|
210
|
+
print("Breaking changes detected:")
|
|
211
|
+
for change in result.breaking_changes:
|
|
212
|
+
print(f"- [{change.type}] {change.description}")
|
|
213
|
+
if change.path:
|
|
214
|
+
print(f" Path: {change.method} {change.path}")
|
|
215
|
+
sys.exit(1) # Fail CI build
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Breaking Change Types
|
|
219
|
+
|
|
220
|
+
| Type | Description |
|
|
221
|
+
| ---------------------- | ------------------------------------- |
|
|
222
|
+
| `ENDPOINT_REMOVED` | An endpoint was removed |
|
|
223
|
+
| `REQUIRED_FIELD_ADDED` | A required field was added to request |
|
|
224
|
+
| `FIELD_TYPE_CHANGED` | A field's type was changed |
|
|
225
|
+
| `ENUM_VALUE_REMOVED` | An allowed enum value was removed |
|
|
226
|
+
|
|
227
|
+
See `examples/breaking_changes.py` for a complete example.
|
|
228
|
+
|
|
229
|
+
## Producer Testing
|
|
230
|
+
|
|
231
|
+
Test that your API handlers return responses matching your OpenAPI specification.
|
|
232
|
+
|
|
233
|
+
### ProducerTestKit
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
from cvt_sdk.producer import ProducerTestKit, TestConfig, TestResponseData
|
|
237
|
+
|
|
238
|
+
test_kit = ProducerTestKit(TestConfig(
|
|
239
|
+
schema_id="user-api",
|
|
240
|
+
server_address="localhost:9550",
|
|
241
|
+
))
|
|
242
|
+
|
|
243
|
+
# Validate handler response
|
|
244
|
+
result = test_kit.validate_response(
|
|
245
|
+
method="GET",
|
|
246
|
+
path="/users/123",
|
|
247
|
+
response=TestResponseData(
|
|
248
|
+
status_code=200,
|
|
249
|
+
body={"id": "123", "name": "Alice", "email": "alice@example.com"},
|
|
250
|
+
),
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
assert result.valid
|
|
254
|
+
|
|
255
|
+
# Don't forget to close
|
|
256
|
+
test_kit.close()
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Consumer Registry
|
|
260
|
+
|
|
261
|
+
Track which services depend on your API:
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
# Register a consumer after successful contract tests
|
|
265
|
+
consumer = validator.register_consumer(
|
|
266
|
+
consumer_id="order-service",
|
|
267
|
+
consumer_version="2.1.0",
|
|
268
|
+
schema_id="user-api",
|
|
269
|
+
schema_version="1.0.0",
|
|
270
|
+
environment="prod",
|
|
271
|
+
used_endpoints=[
|
|
272
|
+
{"method": "GET", "path": "/users/{id}", "used_fields": ["id", "email"]},
|
|
273
|
+
],
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
# List all consumers of a schema
|
|
277
|
+
consumers = validator.list_consumers(schema_id="user-api", environment="prod")
|
|
278
|
+
|
|
279
|
+
# Deregister a consumer
|
|
280
|
+
validator.deregister_consumer("order-service", "user-api", "prod")
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Deployment Safety (can-i-deploy)
|
|
284
|
+
|
|
285
|
+
Check if a new schema version can be safely deployed:
|
|
286
|
+
|
|
287
|
+
```python
|
|
288
|
+
result = validator.can_i_deploy(
|
|
289
|
+
schema_id="user-api",
|
|
290
|
+
new_version="2.0.0",
|
|
291
|
+
environment="prod",
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
if not result.safe_to_deploy:
|
|
295
|
+
print(f"Cannot deploy: {result.summary}")
|
|
296
|
+
for consumer in result.affected_consumers:
|
|
297
|
+
if consumer.will_break:
|
|
298
|
+
print(f"- {consumer.consumer_id} will break")
|
|
299
|
+
sys.exit(1)
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
See [Producer Testing Guide](../../docs/guides/producer-testing.mdx) for complete documentation.
|
|
303
|
+
|
|
304
|
+
## Security Configuration
|
|
305
|
+
|
|
306
|
+
### TLS
|
|
307
|
+
|
|
308
|
+
```python
|
|
309
|
+
validator = ContractValidator(
|
|
310
|
+
host="localhost:9550",
|
|
311
|
+
tls_enabled=True,
|
|
312
|
+
tls_root_cert="./certs/ca.crt",
|
|
313
|
+
tls_client_cert="./certs/client.crt", # For mTLS
|
|
314
|
+
tls_client_key="./certs/client.key" # For mTLS
|
|
315
|
+
)
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### API Key Authentication
|
|
319
|
+
|
|
320
|
+
```python
|
|
321
|
+
validator = ContractValidator(
|
|
322
|
+
host="localhost:9550",
|
|
323
|
+
api_key="your-api-key-here"
|
|
324
|
+
)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Prerequisites
|
|
328
|
+
|
|
329
|
+
Ensure the CVT gRPC server is running (default: `localhost:9550`).
|
|
330
|
+
|
|
331
|
+
## Testing
|
|
332
|
+
|
|
333
|
+
The Python SDK includes tests covering:
|
|
334
|
+
|
|
335
|
+
- Client initialization and configuration
|
|
336
|
+
- Schema registration
|
|
337
|
+
- Validation requests and responses
|
|
338
|
+
- Error handling
|
|
339
|
+
|
|
340
|
+
### Running Tests
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
# Install dependencies
|
|
344
|
+
uv sync
|
|
345
|
+
|
|
346
|
+
# Run all tests
|
|
347
|
+
uv run pytest
|
|
348
|
+
|
|
349
|
+
# Run tests with coverage
|
|
350
|
+
uv run pytest --cov=cvt_sdk --cov-report=html
|
|
351
|
+
|
|
352
|
+
# View coverage report
|
|
353
|
+
open htmlcov/index.html
|
|
354
|
+
|
|
355
|
+
# Run specific test file
|
|
356
|
+
uv run pytest tests/test_validator.py
|
|
357
|
+
|
|
358
|
+
# Run with verbose output
|
|
359
|
+
uv run pytest -v -s
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Test Structure
|
|
363
|
+
|
|
364
|
+
```shell
|
|
365
|
+
tests/
|
|
366
|
+
├── test_validator.py # Main SDK test suite
|
|
367
|
+
├── test_registration.py # Schema registration tests
|
|
368
|
+
└── conftest.py # Test fixtures
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Writing Tests
|
|
372
|
+
|
|
373
|
+
Example test using pytest:
|
|
374
|
+
|
|
375
|
+
```python
|
|
376
|
+
import pytest
|
|
377
|
+
from cvt_sdk import ContractValidator
|
|
378
|
+
|
|
379
|
+
@pytest.fixture
|
|
380
|
+
def validator():
|
|
381
|
+
"""Create validator instance for testing."""
|
|
382
|
+
v = ContractValidator(host="localhost:9550")
|
|
383
|
+
yield v
|
|
384
|
+
v.close()
|
|
385
|
+
|
|
386
|
+
def test_validate_correct_interaction(validator):
|
|
387
|
+
"""Test validation of a correct interaction."""
|
|
388
|
+
validator.register_schema("test", "tests/fixtures/openapi.json")
|
|
389
|
+
|
|
390
|
+
result = validator.validate(
|
|
391
|
+
request={"method": "GET", "path": "/users"},
|
|
392
|
+
response={"status_code": 200, "body": []}
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
assert result.valid is True
|
|
396
|
+
|
|
397
|
+
def test_validate_incorrect_interaction(validator):
|
|
398
|
+
"""Test validation of an incorrect interaction."""
|
|
399
|
+
validator.register_schema("test", "tests/fixtures/openapi.json")
|
|
400
|
+
|
|
401
|
+
result = validator.validate(
|
|
402
|
+
request={"method": "GET", "path": "/users"},
|
|
403
|
+
response={"status_code": 500} # Should be 200
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
assert result.valid is False
|
|
407
|
+
assert len(result.errors) > 0
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Coverage
|
|
411
|
+
|
|
412
|
+
The SDK targets 60%+ test coverage.
|
|
413
|
+
|
|
414
|
+
## Development
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
# Install development dependencies
|
|
418
|
+
uv sync --all-extras
|
|
419
|
+
|
|
420
|
+
# Run linter
|
|
421
|
+
uv run ruff check cvt_sdk
|
|
422
|
+
|
|
423
|
+
# Format code
|
|
424
|
+
uv run ruff format cvt_sdk
|
|
425
|
+
|
|
426
|
+
# Type checking
|
|
427
|
+
uv run mypy cvt_sdk
|
|
428
|
+
|
|
429
|
+
# Build package
|
|
430
|
+
uv build
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## Contributing
|
|
434
|
+
|
|
435
|
+
Contributions are welcome!
|
|
436
|
+
|
|
437
|
+
## License
|
|
438
|
+
|
|
439
|
+
MIT License
|