123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- # -*- test-case-name: twisted.test.test_persisted -*-
- # Copyright (c) Twisted Matrix Laboratories.
- # See LICENSE for details.
- """
- Utility classes for dealing with circular references.
- """
- from __future__ import division, absolute_import
- from twisted.python import log, reflect
- from twisted.python.compat import range, _constructMethod
- class NotKnown:
- def __init__(self):
- self.dependants = []
- self.resolved = 0
- def addDependant(self, mutableObject, key):
- assert not self.resolved
- self.dependants.append( (mutableObject, key) )
- resolvedObject = None
- def resolveDependants(self, newObject):
- self.resolved = 1
- self.resolvedObject = newObject
- for mut, key in self.dependants:
- mut[key] = newObject
- def __hash__(self):
- assert 0, "I am not to be used as a dictionary key."
- class _Container(NotKnown):
- """
- Helper class to resolve circular references on container objects.
- """
- def __init__(self, l, containerType):
- """
- @param l: The list of object which may contain some not yet referenced
- objects.
- @param containerType: A type of container objects (e.g., C{tuple} or
- C{set}).
- """
- NotKnown.__init__(self)
- self.containerType = containerType
- self.l = l
- self.locs = list(range(len(l)))
- for idx in range(len(l)):
- if not isinstance(l[idx], NotKnown):
- self.locs.remove(idx)
- else:
- l[idx].addDependant(self, idx)
- if not self.locs:
- self.resolveDependants(self.containerType(self.l))
- def __setitem__(self, n, obj):
- """
- Change the value of one contained objects, and resolve references if
- all objects have been referenced.
- """
- self.l[n] = obj
- if not isinstance(obj, NotKnown):
- self.locs.remove(n)
- if not self.locs:
- self.resolveDependants(self.containerType(self.l))
- class _Tuple(_Container):
- """
- Manage tuple containing circular references. Deprecated: use C{_Container}
- instead.
- """
- def __init__(self, l):
- """
- @param l: The list of object which may contain some not yet referenced
- objects.
- """
- _Container.__init__(self, l, tuple)
- class _InstanceMethod(NotKnown):
- def __init__(self, im_name, im_self, im_class):
- NotKnown.__init__(self)
- self.my_class = im_class
- self.name = im_name
- # im_self _must_ be a NotKnown
- im_self.addDependant(self, 0)
- def __call__(self, *args, **kw):
- import traceback
- log.msg('instance method %s.%s' % (reflect.qual(self.my_class), self.name))
- log.msg('being called with %r %r' % (args, kw))
- traceback.print_stack(file=log.logfile)
- assert 0
- def __setitem__(self, n, obj):
- assert n == 0, "only zero index allowed"
- if not isinstance(obj, NotKnown):
- method = _constructMethod(self.my_class, self.name, obj)
- self.resolveDependants(method)
- class _DictKeyAndValue:
- def __init__(self, dict):
- self.dict = dict
- def __setitem__(self, n, obj):
- if n not in (1, 0):
- raise RuntimeError("DictKeyAndValue should only ever be called with 0 or 1")
- if n: # value
- self.value = obj
- else:
- self.key = obj
- if hasattr(self, "key") and hasattr(self, "value"):
- self.dict[self.key] = self.value
- class _Dereference(NotKnown):
- def __init__(self, id):
- NotKnown.__init__(self)
- self.id = id
- from twisted.internet.defer import Deferred
- class _Defer(Deferred, NotKnown):
- def __init__(self):
- Deferred.__init__(self)
- NotKnown.__init__(self)
- self.pause()
- wasset = 0
- def __setitem__(self, n, obj):
- if self.wasset:
- raise RuntimeError('setitem should only be called once, setting %r to %r' % (n, obj))
- else:
- self.wasset = 1
- self.callback(obj)
- def addDependant(self, dep, key):
- # by the time I'm adding a dependant, I'm *not* adding any more
- # callbacks
- NotKnown.addDependant(self, dep, key)
- self.unpause()
- resovd = self.result
- self.resolveDependants(resovd)
|