update
This commit is contained in:
139
CHANGES.txt
139
CHANGES.txt
@@ -34,8 +34,10 @@ Features
|
||||
create a bundle of default node behavior. The subclass can define the
|
||||
following methods and attributes: ``preparer``, ``validator``, ``default``,
|
||||
``missing``, ``name``, ``title``, ``description``, ``widget``, and
|
||||
``after_bind``. For example, the older, more imperative style that
|
||||
looked like this still works::
|
||||
``after_bind``.
|
||||
|
||||
For example, the older, more imperative style that looked like this still
|
||||
works, of course::
|
||||
|
||||
from colander import SchemaNode
|
||||
|
||||
@@ -45,19 +47,19 @@ Features
|
||||
title='Ranged Int'
|
||||
)
|
||||
|
||||
But you can alternately now do something like::
|
||||
But you can alternately now do something like this::
|
||||
|
||||
from colander import SchemaNode
|
||||
|
||||
class RangedIntSchemaNode(SchemaNode):
|
||||
validator = colander.range(0, 10)
|
||||
validator = colander.Range(0, 10)
|
||||
default = 10
|
||||
title = 'Ranged Int'
|
||||
|
||||
ranged_int = RangedInt()
|
||||
|
||||
Values that are expected to be callables can be methods of the schemanode
|
||||
subclass instead of plain attributes::
|
||||
Values that are expected to be callables can now alternately be methods of
|
||||
the schemanode subclass instead of plain attributes::
|
||||
|
||||
from colander import SchemaNode
|
||||
|
||||
@@ -71,22 +73,22 @@ Features
|
||||
|
||||
ranged_int = RangedInt()
|
||||
|
||||
When implementing a method value that expects ``node``, ``node`` must be
|
||||
provided in the call signature, even though ``node`` will almost always be
|
||||
the same as ``self``. This is because Colander simply treats the method
|
||||
as another kind of callable, be it a method, or a function, or an instance
|
||||
that has a ``__call__`` method. It doesn't care that it happens to be a
|
||||
method of ``self``, and it needs to support callables that are not
|
||||
methods, so it sends ``node`` in regardless.
|
||||
Note that when implementing a method value such as ``validator`` that
|
||||
expects to receive a ``node`` argument, ``node`` must be provided in the
|
||||
call signature, even though ``node`` will almost always be the same as
|
||||
``self``. This is because Colander simply treats the method as another
|
||||
kind of callable, be it a method, or a function, or an instance that has a
|
||||
``__call__`` method. It doesn't care that it happens to be a method of
|
||||
``self``, and it needs to support callables that are not methods, so it
|
||||
sends ``node`` in regardless.
|
||||
|
||||
Normal inheritance rules apply to class attributes and methods defined in
|
||||
a schemanode subclass. If your schemanode subclass inherits from another
|
||||
schemanode class, your schemanode subclass' methods and class attributes
|
||||
will override the superclass' methods and class attributes.
|
||||
|
||||
Method values that need to be deferred for binding cannot currently be
|
||||
implemented as ``colander.deferred`` callables. For example this will
|
||||
*not* work::
|
||||
You can't currently use *method* definitions as ``colander.deferred``
|
||||
callables. For example this will *not* work::
|
||||
|
||||
from colander import SchemaNode
|
||||
|
||||
@@ -110,9 +112,33 @@ Features
|
||||
|
||||
TypeError: avalidator() takes exactly 3 arguments (2 given)
|
||||
|
||||
Instead of trying to defer methods via a decorator, you can instead use
|
||||
the ``bindings`` attribute of ``self`` to obtain access to the bind
|
||||
parameters within values that are methody::
|
||||
However, if you treat the thing being decorated as a function instead of a
|
||||
method (remove the ``self`` argument from the argument list), it will
|
||||
indeed work)::
|
||||
|
||||
from colander import SchemaNode
|
||||
|
||||
class RangedIntSchemaNode(SchemaNode):
|
||||
default = 10
|
||||
title = 'Ranged Int'
|
||||
|
||||
@colander.deferred
|
||||
def validator(node, kw):
|
||||
request = kw['request']
|
||||
def avalidator(node, cstruct):
|
||||
if not 0 < cstruct < 10:
|
||||
if request.user != 'admin':
|
||||
raise colander.Invalid(node, 'Must be between 0 and 10')
|
||||
return avalidator
|
||||
|
||||
ranged_int = RangedInt()
|
||||
bound_ranged_int = ranged_int.bind(request=request)
|
||||
|
||||
In previous releases of Colander, the only way to defer the computation of
|
||||
values was via the ``colander.deferred`` decorator. In this release,
|
||||
however, you can instead use the ``bindings`` attribute of ``self`` to
|
||||
obtain access to the bind parameters within values that are plain old
|
||||
methods::
|
||||
|
||||
from colander import SchemaNode
|
||||
|
||||
@@ -129,42 +155,18 @@ Features
|
||||
ranged_int = RangedInt()
|
||||
bound_range_int = ranged_int.bind(request=request)
|
||||
|
||||
You can use ``after_bind`` to set attributes of the schemanode that rely
|
||||
on binding variables, such as ``missing`` and ``default``::
|
||||
If the things you're trying to defer aren't callables like ``validator``,
|
||||
but they're instead just plain attributes like ``missing`` or ``default``,
|
||||
instead of using a ``colander.deferred``, you can use ``after_bind`` to
|
||||
set attributes of the schemanode that rely on binding variables::
|
||||
|
||||
from colander import SchemaNode
|
||||
|
||||
class RangedIntSchemaNode(SchemaNode):
|
||||
default = 10
|
||||
title = 'Ranged Int'
|
||||
|
||||
def validator(self, node, cstruct):
|
||||
request = self.bindings['request']
|
||||
if not 0 < cstruct < 10:
|
||||
if request.user != 'admin':
|
||||
raise colander.Invalid(node, 'Must be between 0 and 10')
|
||||
class UserIdSchemaNode(SchemaNode):
|
||||
title = 'User Id'
|
||||
|
||||
def after_bind(self, node, kw):
|
||||
self.request = kw['request']
|
||||
self.default = self.request.user.id
|
||||
|
||||
Non-method values can still be implemented as ``colander.deferred``
|
||||
however::
|
||||
|
||||
from colander import SchemaNode
|
||||
|
||||
def _missing(node, kw):
|
||||
request = kw['request']
|
||||
if request.user.name == 'admin':
|
||||
return 10
|
||||
return 20
|
||||
|
||||
class RangedIntSchemaNode(SchemaNode):
|
||||
default = 10
|
||||
title = 'Ranged Int'
|
||||
missing = colander.deferred(_missing)
|
||||
|
||||
ranged_int = RangedInt()
|
||||
self.default = kw['request'].user.id
|
||||
|
||||
You can override the default values of a schemanode subclass in its
|
||||
constructor::
|
||||
@@ -180,18 +182,41 @@ Features
|
||||
|
||||
In the above example, the validation will be done on 0-20, not 0-10.
|
||||
|
||||
If your schema node names conflict with schema value attribute names, you
|
||||
can work around it with the ``name`` argument to the schema node::
|
||||
If a schema node name conflicts with a schema value attribute name on the
|
||||
same class, you can work around it by giving the schema node a bogus name
|
||||
in the class definition but providing a correct ``name`` argument to the
|
||||
schema node constructor::
|
||||
|
||||
from colander import SchemaNode, Schema
|
||||
|
||||
class TitleNode(SchemaNode):
|
||||
validator = colander.range(0, 10)
|
||||
default = 10
|
||||
|
||||
class SomeSchema(Schema):
|
||||
title = 'Some Schema'
|
||||
thisnamewontmatter = TitleNode(name='title')
|
||||
thisnamewillbeignored = colander.SchemaNode(
|
||||
colander.String(),
|
||||
name='title'
|
||||
)
|
||||
|
||||
Note that such a workaround is only required if the conflicting names are
|
||||
attached to the *exact same* class definition. Colander scrapes off schema
|
||||
node definitions at each class' construction time, so it's not an issue for
|
||||
inherited values. For example::
|
||||
|
||||
from colander import SchemaNode, Schema
|
||||
|
||||
class SomeSchema(Schema):
|
||||
title = colander.SchemaNode(colander.String())
|
||||
|
||||
class AnotherSchema(SomeSchema):
|
||||
title = 'Some Schema'
|
||||
|
||||
schema = AnotherSchema()
|
||||
|
||||
In the above example, even though the ``title = 'Some Schema'`` appears to
|
||||
override the superclass' ``title`` SchemaNode, a ``title`` SchemaNode will
|
||||
indeed be present in the child list of the ``schema`` instance
|
||||
(``schema['title']`` will return the title SchemaNode) and the schema's
|
||||
``title`` attribute will be ``Some Schema`` (schema.title will return
|
||||
``Some Schema``).
|
||||
|
||||
Backwards Incompatibilities
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Reference in New Issue
Block a user