add the possibility to define Field type argument as a string
instead of:
class A:
x = Field("This must be an instance of class B",B)
we could write:
class A:
x = Field("This must be an instance of class B","B")
The use case is when B is a child of A and thus cannot be used
before its definition
Signed-off-by: Pierre Mazière <pierre.maziere@gmx.com>
This commit is contained in:
parent
82f0a27790
commit
178c7cd406
1 changed files with 30 additions and 6 deletions
|
|
@ -184,10 +184,10 @@ class Field(object):
|
||||||
self.doc = doc
|
self.doc = doc
|
||||||
|
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if isinstance(arg, type):
|
if isinstance(arg, type) or isinstance(arg,str):
|
||||||
self.types += (arg,)
|
self.types += (arg,)
|
||||||
else:
|
else:
|
||||||
raise TypeError('Arguments must be types')
|
raise TypeError('Arguments must be types or strings of type name')
|
||||||
|
|
||||||
self._creation_counter = Field._creation_counter
|
self._creation_counter = Field._creation_counter
|
||||||
Field._creation_counter += 1
|
Field._creation_counter += 1
|
||||||
|
|
@ -278,7 +278,7 @@ class _BaseObjectMeta(type):
|
||||||
if new_class.__doc__ is None:
|
if new_class.__doc__ is None:
|
||||||
new_class.__doc__ = ''
|
new_class.__doc__ = ''
|
||||||
for name, field in fields:
|
for name, field in fields:
|
||||||
doc = '(%s) %s' % (', '.join([':class:`%s`' % v.__name__ for v in field.types]), field.doc)
|
doc = '(%s) %s' % (', '.join([':class:`%s`' % v.__name__ if isinstance(v,type) else v for v in field.types]), field.doc)
|
||||||
if field.value is not NotLoaded:
|
if field.value is not NotLoaded:
|
||||||
doc += ' (default: %s)' % field.value
|
doc += ' (default: %s)' % field.value
|
||||||
new_class.__doc__ += '\n:var %s: %s' % (name, doc)
|
new_class.__doc__ += '\n:var %s: %s' % (name, doc)
|
||||||
|
|
@ -412,11 +412,35 @@ class BaseObject(object):
|
||||||
# match the wanted following types, so we'll
|
# match the wanted following types, so we'll
|
||||||
# raise ValueError.
|
# raise ValueError.
|
||||||
pass
|
pass
|
||||||
|
from collections import deque
|
||||||
|
actual_types=()
|
||||||
|
for v in attr.types:
|
||||||
|
if isinstance(v,str):
|
||||||
|
# the following is a (almost) copy/paste from
|
||||||
|
# https://stackoverflow.com/questions/11775460/lexical-cast-from-string-to-type
|
||||||
|
q=deque([object])
|
||||||
|
while q:
|
||||||
|
t=q.popleft()
|
||||||
|
if t.__name__ == v:
|
||||||
|
actual_types+=(t,)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
# keep looking!
|
||||||
|
q.extend(t.__subclasses__())
|
||||||
|
except TypeError:
|
||||||
|
# type.__subclasses__ needs an argument for
|
||||||
|
# whatever reason.
|
||||||
|
if t is type:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
actual_types+=(v,)
|
||||||
|
|
||||||
if not isinstance(value, attr.types) and not empty(value):
|
if not isinstance(value, actual_types) and not empty(value):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
'Value for "%s" needs to be of type %r, not %r' % (
|
'Value for "%s" needs to be of type %r, not %r' % (
|
||||||
name, attr.types, type(value)))
|
name, actual_types, type(value)))
|
||||||
attr.value = value
|
attr.value = value
|
||||||
|
|
||||||
def __delattr__(self, name):
|
def __delattr__(self, name):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue