Attempting a on-demand resolution of datatypes references, so we don't need to call resolve_references anymore. It works with python 2, but not yet python 3 (some weakref issues)

This commit is contained in:
Christophe de Vienne 2012-06-04 19:22:32 +02:00
parent 520341238e
commit 938c6f5e13
4 changed files with 35 additions and 9 deletions

@ -32,6 +32,7 @@ deps=
webtest webtest
coverage coverage
simplejson simplejson
zope.interface<=3.8.99
transaction<=1.1.1 transaction<=1.1.1
[testenv:sphinxext] [testenv:sphinxext]

@ -117,7 +117,6 @@ class WSRoot(object):
:rtype: list of (path, :class:`FunctionDefinition`) :rtype: list of (path, :class:`FunctionDefinition`)
""" """
if self._api is None: if self._api is None:
self.__registry__.resolve_references()
self._api = [i for i in scan_api(self)] self._api = [i for i in scan_api(self)]
return self._api return self._api

@ -287,6 +287,15 @@ class TestTypes(unittest.TestCase):
types.register_type(A) types.register_type(A)
types.register_type(B) types.register_type(B)
types.registry.resolve_references()
assert A.b.datatype is B assert A.b.datatype is B
def test_base(self):
class B1(types.Base):
b2 = types.wsattr('B2')
class B2(types.Base):
b2 = types.wsattr('B2')
assert B1.b2.datatype is B2, repr(B1.b2.datatype)
assert B2.b2.datatype is B2

@ -203,13 +203,15 @@ class wsattr(object):
#: The attribute name on the public of the api. #: The attribute name on the public of the api.
#: Defaults to :attr:`key` #: Defaults to :attr:`key`
self.name = name self.name = name
self._datatype = datatype self._datatype = (datatype,)
#: True if the attribute is mandatory #: True if the attribute is mandatory
self.mandatory = mandatory self.mandatory = mandatory
#: Default value. The attribute will return this instead #: Default value. The attribute will return this instead
#: of :data:`Unset` if no value has been set. #: of :data:`Unset` if no value has been set.
self.default = default self.default = default
self.complextype = None
def __get__(self, instance, owner): def __get__(self, instance, owner):
if instance is None: if instance is None:
return self return self
@ -231,6 +233,9 @@ class wsattr(object):
self.__set__(instance, Unset) self.__set__(instance, Unset)
def _get_datatype(self): def _get_datatype(self):
if isinstance(self._datatype, tuple):
self._datatype = \
self.complextype().__registry__.resolve_type(self._datatype[0])
if isinstance(self._datatype, weakref.ref): if isinstance(self._datatype, weakref.ref):
return self._datatype() return self._datatype()
return self._datatype return self._datatype
@ -320,6 +325,7 @@ def inspect_class(class_):
attrdef.key = name attrdef.key = name
if attrdef.name is None: if attrdef.name is None:
attrdef.name = name attrdef.name = name
attrdef.complextype = weakref.ref(class_)
attributes.append(attrdef) attributes.append(attrdef)
setattr(class_, name, attrdef) setattr(class_, name, attrdef)
@ -378,6 +384,7 @@ class Registry(object):
class_._wsme_attributes = None class_._wsme_attributes = None
class_._wsme_attributes = inspect_class(class_) class_._wsme_attributes = inspect_class(class_)
class_.__registry__ = self
self.complex_types.append(weakref.ref(class_)) self.complex_types.append(weakref.ref(class_))
def lookup(self, typename): def lookup(self, typename):
@ -402,15 +409,25 @@ class Registry(object):
} }
return type_ return type_
def resolve_references(self):
for ct in self.complex_types:
ct = ct()
for attr in list_attributes(ct):
attr.datatype = self.resolve_type(attr.datatype)
# Default type registry # Default type registry
registry = Registry() registry = Registry()
def register_type(class_): def register_type(class_):
return registry.register(class_) return registry.register(class_)
class BaseMeta(type):
def __new__(cls, name, bases, dct):
r = type.__new__(cls, name, bases, dct)
if bases[0] is object:
return r
if getattr(r, '__registry__', None) is None:
registry.register(r)
else:
r.__registry__.register(r)
return r
class Base(object):
__metaclass__ = BaseMeta