semblance 0.2.2__tar.gz → 0.4.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.
- {semblance-0.2.2/src/semblance.egg-info → semblance-0.4.0}/PKG-INFO +28 -10
- {semblance-0.2.2 → semblance-0.4.0}/README.md +26 -9
- {semblance-0.2.2 → semblance-0.4.0}/pyproject.toml +27 -1
- semblance-0.4.0/src/semblance/api.py +838 -0
- {semblance-0.2.2 → semblance-0.4.0}/src/semblance/cli.py +3 -2
- {semblance-0.2.2 → semblance-0.4.0}/src/semblance/export.py +38 -25
- {semblance-0.2.2 → semblance-0.4.0}/src/semblance/factory.py +15 -0
- {semblance-0.2.2 → semblance-0.4.0}/src/semblance/plugins.py +3 -3
- semblance-0.4.0/src/semblance/property_testing.py +160 -0
- semblance-0.4.0/src/semblance/rate_limit.py +48 -0
- semblance-0.4.0/src/semblance/state.py +80 -0
- {semblance-0.2.2 → semblance-0.4.0/src/semblance.egg-info}/PKG-INFO +28 -10
- {semblance-0.2.2 → semblance-0.4.0}/src/semblance.egg-info/SOURCES.txt +8 -0
- {semblance-0.2.2 → semblance-0.4.0}/src/semblance.egg-info/requires.txt +1 -0
- {semblance-0.2.2 → semblance-0.4.0}/tests/test_api.py +22 -1
- {semblance-0.2.2 → semblance-0.4.0}/tests/test_doc_examples.py +8 -1
- {semblance-0.2.2 → semblance-0.4.0}/tests/test_edge_cases.py +38 -1
- semblance-0.4.0/tests/test_export.py +101 -0
- {semblance-0.2.2 → semblance-0.4.0}/tests/test_phase2.py +5 -2
- semblance-0.4.0/tests/test_phase5.py +123 -0
- semblance-0.4.0/tests/test_phase6.py +217 -0
- semblance-0.4.0/tests/test_property_testing.py +53 -0
- semblance-0.4.0/tests/test_rate_limit.py +54 -0
- semblance-0.4.0/tests/test_smoke.py +32 -0
- semblance-0.2.2/src/semblance/api.py +0 -397
- semblance-0.2.2/src/semblance/state.py +0 -42
- {semblance-0.2.2 → semblance-0.4.0}/LICENSE.md +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/setup.cfg +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/src/semblance/__init__.py +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/src/semblance/links.py +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/src/semblance/pagination.py +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/src/semblance/resolver.py +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/src/semblance/testing.py +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/src/semblance.egg-info/dependency_links.txt +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/src/semblance.egg-info/entry_points.txt +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/src/semblance.egg-info/top_level.txt +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/tests/test_factory.py +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/tests/test_links.py +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/tests/test_phase3.py +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/tests/test_phase4.py +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/tests/test_plugins.py +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/tests/test_resolver.py +0 -0
- {semblance-0.2.2 → semblance-0.4.0}/tests/test_state.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: semblance
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Schema-driven REST API simulation with FastAPI, Pydantic, and Polyfactory
|
|
5
5
|
Author: Semblance Contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -25,6 +25,7 @@ Provides-Extra: dev
|
|
|
25
25
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
26
26
|
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
27
27
|
Requires-Dist: httpx>=0.25.0; extra == "dev"
|
|
28
|
+
Requires-Dist: hypothesis>=6.0.0; extra == "dev"
|
|
28
29
|
Requires-Dist: ruff>=0.8.0; extra == "dev"
|
|
29
30
|
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
30
31
|
Requires-Dist: bandit>=1.7.0; extra == "dev"
|
|
@@ -55,7 +56,7 @@ Define API behavior declaratively using schemas and dependency metadata—no end
|
|
|
55
56
|
- **FastAPI-native** — Full OpenAPI, validation, async
|
|
56
57
|
- **Deterministic** — Seeded generation for reproducible tests
|
|
57
58
|
- **Extensible** — Custom link types via plugins
|
|
58
|
-
- **Production-ready** — Error simulation, latency, pagination, stateful mode
|
|
59
|
+
- **Production-ready** — Error simulation, latency, rate limiting, pagination, stateful mode, optional response validation
|
|
59
60
|
|
|
60
61
|
## Requirements
|
|
61
62
|
|
|
@@ -100,10 +101,10 @@ class User(BaseModel):
|
|
|
100
101
|
]
|
|
101
102
|
|
|
102
103
|
|
|
103
|
-
api = SemblanceAPI()
|
|
104
|
+
api = SemblanceAPI(seed=42)
|
|
104
105
|
|
|
105
106
|
|
|
106
|
-
@api.get("/users", input=UserQuery, output=list[User])
|
|
107
|
+
@api.get("/users", input=UserQuery, output=list[User], list_count=2)
|
|
107
108
|
def users():
|
|
108
109
|
pass
|
|
109
110
|
|
|
@@ -111,6 +112,8 @@ def users():
|
|
|
111
112
|
app = api.as_fastapi()
|
|
112
113
|
```
|
|
113
114
|
|
|
115
|
+
You can register PUT, PATCH, and DELETE endpoints the same way (`@api.put(...)`, `@api.patch(...)`, `@api.delete(..., output=None)` for 204).
|
|
116
|
+
|
|
114
117
|
Run:
|
|
115
118
|
|
|
116
119
|
```bash
|
|
@@ -125,7 +128,16 @@ Try:
|
|
|
125
128
|
curl "http://127.0.0.1:8000/users?name=alice&start_date=2024-01-01&end_date=2024-12-31"
|
|
126
129
|
```
|
|
127
130
|
|
|
128
|
-
|
|
131
|
+
Example output (with `SemblanceAPI(seed=42)` and `list_count=2` for reproducibility):
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
[
|
|
135
|
+
{"name": "alice", "created_at": "2024-08-21T09:22:43.516168"},
|
|
136
|
+
{"name": "alice", "created_at": "2024-01-10T03:05:39.176702"}
|
|
137
|
+
]
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Responses are generated from your output model: `name` comes from the query, `created_at` is in the date range.
|
|
129
141
|
|
|
130
142
|
## Use Cases
|
|
131
143
|
|
|
@@ -145,7 +157,7 @@ semblance run app:api [--host HOST] [--port PORT] [--reload]
|
|
|
145
157
|
# Export OpenAPI schema (optionally with response examples)
|
|
146
158
|
semblance export openapi app:api [-o FILE] [--examples]
|
|
147
159
|
|
|
148
|
-
# Export JSON fixtures per endpoint
|
|
160
|
+
# Export OpenAPI + JSON fixtures per endpoint (GET, POST, PUT, PATCH, DELETE)
|
|
149
161
|
semblance export fixtures app:api [-o DIR]
|
|
150
162
|
```
|
|
151
163
|
|
|
@@ -175,16 +187,19 @@ semblance run examples.plugins.app:api --port 8000
|
|
|
175
187
|
|
|
176
188
|
## Testing
|
|
177
189
|
|
|
190
|
+
Use the same `api` from Quick Start (with `app = api.as_fastapi()`). With the test client you get deterministic responses without starting a server:
|
|
191
|
+
|
|
178
192
|
```python
|
|
179
193
|
from semblance import SemblanceAPI, test_client
|
|
180
194
|
|
|
181
|
-
app
|
|
195
|
+
# api and app from Quick Start above
|
|
182
196
|
client = test_client(app)
|
|
183
197
|
|
|
184
198
|
r = client.get("/users?name=testuser")
|
|
185
199
|
assert r.status_code == 200
|
|
186
200
|
data = r.json()
|
|
187
201
|
assert all(u["name"] == "testuser" for u in data)
|
|
202
|
+
# data is a list of User dicts, e.g. [{"name": "testuser", "created_at": "..."}, ...]
|
|
188
203
|
```
|
|
189
204
|
|
|
190
205
|
Deterministic seeding for reproducible tests:
|
|
@@ -219,15 +234,18 @@ class User(BaseModel):
|
|
|
219
234
|
|
|
220
235
|
| Feature | Description |
|
|
221
236
|
|---------|-------------|
|
|
222
|
-
| **SemblanceAPI** | GET
|
|
237
|
+
| **SemblanceAPI** | GET, POST, PUT, PATCH, DELETE endpoints with input/output models |
|
|
223
238
|
| **Links** | FromInput, DateRangeFrom, WhenInput, ComputedFrom |
|
|
224
239
|
| **Pagination** | PageParams, PaginatedResponse[T] |
|
|
225
240
|
| **Seeding** | `SemblanceAPI(seed=42)` or `seed_from="seed"` |
|
|
226
241
|
| **Error simulation** | `error_rate`, `error_codes` |
|
|
227
242
|
| **Latency** | `latency_ms`, `jitter_ms` |
|
|
243
|
+
| **Rate limiting** | `rate_limit=N` — 429 when exceeded (per endpoint, sliding window) |
|
|
228
244
|
| **Filtering** | `filter_by` for list endpoints |
|
|
229
|
-
| **Stateful mode** | `SemblanceAPI(stateful=True)` — POST stores
|
|
245
|
+
| **Stateful mode** | `SemblanceAPI(stateful=True)` — POST stores; GET (list + by-id), PUT/PATCH/DELETE by id use store |
|
|
246
|
+
| **Response validation** | `SemblanceAPI(validate_responses=True)` — verify output conforms to model |
|
|
230
247
|
| **OpenAPI** | summary, description, tags on endpoints |
|
|
248
|
+
| **Property-based testing** | `semblance.property_testing`: `strategy_for_input_model()`, `test_endpoint()` (Hypothesis) |
|
|
231
249
|
|
|
232
250
|
## Competitors & Alternatives
|
|
233
251
|
|
|
@@ -245,7 +263,7 @@ class User(BaseModel):
|
|
|
245
263
|
| **Extensible (plugins)** | ✅ | <span title="Middleware-based; custom behavior via decorators or wrappers">🟡</span> | ❌ | ❌ | ✅ | <span title="Templates and response rules provide extensibility">🟡</span> |
|
|
246
264
|
| **OpenAPI schema** | ✅ | ✅ | ✅ | ❌ | ✅ | <span title="Can import/export OpenAPI; design is GUI-first, not schema-first">🟡</span> |
|
|
247
265
|
| **CI / pytest integration** | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
|
|
248
|
-
| **Property-based testing** |
|
|
266
|
+
| **Property-based testing** | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ |
|
|
249
267
|
|
|
250
268
|
🟡 = partial or configurable
|
|
251
269
|
|
|
@@ -16,7 +16,7 @@ Define API behavior declaratively using schemas and dependency metadata—no end
|
|
|
16
16
|
- **FastAPI-native** — Full OpenAPI, validation, async
|
|
17
17
|
- **Deterministic** — Seeded generation for reproducible tests
|
|
18
18
|
- **Extensible** — Custom link types via plugins
|
|
19
|
-
- **Production-ready** — Error simulation, latency, pagination, stateful mode
|
|
19
|
+
- **Production-ready** — Error simulation, latency, rate limiting, pagination, stateful mode, optional response validation
|
|
20
20
|
|
|
21
21
|
## Requirements
|
|
22
22
|
|
|
@@ -61,10 +61,10 @@ class User(BaseModel):
|
|
|
61
61
|
]
|
|
62
62
|
|
|
63
63
|
|
|
64
|
-
api = SemblanceAPI()
|
|
64
|
+
api = SemblanceAPI(seed=42)
|
|
65
65
|
|
|
66
66
|
|
|
67
|
-
@api.get("/users", input=UserQuery, output=list[User])
|
|
67
|
+
@api.get("/users", input=UserQuery, output=list[User], list_count=2)
|
|
68
68
|
def users():
|
|
69
69
|
pass
|
|
70
70
|
|
|
@@ -72,6 +72,8 @@ def users():
|
|
|
72
72
|
app = api.as_fastapi()
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
You can register PUT, PATCH, and DELETE endpoints the same way (`@api.put(...)`, `@api.patch(...)`, `@api.delete(..., output=None)` for 204).
|
|
76
|
+
|
|
75
77
|
Run:
|
|
76
78
|
|
|
77
79
|
```bash
|
|
@@ -86,7 +88,16 @@ Try:
|
|
|
86
88
|
curl "http://127.0.0.1:8000/users?name=alice&start_date=2024-01-01&end_date=2024-12-31"
|
|
87
89
|
```
|
|
88
90
|
|
|
89
|
-
|
|
91
|
+
Example output (with `SemblanceAPI(seed=42)` and `list_count=2` for reproducibility):
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
[
|
|
95
|
+
{"name": "alice", "created_at": "2024-08-21T09:22:43.516168"},
|
|
96
|
+
{"name": "alice", "created_at": "2024-01-10T03:05:39.176702"}
|
|
97
|
+
]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Responses are generated from your output model: `name` comes from the query, `created_at` is in the date range.
|
|
90
101
|
|
|
91
102
|
## Use Cases
|
|
92
103
|
|
|
@@ -106,7 +117,7 @@ semblance run app:api [--host HOST] [--port PORT] [--reload]
|
|
|
106
117
|
# Export OpenAPI schema (optionally with response examples)
|
|
107
118
|
semblance export openapi app:api [-o FILE] [--examples]
|
|
108
119
|
|
|
109
|
-
# Export JSON fixtures per endpoint
|
|
120
|
+
# Export OpenAPI + JSON fixtures per endpoint (GET, POST, PUT, PATCH, DELETE)
|
|
110
121
|
semblance export fixtures app:api [-o DIR]
|
|
111
122
|
```
|
|
112
123
|
|
|
@@ -136,16 +147,19 @@ semblance run examples.plugins.app:api --port 8000
|
|
|
136
147
|
|
|
137
148
|
## Testing
|
|
138
149
|
|
|
150
|
+
Use the same `api` from Quick Start (with `app = api.as_fastapi()`). With the test client you get deterministic responses without starting a server:
|
|
151
|
+
|
|
139
152
|
```python
|
|
140
153
|
from semblance import SemblanceAPI, test_client
|
|
141
154
|
|
|
142
|
-
app
|
|
155
|
+
# api and app from Quick Start above
|
|
143
156
|
client = test_client(app)
|
|
144
157
|
|
|
145
158
|
r = client.get("/users?name=testuser")
|
|
146
159
|
assert r.status_code == 200
|
|
147
160
|
data = r.json()
|
|
148
161
|
assert all(u["name"] == "testuser" for u in data)
|
|
162
|
+
# data is a list of User dicts, e.g. [{"name": "testuser", "created_at": "..."}, ...]
|
|
149
163
|
```
|
|
150
164
|
|
|
151
165
|
Deterministic seeding for reproducible tests:
|
|
@@ -180,15 +194,18 @@ class User(BaseModel):
|
|
|
180
194
|
|
|
181
195
|
| Feature | Description |
|
|
182
196
|
|---------|-------------|
|
|
183
|
-
| **SemblanceAPI** | GET
|
|
197
|
+
| **SemblanceAPI** | GET, POST, PUT, PATCH, DELETE endpoints with input/output models |
|
|
184
198
|
| **Links** | FromInput, DateRangeFrom, WhenInput, ComputedFrom |
|
|
185
199
|
| **Pagination** | PageParams, PaginatedResponse[T] |
|
|
186
200
|
| **Seeding** | `SemblanceAPI(seed=42)` or `seed_from="seed"` |
|
|
187
201
|
| **Error simulation** | `error_rate`, `error_codes` |
|
|
188
202
|
| **Latency** | `latency_ms`, `jitter_ms` |
|
|
203
|
+
| **Rate limiting** | `rate_limit=N` — 429 when exceeded (per endpoint, sliding window) |
|
|
189
204
|
| **Filtering** | `filter_by` for list endpoints |
|
|
190
|
-
| **Stateful mode** | `SemblanceAPI(stateful=True)` — POST stores
|
|
205
|
+
| **Stateful mode** | `SemblanceAPI(stateful=True)` — POST stores; GET (list + by-id), PUT/PATCH/DELETE by id use store |
|
|
206
|
+
| **Response validation** | `SemblanceAPI(validate_responses=True)` — verify output conforms to model |
|
|
191
207
|
| **OpenAPI** | summary, description, tags on endpoints |
|
|
208
|
+
| **Property-based testing** | `semblance.property_testing`: `strategy_for_input_model()`, `test_endpoint()` (Hypothesis) |
|
|
192
209
|
|
|
193
210
|
## Competitors & Alternatives
|
|
194
211
|
|
|
@@ -206,7 +223,7 @@ class User(BaseModel):
|
|
|
206
223
|
| **Extensible (plugins)** | ✅ | <span title="Middleware-based; custom behavior via decorators or wrappers">🟡</span> | ❌ | ❌ | ✅ | <span title="Templates and response rules provide extensibility">🟡</span> |
|
|
207
224
|
| **OpenAPI schema** | ✅ | ✅ | ✅ | ❌ | ✅ | <span title="Can import/export OpenAPI; design is GUI-first, not schema-first">🟡</span> |
|
|
208
225
|
| **CI / pytest integration** | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
|
|
209
|
-
| **Property-based testing** |
|
|
226
|
+
| **Property-based testing** | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ |
|
|
210
227
|
|
|
211
228
|
🟡 = partial or configurable
|
|
212
229
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "semblance"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "Schema-driven REST API simulation with FastAPI, Pydantic, and Polyfactory"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -35,6 +35,7 @@ dev = [
|
|
|
35
35
|
"pytest>=7.0.0",
|
|
36
36
|
"pytest-cov>=4.0.0",
|
|
37
37
|
"httpx>=0.25.0",
|
|
38
|
+
"hypothesis>=6.0.0",
|
|
38
39
|
"ruff>=0.8.0",
|
|
39
40
|
"mypy>=1.0.0",
|
|
40
41
|
"bandit>=1.7.0",
|
|
@@ -58,6 +59,9 @@ where = ["src"]
|
|
|
58
59
|
[tool.pytest.ini_options]
|
|
59
60
|
testpaths = ["tests"]
|
|
60
61
|
pythonpath = ["src"]
|
|
62
|
+
markers = [
|
|
63
|
+
"slow: marks tests as slow (e.g. time.sleep); use -m 'not slow' for fast runs",
|
|
64
|
+
]
|
|
61
65
|
|
|
62
66
|
[tool.ruff]
|
|
63
67
|
target-version = "py310"
|
|
@@ -73,9 +77,15 @@ ignore = ["E501"]
|
|
|
73
77
|
python_version = "3.10"
|
|
74
78
|
warn_return_any = true
|
|
75
79
|
warn_unused_configs = true
|
|
80
|
+
warn_unused_ignores = true
|
|
81
|
+
no_implicit_optional = true
|
|
76
82
|
disallow_untyped_defs = false
|
|
77
83
|
mypy_path = "src"
|
|
78
84
|
|
|
85
|
+
[[tool.mypy.overrides]]
|
|
86
|
+
module = ["semblance.*"]
|
|
87
|
+
disallow_untyped_defs = true
|
|
88
|
+
|
|
79
89
|
[[tool.mypy.overrides]]
|
|
80
90
|
module = ["polyfactory.*"]
|
|
81
91
|
ignore_missing_imports = true
|
|
@@ -84,6 +94,22 @@ ignore_missing_imports = true
|
|
|
84
94
|
module = ["semblance.api"]
|
|
85
95
|
disable_error_code = ["valid-type"]
|
|
86
96
|
|
|
97
|
+
[[tool.mypy.overrides]]
|
|
98
|
+
module = ["semblance.rate_limit", "semblance.state", "semblance.pagination"]
|
|
99
|
+
strict_optional = true
|
|
100
|
+
|
|
101
|
+
[[tool.mypy.overrides]]
|
|
102
|
+
module = ["semblance.export", "semblance.plugins"]
|
|
103
|
+
strict_optional = true
|
|
104
|
+
|
|
105
|
+
[[tool.mypy.overrides]]
|
|
106
|
+
module = ["semblance.api", "semblance.factory"]
|
|
107
|
+
strict_optional = true
|
|
108
|
+
|
|
109
|
+
[[tool.mypy.overrides]]
|
|
110
|
+
module = ["semblance.property_testing"]
|
|
111
|
+
strict_optional = true
|
|
112
|
+
|
|
87
113
|
[[tool.mypy.overrides]]
|
|
88
114
|
module = ["tests.*"]
|
|
89
115
|
disallow_untyped_defs = false
|