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
	 Chris McDonough
					Chris McDonough