fixtureqa 0.10.4__tar.gz → 0.11.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.
- {fixtureqa-0.10.4/fixtureqa.egg-info → fixtureqa-0.11.0}/PKG-INFO +1 -1
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/perf_engine.py +1 -1
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/perf_models.py +23 -4
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/perf_payload.py +36 -11
- fixtureqa-0.11.0/fixture/static/assets/index-CfkKS026.js +102 -0
- fixtureqa-0.10.4/fixture/static/assets/index-Bz-K8hE_.css → fixtureqa-0.11.0/fixture/static/assets/index-uoEGYkf_.css +1 -1
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/static/index.html +2 -2
- {fixtureqa-0.10.4 → fixtureqa-0.11.0/fixtureqa.egg-info}/PKG-INFO +1 -1
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixtureqa.egg-info/SOURCES.txt +2 -2
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/pyproject.toml +1 -1
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_perf_payload.py +43 -0
- fixtureqa-0.10.4/fixture/static/assets/index-DA2h8PYe.js +0 -102
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/LICENSE +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/README.md +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/__init__.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/__main__.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/__init__.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/app.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/connection_manager.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/deps.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/__init__.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/admin.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/auth.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/branding.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/custom_tags.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/fix_spec.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/messages.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/perf.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/scenarios.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/sessions.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/setup.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/spec_overlay.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/specs.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/templates.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/routers/ws.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/api/schemas.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/config/__init__.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/__init__.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/atomic_io.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/auth.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/config_store.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/custom_tag_store.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/db_migrations.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/events.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/fix_application.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/fix_builder.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/fix_parser.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/fix_spec_parser.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/fix_tags.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/fix_time.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/housekeeping.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/inbound.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/json_store.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/latency_csv_writer.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/message_log.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/message_store.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/models.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/perf_charts.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/perf_stats.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/perf_store.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/perf_writer.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/scenario_runner.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/scenario_store.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/session.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/session_manager.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/spec_overlay_store.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/spec_store.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/template_store.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/user_store.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/value_gen.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/core/venue_responses.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/server.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/static/assets/ag-grid-_QKprVdm.js +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/static/assets/index-CyNOPa0n.js +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/static/assets/react-vendor-2eF0YfZT.js +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/static/favicon.svg +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixture/ui/__init__.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixtureqa.egg-info/dependency_links.txt +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixtureqa.egg-info/entry_points.txt +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixtureqa.egg-info/requires.txt +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/fixtureqa.egg-info/top_level.txt +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/setup.cfg +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_atomic_io.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_auth.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_config_store.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_connection_manager.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_db_migrations.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_fix_builder.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_health.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_inbound.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_inbound_validation.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_message_store.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_non_stop_session.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_perf_api.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_perf_engine.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_perf_models.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_perf_rehydrate.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_scenarios.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_session_auto_response.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_session_lifecycle.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_session_manager_concurrency.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_sessions.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_specs.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_templates.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_timezone_data.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_value_gen.py +0 -0
- {fixtureqa-0.10.4 → fixtureqa-0.11.0}/tests/test_ws.py +0 -0
|
@@ -868,7 +868,7 @@ class PerfRun:
|
|
|
868
868
|
def _exec(self, of: dict, **kw) -> Optional[Message]:
|
|
869
869
|
"""Build one ExecReport via the exec template when configured, else the
|
|
870
870
|
built-in builder (Phase B). Both enforce the standard correlation tags."""
|
|
871
|
-
if self.
|
|
871
|
+
if self._factory.has_exec_template:
|
|
872
872
|
return self._factory.build_exec_message(of, **kw)
|
|
873
873
|
return self._build_exec(of, **kw)
|
|
874
874
|
|
|
@@ -175,10 +175,14 @@ class PayloadConfig(BaseModel):
|
|
|
175
175
|
fill: FillPayloadConfig = Field(default_factory=FillPayloadConfig)
|
|
176
176
|
scenarios: list[ScenarioConfig] = Field(default_factory=list)
|
|
177
177
|
# Phase B — optional TemplateStore template ids (resolved for the run's owner).
|
|
178
|
-
#
|
|
179
|
-
#
|
|
180
|
-
|
|
181
|
-
|
|
178
|
+
# The *_ids lists shape single-order injection / the venue's ack-fill ExecReports;
|
|
179
|
+
# when more than one is given the engine round-robins them per order / per report.
|
|
180
|
+
# Empty → built-in builders. The singular *_id fields are the legacy one-template
|
|
181
|
+
# form kept for old saved configs; _fold_template_ids merges them into the lists.
|
|
182
|
+
order_template_ids: list[str] = Field(default_factory=list)
|
|
183
|
+
exec_template_ids: list[str] = Field(default_factory=list)
|
|
184
|
+
order_template_id: Optional[str] = None # deprecated — folded into order_template_ids
|
|
185
|
+
exec_template_id: Optional[str] = None # deprecated — folded into exec_template_ids
|
|
182
186
|
# Send-options parity with the standard send UI (client-injected messages only):
|
|
183
187
|
# auto_expiry rewrites ExpireTime(126)/ExpireDate(432) to a future instant when
|
|
184
188
|
# the message already carries them (never inserts); gen_rules set tag → generator
|
|
@@ -194,6 +198,21 @@ class PayloadConfig(BaseModel):
|
|
|
194
198
|
raise ValueError("scenario weights must be > 0")
|
|
195
199
|
return self
|
|
196
200
|
|
|
201
|
+
@model_validator(mode="after")
|
|
202
|
+
def _fold_template_ids(self) -> "PayloadConfig":
|
|
203
|
+
# Old saved configs / API clients send the singular order_template_id /
|
|
204
|
+
# exec_template_id; fold those into the lists so the engine only reads
|
|
205
|
+
# the lists. Drop blanks and de-dup while preserving order.
|
|
206
|
+
if not self.order_template_ids and self.order_template_id:
|
|
207
|
+
self.order_template_ids = [self.order_template_id]
|
|
208
|
+
if not self.exec_template_ids and self.exec_template_id:
|
|
209
|
+
self.exec_template_ids = [self.exec_template_id]
|
|
210
|
+
self.order_template_ids = [t for t in dict.fromkeys(self.order_template_ids) if t]
|
|
211
|
+
self.exec_template_ids = [t for t in dict.fromkeys(self.exec_template_ids) if t]
|
|
212
|
+
self.order_template_id = self.order_template_ids[0] if self.order_template_ids else None
|
|
213
|
+
self.exec_template_id = self.exec_template_ids[0] if self.exec_template_ids else None
|
|
214
|
+
return self
|
|
215
|
+
|
|
197
216
|
|
|
198
217
|
class RelayConfig(BaseModel):
|
|
199
218
|
"""middle_manager relay behaviour. Verbatim forward by default; an optional
|
|
@@ -127,8 +127,12 @@ class PayloadFactory:
|
|
|
127
127
|
self._sender = sender_comp_id
|
|
128
128
|
self._target = target_comp_id
|
|
129
129
|
self._templates: dict[str, dict[int, str]] = {}
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
# Phase B standalone templates — one or more order / ExecReport specs,
|
|
131
|
+
# round-robined per order / per report when more than one is configured.
|
|
132
|
+
self._order_tpls: list[dict[int, str]] = []
|
|
133
|
+
self._exec_tpls: list[dict[int, str]] = []
|
|
134
|
+
self._order_tpl_i = 0
|
|
135
|
+
self._exec_tpl_i = 0
|
|
132
136
|
self._gen_rules: dict[int, str] = {} # tag → expression, every client msg
|
|
133
137
|
self._counters: dict[int, int] = {} # seq() state, per tag per run
|
|
134
138
|
self._symbol_i = 0
|
|
@@ -157,9 +161,10 @@ class PayloadFactory:
|
|
|
157
161
|
|
|
158
162
|
# Phase B standalone templates (no scenario sequence → no {ref:}).
|
|
159
163
|
p = self.config.payload
|
|
160
|
-
self.
|
|
161
|
-
|
|
162
|
-
self.
|
|
164
|
+
self._order_tpls = [self._load_standalone(tid, _SIMPLE, "order", merge_rules=True)
|
|
165
|
+
for tid in p.order_template_ids]
|
|
166
|
+
self._exec_tpls = [self._load_standalone(tid, _SIMPLE | _EXEC_TOKENS, "exec")
|
|
167
|
+
for tid in p.exec_template_ids]
|
|
163
168
|
|
|
164
169
|
def _parse_gen_rules(self, vars_: dict) -> dict[int, str]:
|
|
165
170
|
rules: dict[int, str] = {}
|
|
@@ -238,6 +243,26 @@ class PayloadFactory:
|
|
|
238
243
|
return
|
|
239
244
|
raise PerfConfigError(f"unknown token {{{tok}}} in template {tpl_id!r}")
|
|
240
245
|
|
|
246
|
+
# -- standalone template selection (round-robin) -------------------
|
|
247
|
+
|
|
248
|
+
@property
|
|
249
|
+
def has_order_template(self) -> bool:
|
|
250
|
+
return bool(self._order_tpls)
|
|
251
|
+
|
|
252
|
+
@property
|
|
253
|
+
def has_exec_template(self) -> bool:
|
|
254
|
+
return bool(self._exec_tpls)
|
|
255
|
+
|
|
256
|
+
def _next_order_tpl(self) -> dict[int, str]:
|
|
257
|
+
tpl = self._order_tpls[self._order_tpl_i % len(self._order_tpls)]
|
|
258
|
+
self._order_tpl_i += 1
|
|
259
|
+
return tpl
|
|
260
|
+
|
|
261
|
+
def _next_exec_tpl(self) -> dict[int, str]:
|
|
262
|
+
tpl = self._exec_tpls[self._exec_tpl_i % len(self._exec_tpls)]
|
|
263
|
+
self._exec_tpl_i += 1
|
|
264
|
+
return tpl
|
|
265
|
+
|
|
241
266
|
# -- order context (per scenario instance / per single order) ------
|
|
242
267
|
|
|
243
268
|
def new_context(self) -> dict:
|
|
@@ -262,8 +287,8 @@ class PayloadFactory:
|
|
|
262
287
|
def build_single_order(self) -> tuple[Message, dict]:
|
|
263
288
|
ctx = self.new_context()
|
|
264
289
|
corr, clordid = _uuid(), self._clordid()
|
|
265
|
-
if self.
|
|
266
|
-
return self._build_order_from_template(ctx, corr, clordid)
|
|
290
|
+
if self._order_tpls:
|
|
291
|
+
return self._build_order_from_template(self._next_order_tpl(), ctx, corr, clordid)
|
|
267
292
|
p = self.config.payload.order
|
|
268
293
|
is_market = p.ord_type == "market"
|
|
269
294
|
msg = Message()
|
|
@@ -437,11 +462,11 @@ class PayloadFactory:
|
|
|
437
462
|
|
|
438
463
|
# -- Phase B: templated single order ------------------------------------
|
|
439
464
|
|
|
440
|
-
def _build_order_from_template(self,
|
|
441
|
-
|
|
465
|
+
def _build_order_from_template(self, fields: dict[int, str], ctx: dict,
|
|
466
|
+
corr: str, clordid: str) -> tuple[Message, dict]:
|
|
467
|
+
"""Render one order template, then ensure the standard tags the venue and
|
|
442
468
|
correlator need are present (injected from ctx when the template omits them),
|
|
443
469
|
so an authored order spec can never break filling/correlation."""
|
|
444
|
-
fields = self._order_tpl
|
|
445
470
|
mtype = fields.get(35, "D")
|
|
446
471
|
msg = Message()
|
|
447
472
|
msg.header.set(35, mtype)
|
|
@@ -501,7 +526,7 @@ class PayloadFactory:
|
|
|
501
526
|
}
|
|
502
527
|
msg = Message()
|
|
503
528
|
msg.header.set(35, "8")
|
|
504
|
-
for tag, raw in self.
|
|
529
|
+
for tag, raw in self._next_exec_tpl().items():
|
|
505
530
|
if tag == 35:
|
|
506
531
|
continue
|
|
507
532
|
msg.set_field(tag, self._resolve_exec(raw, of, exec_ctx, tag))
|