source: main/waeup.sirp/branches/henrik-bootstrap/src/waeup/sirp/schema/field.py @ 10009

Last change on this file since 10009 was 7263, checked in by Henrik Bettermann, 13 years ago

Add tests for applicant batch importer.

Make reg_no filed unique.

Two tests still fail because the importer only accepts the application_number as location field and does not yet search for registration numbers.

  • Property svn:keywords set to Id
File size: 5.0 KB
Line 
1## $Id: field.py 7263 2011-12-04 12:59:40Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""Special fields.
19"""
20from zope.interface import implements
21from zope.schema import TextLine
22from zope.schema.interfaces import (
23    ITextLine, IBaseVocabulary, ISource, IContextSourceBinder, InvalidValue,)
24from zope.schema.vocabulary import (
25    SimpleVocabulary, getVocabularyRegistry, VocabularyRegistryError)
26
27class CustomizableErrorMsg(object):
28    # Still work in progress
29
30    def __init__(self, not_in_vocab=InvalidValue, **kw):
31        self.not_in_vocab = not_in_vocab
32        return
33
34class TextLineChoice(TextLine, CustomizableErrorMsg):
35    """A TextLine field that also accepts sources, vocabs and values.
36
37    You can use this field like a regular zope.schema.TextLine field.
38
39    You can additionally give `source`, `values` or `vocabulary`
40    parameters which will work mainly as with regular
41    zope.schema.Choice fields (hence the name). Different to
42    `Choice` field, these parameters are not mandatory. Leave them
43    out and you have a regular `TextLine` field.
44
45    If you pass a simple source parameter, only those values are
46    allowed which also appear in the source. The source should of
47    course provide string values as suitable for TextLine fields only!
48
49    If, for example you create a TextLineChoice like this:
50
51      name = TextLineChoice(
52        title = u'Some name',
53        values = [u'foo', u'bar']  # unicode allowed only!
54        )
55
56    any formlib form rendering this field will only accept input u'foo'
57    or u'bar'.
58
59    The main advantage of this modified TextLine field is to support
60    contextual sources. That means you can define some
61    IContextSourceBinder component that looks up catalogs or something
62    external else and decide then, whether the entered value of a form
63    is allowed or not.
64
65    The code herein is mainly copied over from
66    zope.schema._field.Choice with slight modifications.
67    """
68    implements(ITextLine)
69
70    def __init__(self, values=None, vocabulary=None, source=None, **kw):
71        if vocabulary is not None:
72            assert (isinstance(vocabulary, basestring)
73                    or IBaseVocabulary.providedBy(vocabulary))
74            assert source is None, (
75                "You cannot specify both source and vocabulary.")
76        elif source is not None:
77            vocabulary = source
78
79        assert values is None or vocabulary is None, (
80               "You cannot specify both values and vocabulary.")
81
82        self.vocabulary = None
83        self.vocabularyName = None
84        if values is not None:
85            self.vocabulary = SimpleVocabulary.fromValues(values)
86        elif isinstance(vocabulary, (unicode, str)):
87            self.vocabularyName = vocabulary
88        elif (ISource.providedBy(vocabulary) or
89              IContextSourceBinder.providedBy(vocabulary)):
90            self.vocabulary = vocabulary
91        super(TextLineChoice, self).__init__(**kw)
92        return
93
94    source = property(lambda self: self.vocabulary)
95
96    def bind(self, object):
97        """See zope.schema._bootstrapinterfaces.IField."""
98        clone = super(TextLineChoice, self).bind(object)
99        # get registered vocabulary if needed:
100        if IContextSourceBinder.providedBy(self.vocabulary):
101            clone.vocabulary = self.vocabulary(object)
102            assert ISource.providedBy(clone.vocabulary)
103        elif clone.vocabulary is None and self.vocabularyName is not None:
104            vr = getVocabularyRegistry()
105            clone.vocabulary = vr.get(object, self.vocabularyName)
106            assert ISource.providedBy(clone.vocabulary)
107        return clone
108
109    def _validate(self, value):
110        """First validate against the regular TextLine rules. Then check any
111        vocabularies/sources.
112        """
113        # Do TextLine validation
114        super(TextLineChoice, self)._validate(value)
115
116        # Check allowed value range (the vocabulary part)
117        vocabulary = self.vocabulary
118        if vocabulary is None and self.vocabularyName is not None:
119            vr = getVocabularyRegistry()
120            try:
121                vocabulary = vr.get(None, self.vocabularyName)
122            except VocabularyRegistryError:
123                raise ValueError("Can't validate value without vocabulary")
124        if vocabulary and value not in vocabulary:
125            raise InvalidValue(value)
126        return
Note: See TracBrowser for help on using the repository browser.