1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
|
"""
A hashable Key class that provides a means for tracking
the lifetime of objects to associate objects with
blocks, options and other parts of an asdf file.
This Key is meant to replace uses of id(obj) which in
previous code was used to store settings (like block
array storage). The use of id was problematic as
an object might be deallocated (if it is removed from
the tree and all other references freed) and a new
object of the same type might occupy the same location
in memory and result in the same id. This could result
in options originally associated with the first object
being incorrectly assigned to the new object.
At it's core, Key, uses a weak reference to the object
which can be checked to see if the object is still
in memory.
Instances of this class will be provided to extension
code (see ``SerializationContext.generate_block_key``)
as Converters will need to resupply these keys
on rewrites (updates) to allow asdf to reassociate
objects and blocks. To discourage modifications
of these Key instances all methods and attributes
are private.
"""
import weakref
class Key:
_next = 0
@classmethod
def _next_key(cls):
key = cls._next
cls._next += 1
return key
def __init__(self, obj=None, _key=None):
if _key is None:
_key = Key._next_key()
self._key = _key
self._ref = None
if obj is not None:
self._assign_object(obj)
def _is_valid(self):
if self._ref is None:
return False
r = self._ref()
if r is None:
return False
return True
def __hash__(self):
return self._key
def _assign_object(self, obj):
self._ref = weakref.ref(obj)
def _matches_object(self, obj):
if self._ref is None:
return False
r = self._ref()
if r is None:
return False
return r is obj
def __eq__(self, other):
if not isinstance(other, Key):
return NotImplemented
if self._key != other._key:
return False
if not self._is_valid():
return False
return other._matches_object(self._ref())
def __copy__(self):
obj = self._ref if self._ref is None else self._ref()
return type(self)(obj, self._key)
|