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.
Files changed (94) hide show
  1. {fixtureqa-0.3.3/fixtureqa.egg-info → fixtureqa-0.3.4}/PKG-INFO +1 -1
  2. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/fix_builder.py +2 -2
  3. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/perf_payload.py +14 -8
  4. {fixtureqa-0.3.3 → fixtureqa-0.3.4/fixtureqa.egg-info}/PKG-INFO +1 -1
  5. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/pyproject.toml +1 -1
  6. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_perf_payload.py +27 -0
  7. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/LICENSE +0 -0
  8. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/README.md +0 -0
  9. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/__init__.py +0 -0
  10. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/__main__.py +0 -0
  11. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/__init__.py +0 -0
  12. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/app.py +0 -0
  13. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/connection_manager.py +0 -0
  14. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/deps.py +0 -0
  15. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/__init__.py +0 -0
  16. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/admin.py +0 -0
  17. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/auth.py +0 -0
  18. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/branding.py +0 -0
  19. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/custom_tags.py +0 -0
  20. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/fix_spec.py +0 -0
  21. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/messages.py +0 -0
  22. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/perf.py +0 -0
  23. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/scenarios.py +0 -0
  24. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/sessions.py +0 -0
  25. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/setup.py +0 -0
  26. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/spec_overlay.py +0 -0
  27. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/templates.py +0 -0
  28. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/routers/ws.py +0 -0
  29. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/api/schemas.py +0 -0
  30. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/config/__init__.py +0 -0
  31. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/__init__.py +0 -0
  32. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/atomic_io.py +0 -0
  33. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/auth.py +0 -0
  34. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/config_store.py +0 -0
  35. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/custom_tag_store.py +0 -0
  36. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/db_migrations.py +0 -0
  37. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/events.py +0 -0
  38. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/fix_application.py +0 -0
  39. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/fix_parser.py +0 -0
  40. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/fix_spec_parser.py +0 -0
  41. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/fix_tags.py +0 -0
  42. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/housekeeping.py +0 -0
  43. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/inbound.py +0 -0
  44. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/message_log.py +0 -0
  45. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/message_store.py +0 -0
  46. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/models.py +0 -0
  47. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/perf_engine.py +0 -0
  48. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/perf_models.py +0 -0
  49. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/perf_stats.py +0 -0
  50. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/perf_store.py +0 -0
  51. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/perf_writer.py +0 -0
  52. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/scenario_runner.py +0 -0
  53. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/scenario_store.py +0 -0
  54. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/session.py +0 -0
  55. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/session_manager.py +0 -0
  56. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/spec_overlay_store.py +0 -0
  57. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/template_store.py +0 -0
  58. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/user_store.py +0 -0
  59. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/core/venue_responses.py +0 -0
  60. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/fix_specs/FIX42.xml +0 -0
  61. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/fix_specs/FIX44.xml +0 -0
  62. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/server.py +0 -0
  63. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/static/assets/ag-grid-_QKprVdm.js +0 -0
  64. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/static/assets/index-BYDmHEr1.js +0 -0
  65. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/static/assets/index-D9vW5wFo.css +0 -0
  66. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/static/assets/react-vendor-2eF0YfZT.js +0 -0
  67. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/static/favicon.svg +0 -0
  68. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/static/index.html +0 -0
  69. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixture/ui/__init__.py +0 -0
  70. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixtureqa.egg-info/SOURCES.txt +0 -0
  71. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixtureqa.egg-info/dependency_links.txt +0 -0
  72. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixtureqa.egg-info/entry_points.txt +0 -0
  73. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixtureqa.egg-info/requires.txt +0 -0
  74. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/fixtureqa.egg-info/top_level.txt +0 -0
  75. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/setup.cfg +0 -0
  76. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_atomic_io.py +0 -0
  77. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_auth.py +0 -0
  78. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_connection_manager.py +0 -0
  79. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_db_migrations.py +0 -0
  80. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_fix_builder.py +0 -0
  81. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_health.py +0 -0
  82. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_inbound.py +0 -0
  83. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_inbound_validation.py +0 -0
  84. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_message_store.py +0 -0
  85. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_perf_api.py +0 -0
  86. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_perf_engine.py +0 -0
  87. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_perf_models.py +0 -0
  88. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_perf_rehydrate.py +0 -0
  89. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_scenarios.py +0 -0
  90. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_session_lifecycle.py +0 -0
  91. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_session_manager_concurrency.py +0 -0
  92. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_sessions.py +0 -0
  93. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_templates.py +0 -0
  94. {fixtureqa-0.3.3 → fixtureqa-0.3.4}/tests/test_ws.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fixtureqa
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary: FIXture — FIX Protocol Testing Tool
5
5
  Requires-Python: >=3.10
6
6
  License-File: LICENSE
@@ -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
- _CONTROL_TAGS = frozenset({8, 9, 10, 34, 49, 52, 56})
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 _CONTROL_TAGS]
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
- try:
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
- try:
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_:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fixtureqa
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary: FIXture — FIX Protocol Testing Tool
5
5
  Requires-Python: >=3.10
6
6
  License-File: LICENSE
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "fixtureqa"
7
- version = "0.3.3"
7
+ version = "0.3.4"
8
8
  description = "FIXture — FIX Protocol Testing Tool"
9
9
  requires-python = ">=3.10"
10
10
  dependencies = [
@@ -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