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
|
||||
|
||||
for arg in args:
|
||||
if isinstance(arg, type):
|
||||
if isinstance(arg, type) or isinstance(arg,str):
|
||||
self.types += (arg,)
|
||||
else:
|
||||
raise TypeError('Arguments must be types')
|
||||
raise TypeError('Arguments must be types or strings of type name')
|
||||
|
||||
self._creation_counter = Field._creation_counter
|
||||
Field._creation_counter += 1
|
||||
|
|
@ -278,7 +278,7 @@ class _BaseObjectMeta(type):
|
|||
if new_class.__doc__ is None:
|
||||
new_class.__doc__ = ''
|
||||
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:
|
||||
doc += ' (default: %s)' % field.value
|
||||
new_class.__doc__ += '\n:var %s: %s' % (name, doc)
|
||||
|
|
@ -412,11 +412,35 @@ class BaseObject(object):
|
|||
# match the wanted following types, so we'll
|
||||
# raise ValueError.
|
||||
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(
|
||||
'Value for "%s" needs to be of type %r, not %r' % (
|
||||
name, attr.types, type(value)))
|
||||
name, actual_types, type(value)))
|
||||
attr.value = value
|
||||
|
||||
def __delattr__(self, name):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue