[Zope3-checkins] SVN: Zope3/trunk/ Add a Decimal field and widget to Zope 3. The field and widget almost exactly

Marius Gedminas marius at pov.lt
Thu Aug 31 17:16:48 EDT 2006


Log message for revision 69907:
  Add a Decimal field and widget to Zope 3.  The field and widget almost exactly
  mirror the existing ones for float.
  
  Also adds security declarations for Decimal.  The reason why I didn't just
  declare Decimal objects to be rocks is that they're not really immutable:
  
    >>> from decimal import Decimal
    >>> d = Decimal("1.24")
    >>> d._exp = -1
    >>> d
    Decimal("12.4")
  
  

Changed:
  U   Zope3/trunk/doc/CHANGES.txt
  U   Zope3/trunk/src/zope/app/form/browser/__init__.py
  U   Zope3/trunk/src/zope/app/form/browser/configure.zcml
  A   Zope3/trunk/src/zope/app/form/browser/ftests/test_decimalwidget.py
  A   Zope3/trunk/src/zope/app/form/browser/tests/test_decimalwidget.py
  U   Zope3/trunk/src/zope/app/form/browser/tests/test_registrations.py
  U   Zope3/trunk/src/zope/app/form/browser/textwidgets.py
  U   Zope3/trunk/src/zope/app/schema/configure.zcml
  U   Zope3/trunk/src/zope/schema/__init__.py
  U   Zope3/trunk/src/zope/schema/_field.py
  U   Zope3/trunk/src/zope/schema/interfaces.py
  A   Zope3/trunk/src/zope/schema/tests/test_decimalfield.py
  U   Zope3/trunk/src/zope/security/checker.py

-=-
Modified: Zope3/trunk/doc/CHANGES.txt
===================================================================
--- Zope3/trunk/doc/CHANGES.txt	2006-08-31 21:01:06 UTC (rev 69906)
+++ Zope3/trunk/doc/CHANGES.txt	2006-08-31 21:16:48 UTC (rev 69907)
@@ -10,6 +10,11 @@
 
     New features
 
+      - Added new Decimal field type to zope.schema (and DecimalWidget in
+        zope.app.form)
+
+      - Added security declarations for decimal.Decimal objects
+
       - Added new Time field type to zope.schema
 
       - IHTTPApplicationRequests emit a new event,

Modified: Zope3/trunk/src/zope/app/form/browser/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/form/browser/__init__.py	2006-08-31 21:01:06 UTC (rev 69906)
+++ Zope3/trunk/src/zope/app/form/browser/__init__.py	2006-08-31 21:16:48 UTC (rev 69907)
@@ -25,6 +25,7 @@
 from zope.app.form.browser.textwidgets import PasswordWidget, FileWidget
 from zope.app.form.browser.textwidgets import ASCIIWidget, ASCIIAreaWidget
 from zope.app.form.browser.textwidgets import IntWidget, FloatWidget
+from zope.app.form.browser.textwidgets import DecimalWidget
 from zope.app.form.browser.textwidgets import DatetimeWidget, DateWidget
 from zope.app.form.browser.textwidgets import DatetimeI18nWidget
 from zope.app.form.browser.textwidgets import DateI18nWidget

Modified: Zope3/trunk/src/zope/app/form/browser/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/form/browser/configure.zcml	2006-08-31 21:01:06 UTC (rev 69906)
+++ Zope3/trunk/src/zope/app/form/browser/configure.zcml	2006-08-31 21:16:48 UTC (rev 69907)
@@ -202,6 +202,22 @@
 
   <view
       type="zope.publisher.interfaces.browser.IBrowserRequest"
+      for="zope.schema.interfaces.IDecimal"
+      provides="zope.app.form.interfaces.IInputWidget"
+      factory=".DecimalWidget"
+      permission="zope.Public"
+      />
+
+  <view
+      type="zope.publisher.interfaces.browser.IBrowserRequest"
+      for="zope.schema.interfaces.IDecimal"
+      provides="zope.app.form.interfaces.IDisplayWidget"
+      factory=".UnicodeDisplayWidget"
+      permission="zope.Public"
+      />
+
+  <view
+      type="zope.publisher.interfaces.browser.IBrowserRequest"
       for="zope.schema.interfaces.IDatetime"
       provides="zope.app.form.interfaces.IInputWidget"
       factory=".DatetimeWidget"

Added: Zope3/trunk/src/zope/app/form/browser/ftests/test_decimalwidget.py
===================================================================
--- Zope3/trunk/src/zope/app/form/browser/ftests/test_decimalwidget.py	2006-08-31 21:01:06 UTC (rev 69906)
+++ Zope3/trunk/src/zope/app/form/browser/ftests/test_decimalwidget.py	2006-08-31 21:16:48 UTC (rev 69907)
@@ -0,0 +1,233 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Decimal Widget Functional Tests
+
+$Id$
+"""
+import unittest
+import decimal
+import transaction
+from persistent import Persistent
+
+import zope.security.checker
+from zope.interface import Interface, implements
+from zope.traversing.api import traverse
+
+from zope.schema import Decimal, Choice
+from zope.app.form.browser.ftests.support import *
+from zope.app.testing.functional import BrowserTestCase
+
+class IDecimalTest(Interface):
+
+    f1 = Decimal(
+        required=False,
+        min=decimal.Decimal("1.1"),
+        max=decimal.Decimal("10.1"))
+
+    f2 = Decimal(
+        required=False)
+
+    f3 = Choice(
+        required=True,
+        values=(decimal.Decimal("0.0"), decimal.Decimal("1.1"),
+                decimal.Decimal("2.1"), decimal.Decimal("3.1"),
+                decimal.Decimal("5.1"), decimal.Decimal("7.1"),
+                decimal.Decimal("11.1")),
+        missing_value=0)
+
+    f4 = Decimal(readonly=True)
+
+
+class DecimalTest(Persistent):
+
+    implements(IDecimalTest)
+
+    def __init__(self):
+        self.f1 = None
+        self.f2 = decimal.Decimal("1.1")
+        self.f3 = decimal.Decimal("2.1")
+        self.f4 = decimal.Decimal("17.2")
+
+
+class Test(BrowserTestCase):
+
+    def setUp(self):
+        BrowserTestCase.setUp(self)
+        registerEditForm(IDecimalTest)
+        defineSecurity(DecimalTest, IDecimalTest)
+
+    def test_display_editform(self):
+        self.getRootFolder()['test'] = DecimalTest()
+        transaction.commit()
+
+        # display edit view
+        response = self.publish('/test/edit.html')
+        self.assertEqual(response.getStatus(), 200)
+
+        # f1 and f2 should be displayed in text fields
+        self.assert_(patternExists(
+            '<input .* name="field.f1".* value="".*>', response.getBody()))
+        self.assert_(patternExists(
+            '<input .* name="field.f2".* value="1.1".*>', response.getBody()))
+
+        # f3 should be in a dropdown
+        self.assert_(patternExists(
+            '<select .*name="field.f3".*>', response.getBody()))
+        self.assert_(patternExists(
+            '<option selected="selected" value="2.1">2.1</option>',
+            response.getBody()))
+
+        # f4 should be rendered by the display widget
+        self.assert_(patternExists(
+            '<div class="field">17.2</div>', response.getBody()))
+
+
+    def test_submit_editform(self):
+        self.getRootFolder()['test'] = DecimalTest()
+        transaction.commit()
+
+        # submit edit view
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : '1.123',
+            'field.f2' : '2.23456789012345',
+            'field.f3' : '11.1' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+
+        # check new values in object
+        object = traverse(self.getRootFolder(), 'test')
+        self.assertEqual(object.f1, decimal.Decimal("1.123"))
+        self.assertEqual(object.f2, decimal.Decimal("2.23456789012345"))
+        self.assertEqual(object.f3, decimal.Decimal("11.1"))
+
+
+    def test_missing_value(self):
+        self.getRootFolder()['test'] = DecimalTest()
+        transaction.commit()
+
+        # submit missing values for f2 and f3
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : '',
+            'field.f2' : '',
+            'field.f3' : '1.1' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+
+        # check new values in object
+        object = traverse(self.getRootFolder(), 'test')
+        self.assertEqual(object.f1, None)
+        self.assertEqual(object.f2, None) # None is default missing_value
+        self.assertEqual(object.f3, decimal.Decimal("1.1"))  # 0 is from f3.missing_value=0
+
+
+    def test_required_validation(self):
+        self.getRootFolder()['test'] = DecimalTest()
+        transaction.commit()
+
+        # submit missing values for required field f1
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : '',
+            'field.f2' : '',
+            'field.f3' : '' })
+        self.assertEqual(response.getStatus(), 200)
+
+        # confirm error msgs
+        self.assert_(not missingInputErrorExists('f1', response.getBody()))
+        self.assert_(not missingInputErrorExists('f2', response.getBody()))
+        self.assert_(missingInputErrorExists('f3', response.getBody()))
+
+
+    def test_invalid_allowed_value(self):
+        self.getRootFolder()['test'] = DecimalTest()
+        transaction.commit()
+
+        # submit a value for f3 that isn't allowed
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f3' : '10000' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(invalidValueErrorExists('f3', response.getBody()))
+
+
+    def test_min_max_validation(self):
+        self.getRootFolder()['test'] = DecimalTest()
+        transaction.commit()
+
+        # submit value for f1 that is too low
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : '-1' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(validationErrorExists('f1', 'Value is too small',
+            response.getBody()))
+
+        # submit value for f1 that is too high
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : '1000.2' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(validationErrorExists('f1', 'Value is too big',
+            response.getBody()))
+
+
+    def test_omitted_value(self):
+        self.getRootFolder()['test'] = DecimalTest()
+        transaction.commit()
+
+        # confirm default values
+        object = traverse(self.getRootFolder(), 'test')
+        self.assert_(object.f1 is None)
+        self.assertEqual(object.f2, decimal.Decimal("1.1"))
+        self.assertEqual(object.f3, decimal.Decimal("2.1"))
+
+        # submit change with only f2 present -- note that required
+        # field f1 is omitted, which should not cause a validation error
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f2' : '' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(updatedMsgExists(response.getBody()))
+
+        # check new value in object
+        object = traverse(self.getRootFolder(), 'test')
+        self.assert_(object.f1 is None)
+        self.assert_(object.f2 is None)
+        self.assertEqual(object.f3, decimal.Decimal("2.1"))
+
+
+    def test_conversion(self):
+        self.getRootFolder()['test'] = DecimalTest()
+        transaction.commit()
+
+        # submit value for f1 that cannot be convert to an float
+        response = self.publish('/test/edit.html', form={
+            'UPDATE_SUBMIT' : '',
+            'field.f1' : 'foo' })
+        self.assertEqual(response.getStatus(), 200)
+        self.assert_(validationErrorExists(
+            'f1',
+            'Invalid decimal data', response.getBody()))
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(Test))
+    return suite
+
+if __name__=='__main__':
+    unittest.main(defaultTest='test_suite')
+


Property changes on: Zope3/trunk/src/zope/app/form/browser/ftests/test_decimalwidget.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: Zope3/trunk/src/zope/app/form/browser/tests/test_decimalwidget.py
===================================================================
--- Zope3/trunk/src/zope/app/form/browser/tests/test_decimalwidget.py	2006-08-31 21:01:06 UTC (rev 69906)
+++ Zope3/trunk/src/zope/app/form/browser/tests/test_decimalwidget.py	2006-08-31 21:16:48 UTC (rev 69907)
@@ -0,0 +1,66 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Decimal Widget tests
+
+$Id$
+"""
+import unittest
+import decimal
+from zope.testing import doctest
+from zope.app.form.browser.tests.test_browserwidget import SimpleInputWidgetTest
+from zope.app.form.interfaces import IInputWidget
+from zope.app.form.browser import DecimalWidget
+from zope.app.form.interfaces import ConversionError, WidgetInputError
+from zope.interface.verify import verifyClass
+
+from zope.schema import Decimal
+
+
+class DecimalWidgetTest(SimpleInputWidgetTest):
+    """Documents and tests the float widget.
+        
+        >>> verifyClass(IInputWidget, DecimalWidget)
+        True
+    """
+
+    _FieldFactory = Decimal
+    _WidgetFactory = DecimalWidget
+
+    def test_hasInput(self):
+        del self._widget.request.form['field.foo']
+        self.failIf(self._widget.hasInput())
+        # widget has input, even if input is an empty string
+        self._widget.request.form['field.foo'] = u''
+        self.failUnless(self._widget.hasInput())
+        self._widget.request.form['field.foo'] = u'123'
+        self.failUnless(self._widget.hasInput())
+
+    def test_getInputValue(self):
+        self._widget.request.form['field.foo'] = u''
+        self.assertRaises(WidgetInputError, self._widget.getInputValue)
+        self._widget.request.form['field.foo'] = u'123.45'
+        self.assertEquals(self._widget.getInputValue(),
+                          decimal.Decimal("123.45"))
+        self._widget.request.form['field.foo'] = u'abc'
+        self.assertRaises(ConversionError, self._widget.getInputValue)
+
+
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite(DecimalWidgetTest),
+        doctest.DocTestSuite(),
+        ))
+
+if __name__=='__main__':
+    unittest.main(defaultTest='test_suite')


Property changes on: Zope3/trunk/src/zope/app/form/browser/tests/test_decimalwidget.py
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: Zope3/trunk/src/zope/app/form/browser/tests/test_registrations.py
===================================================================
--- Zope3/trunk/src/zope/app/form/browser/tests/test_registrations.py	2006-08-31 21:01:06 UTC (rev 69906)
+++ Zope3/trunk/src/zope/app/form/browser/tests/test_registrations.py	2006-08-31 21:16:48 UTC (rev 69907)
@@ -134,6 +134,13 @@
         >>> widget = zapi.getMultiAdapter((field, request), IInputWidget)
         >>> isinstance(widget, FloatWidget)
         True
+
+    IDecimal, IInputWidget -> DecimalWidget
+    
+        >>> field = fields.Decimal()
+        >>> widget = zapi.getMultiAdapter((field, request), IInputWidget)
+        >>> isinstance(widget, DecimalWidget)
+        True
         
     IDatetime, IInputWidget -> DatetimeWidget
     

Modified: Zope3/trunk/src/zope/app/form/browser/textwidgets.py
===================================================================
--- Zope3/trunk/src/zope/app/form/browser/textwidgets.py	2006-08-31 21:01:06 UTC (rev 69906)
+++ Zope3/trunk/src/zope/app/form/browser/textwidgets.py	2006-08-31 21:16:48 UTC (rev 69907)
@@ -17,6 +17,7 @@
 """
 __docformat__ = 'restructuredtext'
 
+import decimal
 from xml.sax import saxutils
 from zope.interface import implements
 from zope.datetime import parseDatetimetz
@@ -485,6 +486,26 @@
             except ValueError, v:
                 raise ConversionError(_("Invalid floating point data"), v)
 
+class DecimalWidget(TextWidget):
+    implements(IInputWidget)
+    displayWidth = 10
+
+    def _toFieldValue(self, input):
+        if input == self._missing:
+            return self.context.missing_value
+        else:
+            try:
+                return decimal.Decimal(input)
+            except decimal.InvalidOperation, v:
+                raise ConversionError(_("Invalid decimal data"), v)
+
+    def _toFormValue(self, value):
+        if value == self.context.missing_value:
+            value = self._missing
+        else:
+            return unicode(value)
+
+
 class DatetimeWidget(TextWidget):
     """Datetime entry widget."""
 

Modified: Zope3/trunk/src/zope/app/schema/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/schema/configure.zcml	2006-08-31 21:01:06 UTC (rev 69906)
+++ Zope3/trunk/src/zope/app/schema/configure.zcml	2006-08-31 21:16:48 UTC (rev 69907)
@@ -170,6 +170,18 @@
 
   </class>
 
+  <class class="zope.schema.Decimal">
+
+    <factory
+	id="zope.schema.Decimal"
+	title="Decimal Field"
+	description="Decimal Field" />
+
+    <require like_class="zope.schema.Orderable" />
+    <require like_class="zope.schema.Field" />
+
+  </class>
+
   <class class="zope.schema.Tuple">
 
     <factory

Modified: Zope3/trunk/src/zope/schema/__init__.py
===================================================================
--- Zope3/trunk/src/zope/schema/__init__.py	2006-08-31 21:01:06 UTC (rev 69906)
+++ Zope3/trunk/src/zope/schema/__init__.py	2006-08-31 21:16:48 UTC (rev 69907)
@@ -18,7 +18,7 @@
 from zope.schema._field import Field, Container, Iterable, Orderable
 from zope.schema._field import MinMaxLen, Choice
 from zope.schema._field import Bytes, ASCII, BytesLine, ASCIILine
-from zope.schema._field import Text, TextLine, Bool, Int, Float
+from zope.schema._field import Text, TextLine, Bool, Int, Float, Decimal
 from zope.schema._field import Tuple, List, Set, FrozenSet
 from zope.schema._field import Password, Dict, Datetime, Date, Timedelta
 from zope.schema._field import Time, SourceText

Modified: Zope3/trunk/src/zope/schema/_field.py
===================================================================
--- Zope3/trunk/src/zope/schema/_field.py	2006-08-31 21:01:06 UTC (rev 69906)
+++ Zope3/trunk/src/zope/schema/_field.py	2006-08-31 21:16:48 UTC (rev 69907)
@@ -19,6 +19,7 @@
 __docformat__ = 'restructuredtext'
 
 import re
+import decimal
 from datetime import datetime, date, timedelta, time
 from sets import Set as SetType
 
@@ -33,7 +34,7 @@
 from zope.schema.interfaces import IBool, IInt, IFloat, IDatetime, IFrozenSet
 from zope.schema.interfaces import IChoice, ITuple, IList, ISet, IDict
 from zope.schema.interfaces import IPassword, IObject, IDate, ITimedelta
-from zope.schema.interfaces import ITime
+from zope.schema.interfaces import ITime, IDecimal
 from zope.schema.interfaces import IURI, IId, IFromUnicode
 from zope.schema.interfaces import ISource, IBaseVocabulary
 from zope.schema.interfaces import IContextSourceBinder
@@ -167,6 +168,31 @@
         self.validate(v)
         return v
 
+class Decimal(Orderable, Field):
+    __doc__ = IDecimal.__doc__
+    implements(IDecimal, IFromUnicode)
+    _type = decimal.Decimal
+
+    def __init__(self, *args, **kw):
+        super(Decimal, self).__init__(*args, **kw)
+
+    def fromUnicode(self, u):
+        """
+        >>> f = Decimal()
+        >>> f.fromUnicode("1.25")
+        Decimal("1.25")
+        >>> f.fromUnicode("1.25.6")
+        Traceback (most recent call last):
+        ...
+        ValueError: invalid literal for Decimal(): 1.25.6
+        """
+        try:
+            v = decimal.Decimal(u)
+        except decimal.InvalidOperation:
+            raise ValueError('invalid literal for Decimal(): %s' % u)
+        self.validate(v)
+        return v
+
 class Datetime(Orderable, Field):
     __doc__ = IDatetime.__doc__
     implements(IDatetime)

Modified: Zope3/trunk/src/zope/schema/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/schema/interfaces.py	2006-08-31 21:01:06 UTC (rev 69906)
+++ Zope3/trunk/src/zope/schema/interfaces.py	2006-08-31 21:16:48 UTC (rev 69907)
@@ -324,6 +324,9 @@
 class IFloat(IMinMax, IField):
     u"""Field containing a Float."""
 
+class IDecimal(IMinMax, IField):
+    u"""Field containing a Decimal."""
+
 class IDatetime(IMinMax, IField):
     u"""Field containing a DateTime."""
 

Added: Zope3/trunk/src/zope/schema/tests/test_decimalfield.py
===================================================================
--- Zope3/trunk/src/zope/schema/tests/test_decimalfield.py	2006-08-31 21:01:06 UTC (rev 69906)
+++ Zope3/trunk/src/zope/schema/tests/test_decimalfield.py	2006-08-31 21:16:48 UTC (rev 69907)
@@ -0,0 +1,90 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Decimal field tests
+
+$Id$
+"""
+import decimal
+from unittest import main, makeSuite
+from zope.schema import Decimal
+from zope.schema.interfaces import RequiredMissing, InvalidValue
+from zope.schema.interfaces import TooSmall, TooBig
+from zope.schema.tests.test_field import FieldTestBase
+
+class DecimalTest(FieldTestBase):
+    """Test the Decimal Field."""
+
+    _Field_Factory = Decimal
+
+    def testValidate(self):
+        field = self._Field_Factory(title=u'Decimal field', description=u'',
+                                    readonly=False, required=False)
+        field.validate(None)
+        field.validate(decimal.Decimal("10.0"))
+        field.validate(decimal.Decimal("0.93"))
+        field.validate(decimal.Decimal("1000.0003"))
+
+    def testValidateRequired(self):
+        field = self._Field_Factory(title=u'Decimal field', description=u'',
+                                    readonly=False, required=True)
+        field.validate(decimal.Decimal("10.0"))
+        field.validate(decimal.Decimal("0.93"))
+        field.validate(decimal.Decimal("1000.0003"))
+
+        self.assertRaises(RequiredMissing, field.validate, None)
+
+    def testValidateMin(self):
+        field = self._Field_Factory(title=u'Decimal field', description=u'',
+                                    readonly=False, required=False,
+                                    min=decimal.Decimal("10.5"))
+        field.validate(None)
+        field.validate(decimal.Decimal("10.6"))
+        field.validate(decimal.Decimal("20.2"))
+
+        self.assertRaises(TooSmall, field.validate, decimal.Decimal("-9.0"))
+        self.assertRaises(TooSmall, field.validate, decimal.Decimal("10.4"))
+
+    def testValidateMax(self):
+        field = self._Field_Factory(title=u'Decimal field', description=u'',
+                                    readonly=False, required=False,
+                                    max=decimal.Decimal("10.5"))
+        field.validate(None)
+        field.validate(decimal.Decimal("5.3"))
+        field.validate(decimal.Decimal("-9.1"))
+
+        self.assertRaises(TooBig, field.validate, decimal.Decimal("10.51"))
+        self.assertRaises(TooBig, field.validate, decimal.Decimal("20.7"))
+
+    def testValidateMinAndMax(self):
+        field = self._Field_Factory(title=u'Decimal field', description=u'',
+                                    readonly=False, required=False,
+                                    min=decimal.Decimal("-0.6"),
+                                    max=decimal.Decimal("10.1"))
+        field.validate(None)
+        field.validate(decimal.Decimal("0.0"))
+        field.validate(decimal.Decimal("-0.03"))
+        field.validate(decimal.Decimal("10.0001"))
+
+        self.assertRaises(TooSmall, field.validate, decimal.Decimal("-10.0"))
+        self.assertRaises(TooSmall, field.validate, decimal.Decimal("-1.6"))
+        self.assertRaises(TooBig, field.validate, decimal.Decimal("11.45"))
+        self.assertRaises(TooBig, field.validate, decimal.Decimal("20.02"))
+
+
+def test_suite():
+    suite = makeSuite(DecimalTest)
+    return suite
+
+if __name__ == '__main__':
+    main(defaultTest='test_suite')


Property changes on: Zope3/trunk/src/zope/schema/tests/test_decimalfield.py
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: Zope3/trunk/src/zope/security/checker.py
===================================================================
--- Zope3/trunk/src/zope/security/checker.py	2006-08-31 21:01:06 UTC (rev 69906)
+++ Zope3/trunk/src/zope/security/checker.py	2006-08-31 21:16:48 UTC (rev 69907)
@@ -30,6 +30,7 @@
 import sets
 import types
 import datetime
+import decimal
 import pytz
 import weakref
 
@@ -667,6 +668,20 @@
     sets.ImmutableSet: _setChecker,
     set: _setChecker,
     frozenset: _setChecker,
+    decimal.Decimal: NamesChecker(['__nonzero__', '__cmp__', '__eq__',
+                                   '__ne__', 'compare', '__hash__',
+                                   'as_tuple', '__str__', 'to_eng_string',
+                                   '__neg__', '__pos__', '__abs__',
+                                   '__add__', '__radd__', '__sub__',
+                                   '__rsub__', '__mul__', '__rmul__',
+                                   '__div__', '__rdiv__', '__rtruediv__',
+                                   '__divmod__', '__rdivmod__', '__mod__',
+                                   '__rmod__', 'remainder_near',
+                                   '__floordiv__', '__rfloordiv__',
+                                   '__float__', '__int__', '__long__',
+                                   '__pow__', '__rpow__', 'normalize',
+                                   'quantize', 'same_quantum', 'to_integral',
+                                   'sqrt', 'max', 'min', 'adjusted']),
 
     # YAGNI: () a rock
     tuple: NamesChecker(['__getitem__', '__getslice__', '__add__', '__radd__',



More information about the Zope3-Checkins mailing list