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.
Files changed (43) hide show
  1. {semblance-0.2.2/src/semblance.egg-info → semblance-0.4.0}/PKG-INFO +28 -10
  2. {semblance-0.2.2 → semblance-0.4.0}/README.md +26 -9
  3. {semblance-0.2.2 → semblance-0.4.0}/pyproject.toml +27 -1
  4. semblance-0.4.0/src/semblance/api.py +838 -0
  5. {semblance-0.2.2 → semblance-0.4.0}/src/semblance/cli.py +3 -2
  6. {semblance-0.2.2 → semblance-0.4.0}/src/semblance/export.py +38 -25
  7. {semblance-0.2.2 → semblance-0.4.0}/src/semblance/factory.py +15 -0
  8. {semblance-0.2.2 → semblance-0.4.0}/src/semblance/plugins.py +3 -3
  9. semblance-0.4.0/src/semblance/property_testing.py +160 -0
  10. semblance-0.4.0/src/semblance/rate_limit.py +48 -0
  11. semblance-0.4.0/src/semblance/state.py +80 -0
  12. {semblance-0.2.2 → semblance-0.4.0/src/semblance.egg-info}/PKG-INFO +28 -10
  13. {semblance-0.2.2 → semblance-0.4.0}/src/semblance.egg-info/SOURCES.txt +8 -0
  14. {semblance-0.2.2 → semblance-0.4.0}/src/semblance.egg-info/requires.txt +1 -0
  15. {semblance-0.2.2 → semblance-0.4.0}/tests/test_api.py +22 -1
  16. {semblance-0.2.2 → semblance-0.4.0}/tests/test_doc_examples.py +8 -1
  17. {semblance-0.2.2 → semblance-0.4.0}/tests/test_edge_cases.py +38 -1
  18. semblance-0.4.0/tests/test_export.py +101 -0
  19. {semblance-0.2.2 → semblance-0.4.0}/tests/test_phase2.py +5 -2
  20. semblance-0.4.0/tests/test_phase5.py +123 -0
  21. semblance-0.4.0/tests/test_phase6.py +217 -0
  22. semblance-0.4.0/tests/test_property_testing.py +53 -0
  23. semblance-0.4.0/tests/test_rate_limit.py +54 -0
  24. semblance-0.4.0/tests/test_smoke.py +32 -0
  25. semblance-0.2.2/src/semblance/api.py +0 -397
  26. semblance-0.2.2/src/semblance/state.py +0 -42
  27. {semblance-0.2.2 → semblance-0.4.0}/LICENSE.md +0 -0
  28. {semblance-0.2.2 → semblance-0.4.0}/setup.cfg +0 -0
  29. {semblance-0.2.2 → semblance-0.4.0}/src/semblance/__init__.py +0 -0
  30. {semblance-0.2.2 → semblance-0.4.0}/src/semblance/links.py +0 -0
  31. {semblance-0.2.2 → semblance-0.4.0}/src/semblance/pagination.py +0 -0
  32. {semblance-0.2.2 → semblance-0.4.0}/src/semblance/resolver.py +0 -0
  33. {semblance-0.2.2 → semblance-0.4.0}/src/semblance/testing.py +0 -0
  34. {semblance-0.2.2 → semblance-0.4.0}/src/semblance.egg-info/dependency_links.txt +0 -0
  35. {semblance-0.2.2 → semblance-0.4.0}/src/semblance.egg-info/entry_points.txt +0 -0
  36. {semblance-0.2.2 → semblance-0.4.0}/src/semblance.egg-info/top_level.txt +0 -0
  37. {semblance-0.2.2 → semblance-0.4.0}/tests/test_factory.py +0 -0
  38. {semblance-0.2.2 → semblance-0.4.0}/tests/test_links.py +0 -0
  39. {semblance-0.2.2 → semblance-0.4.0}/tests/test_phase3.py +0 -0
  40. {semblance-0.2.2 → semblance-0.4.0}/tests/test_phase4.py +0 -0
  41. {semblance-0.2.2 → semblance-0.4.0}/tests/test_plugins.py +0 -0
  42. {semblance-0.2.2 → semblance-0.4.0}/tests/test_resolver.py +0 -0
  43. {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.2.2
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
- Responses are generated from your output model: `name` comes from the query, `created_at` is random in the date range.
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 = api.as_fastapi()
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 and POST endpoints with input/output models |
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, GET returns stored |
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
- Responses are generated from your output model: `name` comes from the query, `created_at` is random in the date range.
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 = api.as_fastapi()
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 and POST endpoints with input/output models |
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, GET returns stored |
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.2.2"
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