Source code for pymatgen.util.serialization
# coding: utf-8
# Copyright (c) Pymatgen Development Team.
# Distributed under the terms of the MIT License.
"""
Most features of this module has been moved to monty. Please refer to
monty.json and monty.serialization documentation.
"""
import json
import functools
import pickle
from pymatgen.core.periodic_table import Element
__author__ = "Shyue Ping Ong"
__copyright__ = "Copyright 2012, The Materials Project"
__version__ = "0.1"
__maintainer__ = "Shyue Ping Ong"
__email__ = "shyuep@gmail.com"
__date__ = "Apr 30, 2012"
[docs]def pmg_serialize(method):
"""
Decorator for methods that add MSON serializations keys
to the dictionary. See documentation of MSON for more details
"""
@functools.wraps(method)
def wrapper(*args, **kwargs):
self = args[0]
d = method(*args, **kwargs)
# Add @module and @class
d["@module"] = self.__class__.__module__
d["@class"] = self.__class__.__name__
return d
return wrapper
[docs]def json_pretty_dump(obj, filename):
"""
Serialize obj as a JSON formatted stream to the given filename (
pretty printing version)
"""
with open(filename, "wt") as fh:
json.dump(obj, fh, indent=4, sort_keys=4)
[docs]class PmgPickler(pickle.Pickler):
"""
Persistence of External Objects as described in section 12.1.5.1 of
https://docs.python.org/3/library/pickle.html
"""
[docs] def persistent_id(self, obj):
"""Instead of pickling as a regular class instance, we emit a
persistent ID."""
if isinstance(obj, Element):
# Here, our persistent ID is simply a tuple, containing a tag and
# a key
return obj.__class__.__name__, obj.symbol
else:
# If obj does not have a persistent ID, return None. This means obj
# needs to be pickled as usual.
return None
[docs]class PmgUnpickler(pickle.Unpickler):
"""
Persistence of External Objects as described in section 12.1.5.1 of
https://docs.python.org/3/library/pickle.html
"""
[docs] def persistent_load(self, pid):
"""
This method is invoked whenever a persistent ID is encountered.
Here, pid is the tuple returned by PmgPickler.
"""
try:
type_tag, key_id = pid
except Exception:
# Sometimes we get a string such as ('Element', u'C') instead
# of a real tuple. Use ast to evalute the expression (much safer
# than eval).
import ast
type_tag, key_id = ast.literal_eval(pid)
if type_tag == "Element":
return Element(key_id)
else:
# Always raises an error if you cannot return the correct object.
# Otherwise, the unpickler will think None is the object referenced
# by the persistent ID.
raise pickle.UnpicklingError(
"unsupported persistent object with pid %s" % pid)
[docs]def pmg_pickle_load(filobj, **kwargs):
r"""
Loads a pickle file and deserialize it with PmgUnpickler.
Args:
filobj: File-like object
**kwargs: Any of the keyword arguments supported by PmgUnpickler
Returns:
Deserialized object.
"""
return PmgUnpickler(filobj, **kwargs).load()
[docs]def pmg_pickle_dump(obj, filobj, **kwargs):
r"""
Dump an object to a pickle file using PmgPickler.
Args:
obj : Object to dump.
fileobj: File-like object
**kwargs: Any of the keyword arguments supported by PmgPickler
"""
return PmgPickler(filobj, **kwargs).dump(obj)
[docs]class SlotPickleMixin:
"""
This mixin makes it possible to pickle/unpickle objects with __slots__
defined.
"""
def __getstate__(self):
return dict(
(slot, getattr(self, slot))
for slot in self.__slots__ if hasattr(self, slot)
)
def __setstate__(self, state):
for slot, value in state.items():
setattr(self, slot, value)