moirai-sim 0.3.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.
- moirai_sim-0.3.0/.gitignore +42 -0
- moirai_sim-0.3.0/CHANGELOG.md +37 -0
- moirai_sim-0.3.0/LICENSE +21 -0
- moirai_sim-0.3.0/PKG-INFO +342 -0
- moirai_sim-0.3.0/README.md +293 -0
- moirai_sim-0.3.0/pyproject.toml +58 -0
- moirai_sim-0.3.0/src/moirai/__init__.py +55 -0
- moirai_sim-0.3.0/src/moirai/__main__.py +170 -0
- moirai_sim-0.3.0/src/moirai/clock.py +145 -0
- moirai_sim-0.3.0/src/moirai/eventbus.py +195 -0
- moirai_sim-0.3.0/src/moirai/examples/__init__.py +13 -0
- moirai_sim-0.3.0/src/moirai/examples/economy.py +184 -0
- moirai_sim-0.3.0/src/moirai/examples/epidemic.py +160 -0
- moirai_sim-0.3.0/src/moirai/examples/population.py +122 -0
- moirai_sim-0.3.0/src/moirai/examples/weather.py +174 -0
- moirai_sim-0.3.0/src/moirai/exceptions.py +104 -0
- moirai_sim-0.3.0/src/moirai/metrics.py +242 -0
- moirai_sim-0.3.0/src/moirai/module.py +156 -0
- moirai_sim-0.3.0/src/moirai/py.typed +1 -0
- moirai_sim-0.3.0/src/moirai/resources.py +193 -0
- moirai_sim-0.3.0/src/moirai/scenario.py +284 -0
- moirai_sim-0.3.0/src/moirai/scheduler.py +247 -0
- moirai_sim-0.3.0/src/moirai/simulation.py +454 -0
- moirai_sim-0.3.0/src/moirai/snapshot.py +183 -0
- moirai_sim-0.3.0/tests/conftest.py +64 -0
- moirai_sim-0.3.0/tests/test_clock.py +94 -0
- moirai_sim-0.3.0/tests/test_integration.py +250 -0
- moirai_sim-0.3.0/tests/test_modules.py +559 -0
- moirai_sim-0.3.0/tests/test_scenario.py +169 -0
- moirai_sim-0.3.0/tests/test_scheduler.py +178 -0
- moirai_sim-0.3.0/tests/test_simulation.py +536 -0
- moirai_sim-0.3.0/tests/test_snapshot.py +127 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
*.so
|
|
7
|
+
*.egg
|
|
8
|
+
*.egg-info/
|
|
9
|
+
dist/
|
|
10
|
+
build/
|
|
11
|
+
*.whl
|
|
12
|
+
.eggs/
|
|
13
|
+
|
|
14
|
+
# Virtual environments
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
env/
|
|
18
|
+
.env
|
|
19
|
+
|
|
20
|
+
# Testing & coverage
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
.coverage
|
|
23
|
+
.coverage.*
|
|
24
|
+
htmlcov/
|
|
25
|
+
coverage.xml
|
|
26
|
+
*.coveragerc
|
|
27
|
+
|
|
28
|
+
# Type checking
|
|
29
|
+
.mypy_cache/
|
|
30
|
+
.pytype/
|
|
31
|
+
pyrightconfig.json
|
|
32
|
+
|
|
33
|
+
# IDEs
|
|
34
|
+
.idea/
|
|
35
|
+
.vscode/
|
|
36
|
+
*.swp
|
|
37
|
+
*.swo
|
|
38
|
+
.DS_Store
|
|
39
|
+
Thumbs.db
|
|
40
|
+
|
|
41
|
+
# Distribution
|
|
42
|
+
MANIFEST
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.3.0] - 2026-04-11
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `Scenario` system for multi-run experiments and cross-run analysis
|
|
14
|
+
- `Snapshot` for JSON serialization of simulation state
|
|
15
|
+
- `Scheduler` for deferred and recurring callbacks
|
|
16
|
+
- `Clock` with real-world time mapping and configurable units
|
|
17
|
+
- `ResourceContainer` for shared data between modules
|
|
18
|
+
- `py.typed` marker for PEP 561 type checking support
|
|
19
|
+
- Full test suite with coverage reporting
|
|
20
|
+
- Four built-in example simulations: weather, population, economy, epidemic
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- Complete rewrite of the core engine into the `src/moirai` package layout
|
|
24
|
+
- `Module` base class now typed and documented
|
|
25
|
+
- `EventBus` redesigned with typed event payloads
|
|
26
|
+
- `Metrics` now supports summaries and history
|
|
27
|
+
|
|
28
|
+
## [0.2.0] - 2026-04-01
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- Initial `Simulation`, `Module`, `EventBus`, `Metrics` primitives
|
|
32
|
+
- Basic phase-based module ordering
|
|
33
|
+
|
|
34
|
+
## [0.1.0] - 2026-03-15
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
- Project bootstrap
|
moirai_sim-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Naveoo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: moirai-sim
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: A universal orchestrator for dynamic modular simulations.
|
|
5
|
+
Project-URL: Homepage, https://github.com/naveoo/moirai
|
|
6
|
+
Project-URL: Repository, https://github.com/naveoo/moirai
|
|
7
|
+
Project-URL: Issues, https://github.com/naveoo/moirai/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/naveoo/moirai/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Naveoo <naa.veoos@gmail.com>
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 Naveoo
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: agent,dynamical-systems,ecs,modular,orchestrator,simulation
|
|
33
|
+
Classifier: Development Status :: 3 - Alpha
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: Intended Audience :: Science/Research
|
|
36
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
37
|
+
Classifier: Programming Language :: Python :: 3
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
39
|
+
Classifier: Topic :: Scientific/Engineering
|
|
40
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
41
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
42
|
+
Classifier: Typing :: Typed
|
|
43
|
+
Requires-Python: >=3.12
|
|
44
|
+
Provides-Extra: dev
|
|
45
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
46
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
47
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
48
|
+
Description-Content-Type: text/markdown
|
|
49
|
+
|
|
50
|
+
# ๐ Moirai
|
|
51
|
+
|
|
52
|
+
> **A universal orchestrator for dynamic, modular simulations.**
|
|
53
|
+
|
|
54
|
+
[](https://www.python.org/downloads/)
|
|
55
|
+
[](https://opensource.org/licenses/MIT)
|
|
56
|
+
[](https://badge.fury.io/py/moirai-sim)
|
|
57
|
+
|
|
58
|
+
Moirai is a lightweight, extensible Python framework for orchestrating heterogeneous simulations. A central `Simulation` runtime manages pluggable `Module` components โ each responsible for its own domain logic.
|
|
59
|
+
|
|
60
|
+
**Use it for:** agent-based models, ECS systems, weather simulation, economic models, epidemiology, social dynamics, city simulators, power grids, supply chains, and any other dynamic system you can imagine.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## โจ Philosophy
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
Simulation โ universal runtime
|
|
68
|
+
Module โ pluggable domain logic
|
|
69
|
+
EventBus โ loose coupling between modules
|
|
70
|
+
Metrics โ observable simulation state
|
|
71
|
+
Resources โ shared data between modules
|
|
72
|
+
Clock โ real-world time mapping
|
|
73
|
+
Scheduler โ deferred & recurring callbacks
|
|
74
|
+
Snapshot โ serialize state to JSON
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## ๐ Quick Start
|
|
80
|
+
|
|
81
|
+
### Installation
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pip install moirai-sim
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Or from source:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
git clone https://github.com/yourname/moirai
|
|
91
|
+
cd moirai
|
|
92
|
+
pip install -e ".[dev]"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Basic Usage
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from moirai import Simulation
|
|
99
|
+
from moirai.clock import Clock
|
|
100
|
+
from moirai.examples.weather import WeatherModule
|
|
101
|
+
from moirai.examples.population import PopulationModule
|
|
102
|
+
|
|
103
|
+
sim = Simulation(seed=42, clock=Clock(time_step=1.0, unit="day"))
|
|
104
|
+
|
|
105
|
+
sim.attach(WeatherModule(initial_temp=15.0))
|
|
106
|
+
sim.attach(PopulationModule(initial_mood=100.0))
|
|
107
|
+
|
|
108
|
+
sim.run(365)
|
|
109
|
+
|
|
110
|
+
print(sim.summary())
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## ๐งฉ Writing a Module
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
from moirai.module import Module
|
|
119
|
+
|
|
120
|
+
class EconomyModule(Module):
|
|
121
|
+
phase = "economy" # execution phase (lexicographic order)
|
|
122
|
+
priority = 0 # within-phase ordering (lower = earlier)
|
|
123
|
+
enabled = True # set False to skip update() each tick
|
|
124
|
+
|
|
125
|
+
def setup(self, sim) -> None:
|
|
126
|
+
sim.resources.set("gdp", 1_000_000.0)
|
|
127
|
+
|
|
128
|
+
def update(self, sim) -> None:
|
|
129
|
+
growth = sim.rng.uniform(0.98, 1.03)
|
|
130
|
+
gdp = sim.resources.get("gdp")
|
|
131
|
+
sim.resources.set("gdp", gdp * growth)
|
|
132
|
+
sim.metrics.track("gdp", sim.resources.get("gdp"))
|
|
133
|
+
sim.eventbus.emit("gdp_updated", value=sim.resources.get("gdp"))
|
|
134
|
+
|
|
135
|
+
def teardown(self, sim) -> None:
|
|
136
|
+
pass
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## ๐ Event Bus
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
# Standard subscription
|
|
145
|
+
sim.eventbus.subscribe("gdp_updated", lambda value, **_: print(f"GDP: {value:,.0f}"))
|
|
146
|
+
|
|
147
|
+
# One-shot (auto-unsubscribes after first call)
|
|
148
|
+
sim.eventbus.once("run_start", lambda **_: print("Simulation started!"))
|
|
149
|
+
|
|
150
|
+
# Wildcard โ receives every event
|
|
151
|
+
sim.eventbus.subscribe("*", lambda **kw: log.debug("event received"))
|
|
152
|
+
|
|
153
|
+
# Decorator shorthand on the simulation
|
|
154
|
+
@sim.on("temperature_changed")
|
|
155
|
+
def log_temp(value, **_):
|
|
156
|
+
print(f"[{sim.clock.format_time(sim.ticks)}] Temp: {value:.1f} ยฐC")
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## โฑ Clock
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from datetime import datetime
|
|
165
|
+
from moirai.clock import Clock
|
|
166
|
+
|
|
167
|
+
# 1 tick = 1 day, anchored to a calendar date
|
|
168
|
+
clock = Clock(time_step=1.0, unit="day", start_date=datetime(2025, 1, 1))
|
|
169
|
+
|
|
170
|
+
sim = Simulation(seed=42, clock=clock)
|
|
171
|
+
sim.run(90)
|
|
172
|
+
|
|
173
|
+
print(sim.clock.format_time(sim.ticks)) # "2025-04-01"
|
|
174
|
+
print(sim.time) # 90.0
|
|
175
|
+
print(clock.ticks_for(365)) # 365
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## ๐ Scheduler
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
# One-shot callback at tick 10
|
|
184
|
+
sim.scheduler.schedule_at(10, lambda: print("Tick 10!"))
|
|
185
|
+
|
|
186
|
+
# Recurring every 7 ticks (weekly event)
|
|
187
|
+
handle = sim.scheduler.schedule_every(7, lambda: print("Weekly checkpoint"))
|
|
188
|
+
|
|
189
|
+
# Cancel
|
|
190
|
+
sim.scheduler.cancel(handle)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## ๐ Metrics
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
# Track values
|
|
199
|
+
sim.metrics.track("population", 5_000)
|
|
200
|
+
|
|
201
|
+
# Query
|
|
202
|
+
print(sim.metrics.history("population")) # full history
|
|
203
|
+
print(sim.metrics.latest("population")) # most recent value
|
|
204
|
+
|
|
205
|
+
# Statistical summary
|
|
206
|
+
s = sim.metrics.summary("population")
|
|
207
|
+
print(s.mean, s.std, s.min, s.max, s.count)
|
|
208
|
+
|
|
209
|
+
# Export to JSON
|
|
210
|
+
sim.metrics.export_json("results/metrics.json")
|
|
211
|
+
|
|
212
|
+
# pandas-compatible dict
|
|
213
|
+
import pandas as pd
|
|
214
|
+
df = pd.DataFrame(sim.metrics.to_frame())
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## ๐ชฃ Resources
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
# Set, get, update
|
|
223
|
+
sim.resources.set("gdp", 1_000_000.0)
|
|
224
|
+
sim.resources.update({"inflation": 0.02, "unemployment": 0.05})
|
|
225
|
+
|
|
226
|
+
# Type-safe get โ raises ResourceTypeError on mismatch
|
|
227
|
+
gdp = sim.resources.get_typed("gdp", float)
|
|
228
|
+
|
|
229
|
+
# set-if-absent
|
|
230
|
+
sim.resources.setdefault("mortality_rate", 0.01)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## โธ Pause & Resume
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
class CheckpointModule(Module):
|
|
239
|
+
phase = "control"
|
|
240
|
+
|
|
241
|
+
def setup(self, sim): pass
|
|
242
|
+
def teardown(self, sim): pass
|
|
243
|
+
|
|
244
|
+
def update(self, sim):
|
|
245
|
+
if sim.ticks == 100:
|
|
246
|
+
sim.pause() # stops the loop after this tick
|
|
247
|
+
|
|
248
|
+
sim.attach(CheckpointModule())
|
|
249
|
+
ticks_run = sim.run(365) # returns early at tick 100
|
|
250
|
+
print(sim.state) # SimulationState.PAUSED
|
|
251
|
+
sim.run(265) # resume for remaining ticks
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## ๐ธ Snapshots
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
sim.run(100)
|
|
260
|
+
|
|
261
|
+
# Save
|
|
262
|
+
snap = sim.snapshot()
|
|
263
|
+
snap.save("checkpoint.json")
|
|
264
|
+
|
|
265
|
+
# Load & inspect
|
|
266
|
+
from moirai.snapshot import Snapshot
|
|
267
|
+
loaded = Snapshot.load("checkpoint.json")
|
|
268
|
+
print(loaded.tick) # 100
|
|
269
|
+
print(loaded.resources) # {"temperature": ...}
|
|
270
|
+
print(loaded.summary())
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## ๐ฌ Built-in Examples
|
|
276
|
+
|
|
277
|
+
| Module | Domain | Key resources |
|
|
278
|
+
| --- | --- | --- |
|
|
279
|
+
| `WeatherModule` | Climate | `temperature` |
|
|
280
|
+
| `PopulationModule` | Social | `population_mood` |
|
|
281
|
+
| `EpidemicModule` | Epidemiology (SIR) | `sir_S`, `sir_I`, `sir_R` |
|
|
282
|
+
| `EconomyModule` | Macroeconomics | `gdp`, `inflation`, `unemployment` |
|
|
283
|
+
|
|
284
|
+
```python
|
|
285
|
+
from moirai.examples.epidemic import EpidemicModule
|
|
286
|
+
|
|
287
|
+
sim = Simulation(seed=0)
|
|
288
|
+
sim.eventbus.subscribe("epidemic_ended", lambda tick, **_: print(f"Ended at tick {tick}"))
|
|
289
|
+
sim.attach(EpidemicModule(population=100_000, initial_infected=10, beta=0.3, gamma=0.1))
|
|
290
|
+
sim.run(500)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## ๐ Project Structure
|
|
296
|
+
|
|
297
|
+
```text
|
|
298
|
+
moirai/
|
|
299
|
+
โโโ pyproject.toml
|
|
300
|
+
โโโ README.md
|
|
301
|
+
โโโ CHANGELOG.md
|
|
302
|
+
โโโ src/
|
|
303
|
+
โ โโโ moirai/
|
|
304
|
+
โ โโโ __init__.py # Public API
|
|
305
|
+
โ โโโ simulation.py # Orchestrator + SimulationState
|
|
306
|
+
โ โโโ module.py # Abstract Module base
|
|
307
|
+
โ โโโ eventbus.py # Pub/sub (once, wildcard)
|
|
308
|
+
โ โโโ metrics.py # Time-series + MetricSummary
|
|
309
|
+
โ โโโ resources.py # Typed resource container
|
|
310
|
+
โ โโโ clock.py # Time-unit mapping
|
|
311
|
+
โ โโโ scheduler.py # Deferred/recurring callbacks
|
|
312
|
+
โ โโโ snapshot.py # JSON checkpoint
|
|
313
|
+
โ โโโ exceptions.py # Exception hierarchy
|
|
314
|
+
โ โโโ py.typed # PEP 561
|
|
315
|
+
โ โโโ examples/
|
|
316
|
+
โ โโโ weather.py
|
|
317
|
+
โ โโโ population.py
|
|
318
|
+
โ โโโ epidemic.py # SIR model
|
|
319
|
+
โ โโโ economy.py # GDP / inflation / unemployment
|
|
320
|
+
โโโ tests/
|
|
321
|
+
โโโ conftest.py
|
|
322
|
+
โโโ test_simulation.py # 68 tests
|
|
323
|
+
โโโ test_modules.py # 85 tests
|
|
324
|
+
โโโ test_clock.py # 17 tests
|
|
325
|
+
โโโ test_scheduler.py # 20 tests
|
|
326
|
+
โโโ test_snapshot.py # 15 tests
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## ๐งช Running Tests
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
pytest
|
|
335
|
+
pytest --cov=moirai --cov-report=term-missing
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## ๐ License
|
|
341
|
+
|
|
342
|
+
MIT โ see [LICENSE](LICENSE) for details.
|