dts: edtlib: allow pickling/unpickling EDT objects
We have a use case for saving the EDT object to be able to open it up
again later. It would be convenient to be able to do this with the
pickle module from stdlib.
The only thing stopping us from doing that appears to be the open
reference to sys.stderr that's held the edt object even after
EDT.__init__ exits. However, there doesn't seem to be a need to keep
holding on to this object, and in fact it would be a little bit nicer
to drop the reference in case something else (even in the same Python
process that created it originally) wants the EDT object around, but
might want the warn file closed if its refcount zeroes out.
Just drop the reference at the end of __init__ and make EDT._warn()
throw an exception if it's attempted to be used after the constructor
exits.
Make pickle-ability an API guarantee so we can treat any regressions
as bugs going forward.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
diff --git a/scripts/dts/edtlib.py b/scripts/dts/edtlib.py
index eb90c97..0232187 100644
--- a/scripts/dts/edtlib.py
+++ b/scripts/dts/edtlib.py
@@ -150,6 +150,9 @@
bindings_dirs:
The bindings directory paths passed to __init__()
+
+ The standard library's pickle module can be used to marshal and
+ unmarshal EDT objects.
"""
def __init__(self, dts, bindings_dirs, warn_file=None,
warn_reg_unit_address_mismatch=True,
@@ -182,8 +185,9 @@
to None. This allows 'fixed-partitions' binding to match regardless
of the bus the 'fixed-partition' is under.
"""
- # Do this indirection with None in case sys.stderr is deliberately
- # overridden
+ # Do this indirection with None in case sys.stderr is
+ # deliberately overridden. We'll only hold on to this file
+ # while we're initializing.
self._warn_file = sys.stderr if warn_file is None else warn_file
self._warn_reg_unit_address_mismatch = warn_reg_unit_address_mismatch
@@ -202,6 +206,11 @@
self._define_order()
+ # Drop the reference to the open warn file. This is necessary
+ # to make this object pickleable, but also allows it to get
+ # garbage collected and closed if nobody else is using it.
+ self._warn_file = None
+
def get_node(self, path):
"""
Returns the Node at the DT path or alias 'path'. Raises EDTError if the
@@ -748,7 +757,10 @@
.format(binding_path, prop_name))
def _warn(self, msg):
- print("warning: " + msg, file=self._warn_file)
+ if self._warn_file is not None:
+ print("warning: " + msg, file=self._warn_file)
+ else:
+ raise _err("can't _warn() outside of EDT.__init__")
class Node: