Source code for lightwin.util.pickling

"""Define a class to pickle objects.

"pickling" a file comes down to saving it in binary format. It can be loaded
and used again later, even with a different Python instance. This is useful
when you want to study a :class:`.Fault` that took a long time to be
compensated, or a :class:`.SimulationOutput` obtained by a time-consuming
TraceWin multiparticle simulation.

.. warning::
    This a very basic pickling. Do not use for long-term storage, but for debug
    only.

.. note::
    Some attributes such as lambda function in :class:`.FieldMap` or modules in
    :class:`.SimulationOutput` cannot be pickled by the built-in `pickle`
    module. I do not plan to refactor them, so for now we stick with
    `cloudpickle` module.

Some objects have built-in `pickle` and `unpickle` methods, namely:

    - :class:`.Accelerator`
    - :class:`.Fault`
    - :class:`.FaultScenario`
    - :class:`.ListOfElements`
    - :class:`.SimulationOutput`

"""

import logging
from abc import ABC, abstractmethod
from pathlib import Path
from types import ModuleType

try:
    import cloudpickle
except ModuleNotFoundError:
    logging.error(
        "cloudpickler module not found. This should not be a problem if you "
        "do not want to use MyCloudPickler."
    )


[docs] class MyPickler(ABC): """Define an object that can save/load arbitrary objects to files."""
[docs] @abstractmethod def pickle(self, my_object: object, path: Path | str) -> None: """Pickle ("save") the object to a binary file.""" pass
[docs] @abstractmethod def unpickle(self, path: Path | str) -> object: """Unpickle ("load") the given path to recreate original object.""" pass
[docs] class MyCloudPickler(MyPickler): """Define a :class:`.MyPickler` that can handle modules and lambda functions. This pickler should not raise errors, but all attributes may not be properly re-created. """
[docs] def __init__(self) -> None: """Import the necessary module.""" assert isinstance(cloudpickle, ModuleType)
[docs] def pickle(self, my_object: object, path: Path | str) -> None: """Pickle ("save") the object to a binary file.""" with open(path, "wb") as f: cloudpickle.dump(my_object, f) logging.info(f"Pickled {my_object} to {path}.")
[docs] def unpickle(self, path: Path | str) -> object: """Unpickle ("load") the given path to recreate original object.""" with open(path, "rb") as f: my_object = cloudpickle.load(f) return my_object