added URLField, DecimalField, tests.

This commit is contained in:
blackbrrr 2010-01-14 11:32:28 -06:00
parent 1cdeb8130d
commit 5f84d6f8f8
3 changed files with 114 additions and 16 deletions

View File

@ -5,11 +5,22 @@ from connection import _get_db
import re import re
import pymongo import pymongo
import datetime import datetime
import decimal
__all__ = ['StringField', 'IntField', 'FloatField', 'BooleanField', __all__ = ['StringField', 'IntField', 'FloatField', 'BooleanField',
'DateTimeField', 'EmbeddedDocumentField', 'ListField', 'DateTimeField', 'EmbeddedDocumentField', 'ListField',
'ObjectIdField', 'ReferenceField', 'ValidationError'] 'ObjectIdField', 'ReferenceField', 'ValidationError',
'URLField', 'DecimalField']
URL_REGEX = re.compile(
r'^https?://'
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|'
r'localhost|'
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
r'(?::\d+)?'
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
class StringField(BaseField): class StringField(BaseField):
@ -38,6 +49,25 @@ class StringField(BaseField):
return None return None
class URLField(BaseField):
"""A field that validates input as a URL.
"""
def __init__(self, verify_exists=True, **kwargs):
self.verify_exists = verify_exists
super(URLField, self).__init__(**kwargs)
def validate(self, value):
import urllib2
if self.verify_exists:
try:
request = urllib2.Request(value)
response = urllib2.urlopen(request)
except Exception, e:
raise ValidationError('This URL appears to be invalid: %s' % e)
class IntField(BaseField): class IntField(BaseField):
"""An integer field. """An integer field.
""" """
@ -50,7 +80,10 @@ class IntField(BaseField):
return int(value) return int(value)
def validate(self, value): def validate(self, value):
assert isinstance(value, (int, long)) try:
value = int(value)
except:
raise ValidationError('%s could not be converted to int' % value)
if self.min_value is not None and value < self.min_value: if self.min_value is not None and value < self.min_value:
raise ValidationError('Integer value is too small') raise ValidationError('Integer value is too small')
@ -80,6 +113,35 @@ class FloatField(BaseField):
raise ValidationError('Float value is too large') raise ValidationError('Float value is too large')
class DecimalField(BaseField):
"""A fixed-point decimal number field.
"""
def __init__(self, min_value=None, max_value=None, **kwargs):
self.min_value, self.max_value = min_value, max_value
super(DecimalField, self).__init__(**kwargs)
def to_python(self, value):
if not isinstance(value, basestring):
value = unicode(value)
return decimal.Decimal(value)
def validate(self, value):
if not isinstance(value, decimal.Decimal):
if not isinstance(value, basestring):
value = str(value)
try:
value = decimal.Decimal(value)
except Exception, exc:
raise ValidationError('Could not convert to decimal: %s' % exc)
if self.min_value is not None and value < self.min_value:
raise ValidationError('Decimal value is too small')
if self.max_value is not None and vale > self.max_value:
raise ValidationError('Decimal value is too large')
class BooleanField(BaseField): class BooleanField(BaseField):
"""A boolean field type. """A boolean field type.

View File

@ -399,7 +399,7 @@ class DocumentTest(unittest.TestCase):
person_obj = collection.find_one({'name': 'Test User'}) person_obj = collection.find_one({'name': 'Test User'})
self.assertEqual(person_obj['name'], 'Test User') self.assertEqual(person_obj['name'], 'Test User')
self.assertEqual(person_obj['age'], 30) self.assertEqual(person_obj['age'], 30)
self.assertEqual(str(person_obj['_id']), person.id) self.assertEqual(person_obj['_id'], person.id)
def test_delete(self): def test_delete(self):
"""Ensure that document may be deleted using the delete method. """Ensure that document may be deleted using the delete method.

View File

@ -1,5 +1,6 @@
import unittest import unittest
import datetime import datetime
from decimal import Decimal
from mongoengine import * from mongoengine import *
from mongoengine.connection import _get_db from mongoengine.connection import _get_db
@ -79,6 +80,23 @@ class FieldTest(unittest.TestCase):
person.name = 'Shorter name' person.name = 'Shorter name'
person.validate() person.validate()
def test_url_validation(self):
"""Ensure that invalid URLs cannot be assigned to URL fields.
"""
class Person(Document):
name = StringField()
personal_blog = URLField()
person = Person()
person.name = "Guido van Rossum"
person.personal_blog = "pep8 or bust!"
self.assertRaises(ValidationError, person.validate)
# swap in a real URL
person.personal_blog = "http://neopythonic.blogspot.com/"
person.validate()
def test_int_validation(self): def test_int_validation(self):
"""Ensure that invalid values cannot be assigned to int fields. """Ensure that invalid values cannot be assigned to int fields.
""" """
@ -113,6 +131,24 @@ class FieldTest(unittest.TestCase):
person.height = 4.0 person.height = 4.0
self.assertRaises(ValidationError, person.validate) self.assertRaises(ValidationError, person.validate)
def test_decimal_validation(self):
"""Ensure that invalid values cannot be assigned to decimal fields.
"""
class AlbumReview(Document):
score = DecimalField()
review = AlbumReview()
review.score = "8.7"
review.validate()
review.score = Decimal("10.0")
review.validate()
# implicit conversion from float to string
review.score = 3.14
review.validate()
review.score = "it stinks!"
self.assertRaises(ValidationError, review.validate)
def test_boolean_validation(self): def test_boolean_validation(self):
"""Ensure that invalid values cannot be assigned to boolean fields. """Ensure that invalid values cannot be assigned to boolean fields.
""" """