fixtureqa 0.3.3__tar.gz → 0.3.4__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.3.3/fixtureqa.egg-info → fixtureqa-0.3.4}/PKG-INFO +1 -1
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/fix_builder.py +2 -2
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/perf_payload.py +14 -8
- {fixtureqa-0.3.3 → fixtureqa-0.3.4/fixtureqa.egg-info}/PKG-INFO +1 -1
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/pyproject.toml +1 -1
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_perf_payload.py +27 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/LICENSE +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/README.md +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/__init__.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/__main__.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/__init__.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/app.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/connection_manager.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/deps.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/__init__.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/admin.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/auth.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/branding.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/custom_tags.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/fix_spec.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/messages.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/perf.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/scenarios.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/sessions.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/setup.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/spec_overlay.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/templates.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/ws.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/schemas.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/config/__init__.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/__init__.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/atomic_io.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/auth.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/config_store.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/custom_tag_store.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/db_migrations.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/events.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/fix_application.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/fix_parser.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/fix_spec_parser.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/fix_tags.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/housekeeping.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/inbound.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/message_log.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/message_store.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/models.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/perf_engine.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/perf_models.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/perf_stats.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/perf_store.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/perf_writer.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/scenario_runner.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/scenario_store.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/session.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/session_manager.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/spec_overlay_store.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/template_store.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/user_store.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/venue_responses.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/fix_specs/FIX42.xml +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/fix_specs/FIX44.xml +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/server.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/static/assets/ag-grid-_QKprVdm.js +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/static/assets/index-BYDmHEr1.js +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/static/assets/index-D9vW5wFo.css +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/static/assets/react-vendor-2eF0YfZT.js +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/static/favicon.svg +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/static/index.html +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/ui/__init__.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixtureqa.egg-info/SOURCES.txt +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixtureqa.egg-info/dependency_links.txt +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixtureqa.egg-info/entry_points.txt +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixtureqa.egg-info/requires.txt +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixtureqa.egg-info/top_level.txt +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/setup.cfg +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_atomic_io.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_auth.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_connection_manager.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_db_migrations.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_fix_builder.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_health.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_inbound.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_inbound_validation.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_message_store.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_perf_api.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_perf_engine.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_perf_models.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_perf_rehydrate.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_scenarios.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_session_lifecycle.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_session_manager_concurrency.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_sessions.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_templates.py +0 -0
- {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_ws.py +0 -0
|
@@ -23,7 +23,7 @@ from fixcore.message import DataDictionary, Group, GroupDef, Message
|
|
|
23
23
|
SOH = "\x01"
|
|
24
24
|
|
|
25
25
|
# Tags the transport owns; never copied from the user's raw into the body.
|
|
26
|
-
|
|
26
|
+
CONTROL_TAGS = frozenset({8, 9, 10, 34, 49, 52, 56})
|
|
27
27
|
_MSG_TYPE = 35
|
|
28
28
|
_TRANSACT_TIME = 60
|
|
29
29
|
|
|
@@ -57,7 +57,7 @@ def build_message_from_raw(
|
|
|
57
57
|
if not msg_type:
|
|
58
58
|
raise ValueError("Missing MsgType (tag 35)")
|
|
59
59
|
|
|
60
|
-
body = [(t, v) for t, v in pairs if t != _MSG_TYPE and t not in
|
|
60
|
+
body = [(t, v) for t, v in pairs if t != _MSG_TYPE and t not in CONTROL_TAGS]
|
|
61
61
|
if transact_time is not None and not any(t == _TRANSACT_TIME for t, _ in body):
|
|
62
62
|
body.insert(0, (_TRANSACT_TIME, transact_time))
|
|
63
63
|
|
|
@@ -28,6 +28,7 @@ from typing import Optional
|
|
|
28
28
|
|
|
29
29
|
from fixcore.message.message import Message
|
|
30
30
|
|
|
31
|
+
from .fix_builder import CONTROL_TAGS
|
|
31
32
|
from .perf_models import RunConfig, ScenarioConfig
|
|
32
33
|
|
|
33
34
|
_TOKEN_RE = re.compile(r"\{([^}]+)\}")
|
|
@@ -94,10 +95,7 @@ class PayloadFactory:
|
|
|
94
95
|
tpl = self._ts.get_template(self._uid, tpl_id) if self._ts else None
|
|
95
96
|
if tpl is None:
|
|
96
97
|
raise PerfConfigError(f"template {tpl_id!r} not found for scenario {scn.name!r}")
|
|
97
|
-
|
|
98
|
-
fields = {int(k): str(v) for k, v in tpl.get("fields", {}).items()}
|
|
99
|
-
except (TypeError, ValueError):
|
|
100
|
-
raise PerfConfigError(f"template {tpl_id!r} has non-integer tags")
|
|
98
|
+
fields = self._parse_fields(tpl, tpl_id)
|
|
101
99
|
self._templates[tpl_id] = fields
|
|
102
100
|
for val in fields.values():
|
|
103
101
|
for tok in _tokens(val):
|
|
@@ -116,10 +114,7 @@ class PayloadFactory:
|
|
|
116
114
|
tpl = self._ts.get_template(self._uid, tpl_id) if self._ts else None
|
|
117
115
|
if tpl is None:
|
|
118
116
|
raise PerfConfigError(f"{label} template {tpl_id!r} not found")
|
|
119
|
-
|
|
120
|
-
fields = {int(k): str(v) for k, v in tpl.get("fields", {}).items()}
|
|
121
|
-
except (TypeError, ValueError):
|
|
122
|
-
raise PerfConfigError(f"{label} template {tpl_id!r} has non-integer tags")
|
|
117
|
+
fields = self._parse_fields(tpl, tpl_id, label)
|
|
123
118
|
vars_ = self.config.payload.variables
|
|
124
119
|
for val in fields.values():
|
|
125
120
|
for tok in _tokens(val):
|
|
@@ -130,6 +125,17 @@ class PayloadFactory:
|
|
|
130
125
|
raise PerfConfigError(f"unknown token {{{tok}}} in {label} template {tpl_id!r}")
|
|
131
126
|
return fields
|
|
132
127
|
|
|
128
|
+
def _parse_fields(self, tpl: dict, tpl_id: str, label: str = "") -> dict[int, str]:
|
|
129
|
+
try:
|
|
130
|
+
fields = {int(k): str(v) for k, v in tpl.get("fields", {}).items()}
|
|
131
|
+
except (TypeError, ValueError):
|
|
132
|
+
what = f"{label} template" if label else "template"
|
|
133
|
+
raise PerfConfigError(f"{what} {tpl_id!r} has non-integer tags")
|
|
134
|
+
# Templates saved from composed raw keep transport-owned header tags
|
|
135
|
+
# (8/9/10/34/49/52/56). The session stamps those on send, so copying
|
|
136
|
+
# them into the body would duplicate them on the wire.
|
|
137
|
+
return {t: v for t, v in fields.items() if t not in CONTROL_TAGS}
|
|
138
|
+
|
|
133
139
|
def _validate_token(self, tok: str, scn: ScenarioConfig, tpl_id: str,
|
|
134
140
|
seen: list[str], vars_: dict) -> None:
|
|
135
141
|
if tok in _SIMPLE or tok in vars_:
|
|
@@ -171,6 +171,33 @@ def test_exec_template_cannot_override_standard_tags():
|
|
|
171
171
|
assert msg.get_field_or(9000, "") == "x" # custom field preserved
|
|
172
172
|
|
|
173
173
|
|
|
174
|
+
def test_transport_tags_stripped_from_templates():
|
|
175
|
+
# Templates saved from a composed raw message keep header tags the session
|
|
176
|
+
# stamps on send (8/9/10/34/49/52/56); copying them into the body would
|
|
177
|
+
# duplicate them on the wire.
|
|
178
|
+
hdr = {"8": "FIX.4.2", "9": "123", "10": "045", "34": "7",
|
|
179
|
+
"49": "CLIENT", "52": "20260101-00:00:00", "56": "VENUE"}
|
|
180
|
+
ts = FakeTemplateStore({
|
|
181
|
+
"ord": _tpl("ord", {"35": "D", "9001": "x", **hdr}),
|
|
182
|
+
"exe": _tpl("exe", {"35": "8", "9002": "y", **hdr}),
|
|
183
|
+
"nos": _tpl("nos", {"35": "D", "9003": "z", **hdr}),
|
|
184
|
+
})
|
|
185
|
+
cfg = _config([ScenarioConfig(name="s", weight=1, sequence="parallel", messages=["nos"])],
|
|
186
|
+
order_template_id="ord", exec_template_id="exe")
|
|
187
|
+
f = PayloadFactory(cfg, ts, "u")
|
|
188
|
+
|
|
189
|
+
order_msg, _ = f.build_single_order()
|
|
190
|
+
scn_msg, _ = f.build_template_message("nos", f.new_context(), {})
|
|
191
|
+
exec_msg = f.build_exec_message({376: "CORR1", 38: "100"}, exec_type="2", ord_status="2",
|
|
192
|
+
last_qty=100, cum_qty=100, leaves_qty=0, px="10")
|
|
193
|
+
for msg in (order_msg, scn_msg, exec_msg):
|
|
194
|
+
for tag in (8, 9, 10, 34, 49, 52, 56):
|
|
195
|
+
assert not msg.has_field(tag), f"transport tag {tag} leaked into body"
|
|
196
|
+
assert order_msg.get_field_or(9001, "") == "x"
|
|
197
|
+
assert exec_msg.get_field_or(9002, "") == "y"
|
|
198
|
+
assert scn_msg.get_field_or(9003, "") == "z"
|
|
199
|
+
|
|
200
|
+
|
|
174
201
|
def test_ref_token_rejected_in_standalone_template():
|
|
175
202
|
ts = FakeTemplateStore({"ord": _tpl("ord", {"35": "D", "41": "{ref:x.clordid}"})})
|
|
176
203
|
cfg = _config([], order_template_id="ord")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|