simudyne-pulse 0.7.0.dev12__tar.gz → 0.7.0.dev14__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.
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/PKG-INFO +1 -1
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/pyproject.toml +1 -1
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/validation.py +156 -13
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne_pulse.egg-info/PKG-INFO +1 -1
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/tests/test_validation.py +65 -1
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/LICENSE +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/README.md +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/setup.cfg +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/__init__.py +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/client.py +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/exceptions.py +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/__init__.py +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/api_keys.py +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/data.py +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/fix.py +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/fm.py +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/historical.py +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/profile.py +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/simulation.py +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/simulator_gym.py +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne_pulse.egg-info/SOURCES.txt +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne_pulse.egg-info/dependency_links.txt +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne_pulse.egg-info/requires.txt +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne_pulse.egg-info/top_level.txt +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/tests/test_new_resources.py +0 -0
- {simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/tests/test_simulator_gym.py +0 -0
{simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/validation.py
RENAMED
|
@@ -9,7 +9,7 @@ Submit, then poll::
|
|
|
9
9
|
|
|
10
10
|
job = client.validation.run(
|
|
11
11
|
symbol="BARC", date="2026-06-17", provider="bmll", exchange="lse",
|
|
12
|
-
sim_ids=[...],
|
|
12
|
+
sim_ids=[...],
|
|
13
13
|
)
|
|
14
14
|
result = client.validation.get_job(job["job_id"])
|
|
15
15
|
result["distances"]["spread"]["l1"] # per simulation
|
|
@@ -27,6 +27,14 @@ default for your tier, resolved server-side, so naming none behaves exactly as
|
|
|
27
27
|
your account is entitled to. Pass ``False`` to skip an expensive pass or
|
|
28
28
|
``True`` to force one on.
|
|
29
29
|
|
|
30
|
+
Tick size
|
|
31
|
+
---------
|
|
32
|
+
Read off the historical day — the metadata sidecar, else pulse_format's own
|
|
33
|
+
metadata for that day's ``full_data.parquet``. It is not a parameter. The
|
|
34
|
+
result reports ``metadata["ticksize"]`` and ``metadata["ticksize_source"]``;
|
|
35
|
+
a source of ``"fallback"`` means none was found and 1.0 was assumed, which
|
|
36
|
+
puts the impact response in price units rather than ticks.
|
|
37
|
+
|
|
30
38
|
The historical gate
|
|
31
39
|
-------------------
|
|
32
40
|
Whether the historical half of the comparison comes back — the series in the
|
|
@@ -39,6 +47,7 @@ them.
|
|
|
39
47
|
"""
|
|
40
48
|
|
|
41
49
|
import json
|
|
50
|
+
from collections.abc import Iterable
|
|
42
51
|
from pathlib import Path
|
|
43
52
|
|
|
44
53
|
|
|
@@ -146,7 +155,32 @@ def _save_plots(result: dict, plot_dir=None) -> list:
|
|
|
146
155
|
|
|
147
156
|
|
|
148
157
|
class ValidationResource:
|
|
149
|
-
"""
|
|
158
|
+
"""Score simulated market data against a real historical day.
|
|
159
|
+
|
|
160
|
+
Reached as ``client.validation``. A job compares one or more simulated runs
|
|
161
|
+
— either platform ``sim_ids`` or your own uploaded frames — against the
|
|
162
|
+
real day for the same instrument, and reports distances, distribution
|
|
163
|
+
overlaps, stylised-fact verdicts and FID/MIND scores.
|
|
164
|
+
|
|
165
|
+
Jobs are asynchronous: :meth:`run` returns a ``job_id`` and :meth:`get_job`
|
|
166
|
+
is polled until it is terminal. A validation of a real day takes minutes.
|
|
167
|
+
|
|
168
|
+
Examples
|
|
169
|
+
--------
|
|
170
|
+
>>> import time
|
|
171
|
+
>>> job = client.validation.run(
|
|
172
|
+
... symbol="BARC", date="2025-09-02",
|
|
173
|
+
... provider="bmll", exchange="lse",
|
|
174
|
+
... sim_ids=["sim_abc", "sim_def"],
|
|
175
|
+
... plots=True,
|
|
176
|
+
... )
|
|
177
|
+
>>> while True:
|
|
178
|
+
... result = client.validation.get_job(job["job_id"], plot_dir="figures/")
|
|
179
|
+
... if result["status"] in ("completed", "failed"):
|
|
180
|
+
... break
|
|
181
|
+
... time.sleep(30)
|
|
182
|
+
>>> result["distances"]
|
|
183
|
+
"""
|
|
150
184
|
|
|
151
185
|
def __init__(self, client):
|
|
152
186
|
self._client = client
|
|
@@ -160,7 +194,6 @@ class ValidationResource:
|
|
|
160
194
|
*,
|
|
161
195
|
sim_ids=None,
|
|
162
196
|
sim_files=None,
|
|
163
|
-
ticksize: float = 1.0,
|
|
164
197
|
statistical=None,
|
|
165
198
|
stylised_facts=None,
|
|
166
199
|
impact=None,
|
|
@@ -191,7 +224,10 @@ class ValidationResource:
|
|
|
191
224
|
exists under both with different dates and tick sizes, so
|
|
192
225
|
``(symbol, provider, exchange)`` is the identity, not the symbol.
|
|
193
226
|
exchange : str
|
|
194
|
-
Exchange, e.g. ``"lse"`` or ``"hkex_securities"``.
|
|
227
|
+
Exchange, e.g. ``"lse"`` or ``"hkex_securities"``. The tick size
|
|
228
|
+
is read off the historical day for this instrument rather than
|
|
229
|
+
passed in; ``metadata["ticksize"]`` reports the value used and
|
|
230
|
+
``metadata["ticksize_source"]`` where it came from.
|
|
195
231
|
sim_ids : list of str or dict, optional
|
|
196
232
|
Platform simulation IDs, 1 to 25. A flat list is one unnamed
|
|
197
233
|
population. A mapping — ``{"fm": [...], "abm": [...]}`` — compares
|
|
@@ -203,8 +239,6 @@ class ValidationResource:
|
|
|
203
239
|
Your own simulated runs, up to 25: paths, ``(filename, bytes)``
|
|
204
240
|
pairs, or polars / pandas DataFrames in pulse format. Grouped the
|
|
205
241
|
same way as ``sim_ids``. The historical side is fetched for you.
|
|
206
|
-
ticksize : float, default 1.0
|
|
207
|
-
Minimum price increment. Should match the instrument.
|
|
208
242
|
statistical, stylised_facts, impact, volume_correlation, fid, mind : bool, optional
|
|
209
243
|
Whether to run each area. ``None`` uses your tier's default.
|
|
210
244
|
lob : bool, optional
|
|
@@ -249,7 +283,58 @@ class ValidationResource:
|
|
|
249
283
|
Raises
|
|
250
284
|
------
|
|
251
285
|
ValueError
|
|
252
|
-
If
|
|
286
|
+
If neither or both of ``sim_ids`` and ``sim_files`` are given,
|
|
287
|
+
either is empty, more than 25 runs are passed, or ``n_levels``
|
|
288
|
+
is below 1. Also raised if the API
|
|
289
|
+
accepts the request but returns no ``job_id``.
|
|
290
|
+
PulseAPIError
|
|
291
|
+
If the instrument has no historical data for ``date``, a
|
|
292
|
+
``sim_id`` is unknown, or the tier does not allow a requested
|
|
293
|
+
area.
|
|
294
|
+
|
|
295
|
+
Examples
|
|
296
|
+
--------
|
|
297
|
+
Platform simulations against the real day:
|
|
298
|
+
|
|
299
|
+
>>> job = client.validation.run(
|
|
300
|
+
... symbol="BARC",
|
|
301
|
+
... date="2025-09-02",
|
|
302
|
+
... provider="bmll",
|
|
303
|
+
... exchange="lse",
|
|
304
|
+
... sim_ids=["sim_abc", "sim_def"],
|
|
305
|
+
... )
|
|
306
|
+
>>> job["job_id"]
|
|
307
|
+
'val_01H...'
|
|
308
|
+
|
|
309
|
+
Two named populations, compared against each other and the real day:
|
|
310
|
+
|
|
311
|
+
>>> job = client.validation.run(
|
|
312
|
+
... symbol="BARC", date="2025-09-02",
|
|
313
|
+
... provider="bmll", exchange="lse",
|
|
314
|
+
... sim_ids={"fm": ["sim_abc"], "abm": ["sim_def", "sim_ghi"]},
|
|
315
|
+
... )
|
|
316
|
+
|
|
317
|
+
Your own frames, with only the areas you want and selected figures:
|
|
318
|
+
|
|
319
|
+
>>> job = client.validation.run(
|
|
320
|
+
... symbol="BARC", date="2025-09-02",
|
|
321
|
+
... provider="bmll", exchange="lse",
|
|
322
|
+
... sim_files=[my_dataframe],
|
|
323
|
+
... statistical=True,
|
|
324
|
+
... stylised_facts=True,
|
|
325
|
+
... impact=False,
|
|
326
|
+
... plots=["statistical.radar", "stylised_facts.overall"],
|
|
327
|
+
... )
|
|
328
|
+
|
|
329
|
+
L2 snapshots resampled onto a one-second grid:
|
|
330
|
+
|
|
331
|
+
>>> job = client.validation.run(
|
|
332
|
+
... symbol="BARC", date="2025-09-02",
|
|
333
|
+
... provider="bmll", exchange="lse",
|
|
334
|
+
... sim_files=["book_snapshots.parquet"],
|
|
335
|
+
... lob=True,
|
|
336
|
+
... sample_period="1s",
|
|
337
|
+
... )
|
|
253
338
|
"""
|
|
254
339
|
if (sim_ids is None) == (sim_files is None):
|
|
255
340
|
raise ValueError("Pass exactly one of sim_ids or sim_files")
|
|
@@ -258,15 +343,29 @@ class ValidationResource:
|
|
|
258
343
|
if sim_files is not None and not sim_files:
|
|
259
344
|
raise ValueError("sim_files must not be empty")
|
|
260
345
|
given = sim_ids if sim_ids is not None else sim_files
|
|
346
|
+
name = "sim_ids" if sim_ids is not None else "sim_files"
|
|
347
|
+
if isinstance(given, dict):
|
|
348
|
+
# A bare string is iterable, so {"fm": "one.parquet"} used to count
|
|
349
|
+
# its characters as runs and fail with "Maximum 25 simulations" —
|
|
350
|
+
# a number the caller never wrote. Say what is actually wrong.
|
|
351
|
+
for group, runs in given.items():
|
|
352
|
+
if isinstance(runs, (str, bytes)):
|
|
353
|
+
raise ValueError(
|
|
354
|
+
f"{name}[{group!r}] must be a list of runs, not a "
|
|
355
|
+
f"single {type(runs).__name__} — write [{runs!r}]"
|
|
356
|
+
)
|
|
357
|
+
if not isinstance(runs, Iterable):
|
|
358
|
+
raise ValueError(
|
|
359
|
+
f"{name}[{group!r}] must be a list of runs, not "
|
|
360
|
+
f"{type(runs).__name__}"
|
|
361
|
+
)
|
|
261
362
|
count = (
|
|
262
|
-
sum(len(v) for v in given.values())
|
|
363
|
+
sum(len(list(v)) for v in given.values())
|
|
263
364
|
if isinstance(given, dict)
|
|
264
365
|
else len(given)
|
|
265
366
|
)
|
|
266
367
|
if count > MAX_SIM_FILES:
|
|
267
368
|
raise ValueError(f"Maximum {MAX_SIM_FILES} simulations per validation job")
|
|
268
|
-
if ticksize <= 0:
|
|
269
|
-
raise ValueError("ticksize must be positive")
|
|
270
369
|
if n_levels < 1:
|
|
271
370
|
raise ValueError("n_levels must be at least 1")
|
|
272
371
|
|
|
@@ -298,7 +397,6 @@ class ValidationResource:
|
|
|
298
397
|
if isinstance(sim_ids, dict)
|
|
299
398
|
else list(sim_ids)
|
|
300
399
|
),
|
|
301
|
-
"ticksize": ticksize,
|
|
302
400
|
"config": config,
|
|
303
401
|
},
|
|
304
402
|
)
|
|
@@ -332,7 +430,6 @@ class ValidationResource:
|
|
|
332
430
|
"date": date,
|
|
333
431
|
"provider": provider,
|
|
334
432
|
"exchange": exchange,
|
|
335
|
-
"ticksize": str(ticksize),
|
|
336
433
|
"config": json.dumps(config),
|
|
337
434
|
},
|
|
338
435
|
)
|
|
@@ -367,6 +464,34 @@ class ValidationResource:
|
|
|
367
464
|
``stylised_fact_verdicts``, ``volume_correlation``,
|
|
368
465
|
``fid_scores``, ``mind_scores`` — enough to rebuild every figure —
|
|
369
466
|
plus ``plot_paths`` when figures were written.
|
|
467
|
+
|
|
468
|
+
Raises
|
|
469
|
+
------
|
|
470
|
+
PulseAPIError
|
|
471
|
+
If ``job_id`` is unknown or belongs to another account — status
|
|
472
|
+
404.
|
|
473
|
+
|
|
474
|
+
Examples
|
|
475
|
+
--------
|
|
476
|
+
>>> result = client.validation.get_job(job_id)
|
|
477
|
+
>>> result["status"]
|
|
478
|
+
'running'
|
|
479
|
+
|
|
480
|
+
Poll to completion, writing any figures into a directory:
|
|
481
|
+
|
|
482
|
+
>>> import time
|
|
483
|
+
>>> while True:
|
|
484
|
+
... result = client.validation.get_job(job_id, plot_dir="figures/")
|
|
485
|
+
... if result["status"] in ("completed", "failed"):
|
|
486
|
+
... break
|
|
487
|
+
... time.sleep(30)
|
|
488
|
+
>>> print(result["plot_paths"])
|
|
489
|
+
['figures/statistical.radar.png', 'figures/stylised_facts.overall.png']
|
|
490
|
+
|
|
491
|
+
With named populations, the scores come back keyed by name:
|
|
492
|
+
|
|
493
|
+
>>> result["fid_scores"]
|
|
494
|
+
{'fm': 0.142, 'abm': 0.318}
|
|
370
495
|
"""
|
|
371
496
|
job = self._client._request("GET", f"{JOBS_PATH}/{job_id}")
|
|
372
497
|
if (job or {}).get("plots"):
|
|
@@ -384,6 +509,24 @@ class ValidationResource:
|
|
|
384
509
|
Returns
|
|
385
510
|
-------
|
|
386
511
|
dict
|
|
387
|
-
``
|
|
512
|
+
Contains ``jobs``, a list of job summaries newest first, and
|
|
513
|
+
``total``, the count before ``limit`` was applied.
|
|
514
|
+
|
|
515
|
+
Raises
|
|
516
|
+
------
|
|
517
|
+
PulseAPIError
|
|
518
|
+
If the key is invalid, revoked or expired — status 401.
|
|
519
|
+
|
|
520
|
+
Examples
|
|
521
|
+
--------
|
|
522
|
+
>>> listing = client.validation.list_jobs(limit=10)
|
|
523
|
+
>>> for job in listing["jobs"]:
|
|
524
|
+
... print(job["job_id"], job["status"], job["symbol"], job["date"])
|
|
525
|
+
|
|
526
|
+
Find the most recent completed job and read it back:
|
|
527
|
+
|
|
528
|
+
>>> done = [j for j in listing["jobs"] if j["status"] == "completed"]
|
|
529
|
+
>>> newest = done[0]
|
|
530
|
+
>>> result = client.validation.get_job(newest["job_id"])
|
|
388
531
|
"""
|
|
389
532
|
return self._client._request("GET", JOBS_PATH, params={"limit": limit})
|
|
@@ -83,7 +83,6 @@ class TestWhatToValidate:
|
|
|
83
83
|
({"sim_ids": SIM_IDS, "sim_files": [("a", b"x")]}, "exactly one"),
|
|
84
84
|
({"sim_ids": []}, "must not be empty"),
|
|
85
85
|
({"sim_ids": SIM_IDS * (MAX_SIM_FILES + 1)}, "Maximum 25"),
|
|
86
|
-
({"sim_ids": SIM_IDS, "ticksize": 0}, "ticksize must be positive"),
|
|
87
86
|
({"sim_ids": SIM_IDS, "n_levels": 0}, "at least 1"),
|
|
88
87
|
],
|
|
89
88
|
)
|
|
@@ -289,3 +288,68 @@ class TestPlotEverything:
|
|
|
289
288
|
def test_plot_all_is_gone(self):
|
|
290
289
|
with pytest.raises(TypeError):
|
|
291
290
|
_run([{"job_id": "v1"}], plot_all=True)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
class TestGroupShape:
|
|
294
|
+
"""A group's value is a list of runs. A bare string is not one.
|
|
295
|
+
|
|
296
|
+
``{"fm": "one.parquet"}`` is the natural thing to write for a group of
|
|
297
|
+
one, and it used to count the path's characters as runs and fail with
|
|
298
|
+
"Maximum 25 simulations per validation job" — a number the caller never
|
|
299
|
+
wrote anywhere.
|
|
300
|
+
"""
|
|
301
|
+
|
|
302
|
+
@staticmethod
|
|
303
|
+
def _submit(**kwargs):
|
|
304
|
+
return ValidationResource(FakeClient([{"job_id": "v1"}])).run(
|
|
305
|
+
**{**IDENTITY, **kwargs}
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
def test_a_string_names_itself_not_the_file_count(self):
|
|
309
|
+
with pytest.raises(ValueError, match=r"sim_files\['fm'\] must be a list"):
|
|
310
|
+
self._submit(sim_files={"fm": "one.parquet"})
|
|
311
|
+
|
|
312
|
+
def test_the_message_shows_the_fix(self):
|
|
313
|
+
with pytest.raises(ValueError, match=r"write \['one.parquet'\]"):
|
|
314
|
+
self._submit(sim_files={"fm": "one.parquet"})
|
|
315
|
+
|
|
316
|
+
def test_sim_ids_groups_are_checked_the_same_way(self):
|
|
317
|
+
with pytest.raises(ValueError, match=r"sim_ids\['abm'\] must be a list"):
|
|
318
|
+
self._submit(sim_ids={"abm": "sim_abc"})
|
|
319
|
+
|
|
320
|
+
def test_a_non_iterable_group_is_named_plainly(self):
|
|
321
|
+
with pytest.raises(ValueError, match=r"not NoneType"):
|
|
322
|
+
self._submit(sim_ids={"abm": None})
|
|
323
|
+
|
|
324
|
+
def test_a_real_list_still_passes(self):
|
|
325
|
+
client = FakeClient([{"job_id": "v1"}])
|
|
326
|
+
ValidationResource(client).run(sim_ids={"abm": ["a", "b"]}, **IDENTITY)
|
|
327
|
+
assert client.calls[0][2]["json"]["sim_ids"] == {"abm": ["a", "b"]}
|
|
328
|
+
|
|
329
|
+
def test_the_count_still_catches_too_many(self):
|
|
330
|
+
with pytest.raises(ValueError, match="Maximum 25"):
|
|
331
|
+
self._submit(sim_ids={"a": ["x"] * 13, "b": ["y"] * 13})
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
class TestTickSizeIsNotAsked:
|
|
335
|
+
"""It is read off the historical day, so passing one is a mistake.
|
|
336
|
+
|
|
337
|
+
The value a caller passed never reached a computation — the impact
|
|
338
|
+
response has always used the one pulse-check looks up — so accepting it
|
|
339
|
+
only let a result disagree with itself.
|
|
340
|
+
"""
|
|
341
|
+
|
|
342
|
+
def test_run_does_not_take_it(self):
|
|
343
|
+
with pytest.raises(TypeError, match="ticksize"):
|
|
344
|
+
ValidationResource(FakeClient([{"job_id": "v1"}])).run(
|
|
345
|
+
sim_ids=SIM_IDS, ticksize=0.1, **IDENTITY
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
def test_it_is_not_sent(self):
|
|
349
|
+
client, _ = _run([{"job_id": "v1"}])
|
|
350
|
+
assert "ticksize" not in client.calls[0][2]["json"]
|
|
351
|
+
|
|
352
|
+
def test_an_upload_does_not_send_it_either(self):
|
|
353
|
+
client = FakeClient([{"job_id": "v1"}])
|
|
354
|
+
ValidationResource(client).run(sim_files=[("a.parquet", b"x")], **IDENTITY)
|
|
355
|
+
assert "ticksize" not in client.calls[0][2]["data"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/__init__.py
RENAMED
|
File without changes
|
{simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/api_keys.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/historical.py
RENAMED
|
File without changes
|
|
File without changes
|
{simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/simulation.py
RENAMED
|
File without changes
|
{simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne/resources/simulator_gym.py
RENAMED
|
File without changes
|
{simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne_pulse.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne_pulse.egg-info/requires.txt
RENAMED
|
File without changes
|
{simudyne_pulse-0.7.0.dev12 → simudyne_pulse-0.7.0.dev14}/src/simudyne_pulse.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|