diff --git a/python/fastsim/__init__.py b/python/fastsim/__init__.py index 70f17608..3dd9afe0 100644 --- a/python/fastsim/__init__.py +++ b/python/fastsim/__init__.py @@ -6,7 +6,10 @@ import logging import traceback from typing import Dict +from typing_extensions import Self +import inspect +import fastsim from fastsim import parameters as params from fastsim import utils from fastsim import simdrive, vehicle, cycle, calibration, tests @@ -55,3 +58,35 @@ def _as_numpy_array(self, *args, **kwargs): setattr(fsr.Pyo3ArrayU32, "__array__", _as_numpy_array) setattr(fsr.Pyo3ArrayBool, "__array__", _as_numpy_array) setattr(fsr.Pyo3VecF64, "__array__", _as_numpy_array) + +# creates a list of all python classes from rust structs that need to_pydict and +# from_pydict added as methods +ACCEPTED_RUST_STRUCTS = [attr for attr in fastsim.__dir__() if not\ + attr.startswith("__") and\ + isinstance(getattr(fastsim, attr), type) and\ + attr[0].isupper() and\ + ("fastsim" in str(inspect.getmodule(getattr(fastsim, attr))))] + +def to_pydict(self) -> Dict: + """ + Returns self converted to pure python dictionary with no nested Rust objects + """ + import json + return json.loads(self.to_json()) + +@classmethod +def from_pydict(cls, pydict: Dict) -> Self: + """ + Instantiates Self from pure python dictionary + """ + import json + return cls.from_json(json.dumps(pydict)) + +for item in ACCEPTED_RUST_STRUCTS: + setattr(getattr(fastsim, item), "to_pydict", to_pydict) + setattr(getattr(fastsim, item), "from_pydict", from_pydict) + +setattr(fsr.RustVehicle, "to_pydict", to_pydict) +setattr(fsr.RustVehicle, "from_pydict", from_pydict) +setattr(fastsim.vehicle.Vehicle, "to_pydict", to_pydict) +setattr(fastsim.vehicle.Vehicle, "from_pydict", from_pydict) diff --git a/python/fastsim/demos/pydict_demo.py b/python/fastsim/demos/pydict_demo.py new file mode 100644 index 00000000..4a2e8360 --- /dev/null +++ b/python/fastsim/demos/pydict_demo.py @@ -0,0 +1,22 @@ +""" +Script demonstrating how to use to_pydict() and from_pydict() for FASTSim +classes. +""" +import fastsim as fsim +from fastsim import fastsimrust as fsr + +# load 2012 Ford F-150 Ecoboost from file +veh = fsim.vehicle.Vehicle.from_file("2017_Ford_F-150_Ecoboost.csv").to_rust() +print(veh) + +# saving vehicle as pydict +veh_pydict = veh.to_pydict() +print(veh_pydict) + +# getting fastsim vehicle from pydict +from_pydict_veh = fsr.RustVehicle.from_pydict(veh_pydict) +print(from_pydict_veh) + +# spot checking to see if the pre-pydict and post-pydict Rust Vehicles are the same +assert(veh.scenario_name==from_pydict_veh.scenario_name) +assert(veh.drag_coef==from_pydict_veh.drag_coef) \ No newline at end of file