Python 2.5 and 3.1 support confirmed

This commit is contained in:
Ross Lawley 2012-08-07 13:07:51 +01:00
parent 44bd8cb85b
commit dd4af2df81
12 changed files with 68 additions and 55 deletions

View File

@ -1,8 +1,10 @@
# http://travis-ci.org/#!/MongoEngine/mongoengine
language: python
python:
- 2.5
- 2.6
- 2.7
- 3.1
- 3.2
install:
- if [[ $TRAVIS_PYTHON_VERSION == '2.'* ]]; then sudo apt-get install zlib1g zlib1g-dev; fi

View File

@ -10,7 +10,7 @@ from queryset import DoesNotExist, MultipleObjectsReturned
from queryset import DO_NOTHING
from mongoengine import signals
from mongoengine.python3_support import PY3, txt_type
from mongoengine.python_support import PY3, PY25, txt_type
import pymongo
from bson import ObjectId
@ -894,10 +894,8 @@ class BaseDocument(object):
if not is_list and '_cls' in value:
cls = get_document(value['_cls'])
# Make keys str instead of unicode
for key,val in value.items():
del value[key]
value[str(key)] = val
if PY25:
value = dict([(str(k), v) for k, v in value.items()])
value = cls(**value)
value._dynamic = True
value._changed_fields = []
@ -1019,12 +1017,9 @@ class BaseDocument(object):
raise InvalidDocumentError("""
Invalid data to create a `%s` instance.\n%s""".strip() % (cls._class_name, errors))
# Make all keys str instead of unicode
for key,val in data.items():
del data[key]
data[str(key)] = val
if PY25:
data = dict([(str(k), v) for k, v in data.items()])
obj = cls(**data)
obj._changed_fields = changed_fields
obj._created = False
return obj

View File

@ -1,7 +1,7 @@
#coding: utf-8
from nose.plugins.skip import SkipTest
from mongoengine.python3_support import PY3
from mongoengine.python_support import PY3
from mongoengine import connect
try:
@ -18,7 +18,7 @@ except Exception as err:
class MongoTestCase(TestCase):
def setUp(self):
if PY3:
raise SkipTest('django does not have Python 3 support')

View File

@ -10,8 +10,8 @@ from operator import itemgetter
import gridfs
from bson import Binary, DBRef, SON, ObjectId
from mongoengine.python3_support import (PY3, bin_type,
txt_type, str_types, StringIO)
from mongoengine.python_support import (PY3, bin_type, txt_type,
str_types, StringIO)
from base import (BaseField, ComplexBaseField, ObjectIdField,
ValidationError, get_document, BaseDocument)
from queryset import DO_NOTHING, QuerySet
@ -840,13 +840,20 @@ class BinaryField(BaseField):
self.max_bytes = max_bytes
super(BinaryField, self).__init__(**kwargs)
def __set__(self, instance, value):
"""Handle bytearrays in python 3.1"""
if PY3 and isinstance(value, bytearray):
value = bin_type(value)
return super(BinaryField, self).__set__(instance, value)
def to_mongo(self, value):
return Binary(value)
def validate(self, value):
if not isinstance(value, (bin_type, txt_type, Binary)):
self.error("BinaryField only accepts instances of "
"(%s, %s, Binary)" % (bin_type.__name__,txt_type.__name__))
"(%s, %s, Binary)" % (
bin_type.__name__, txt_type.__name__))
if self.max_bytes is not None and len(value) > self.max_bytes:
self.error('Binary value is too long')
@ -1270,9 +1277,9 @@ class SequenceField(IntField):
"""
Generate and Increment the counter
"""
sequence_id = "%s.%s"%(self.owner_document._get_collection_name(),
self.name)
collection = get_db(alias = self.db_alias )[self.collection_name]
sequence_id = "%s.%s" % (self.owner_document._get_collection_name(),
self.name)
collection = get_db(alias=self.db_alias)[self.collection_name]
counter = collection.find_and_modify(query={"_id": sequence_id},
update={"$inc": {"next": 1}},
new=True,

View File

@ -1,13 +1,14 @@
"""Helper functions and types to aid with Python 3 support."""
"""Helper functions and types to aid with Python 2.5 - 3 support."""
import sys
PY3 = sys.version_info[0] == 3
PY25 = sys.version_info[:2] == (2, 5)
if PY3:
import codecs
from io import BytesIO as StringIO
# return s converted to binary. b('test') should be equivalent to b'test'
# return s converted to binary. b('test') should be equivalent to b'test'
def b(s):
return codecs.latin_1_encode(s)[0]
@ -24,6 +25,19 @@ else:
return s
bin_type = str
txt_type = unicode
txt_type = unicode
str_types = (bin_type, txt_type)
if PY25:
def product(*args, **kwds):
pools = map(tuple, args) * kwds.get('repeat', 1)
result = [[]]
for pool in pools:
result = [x + [y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
reduce = reduce
else:
from itertools import product
from functools import reduce

View File

@ -3,9 +3,9 @@ import re
import copy
import itertools
import operator
import functools
import sys
from functools import partial
from mongoengine.python_support import product, reduce
import pymongo
from bson.code import Code
@ -15,18 +15,6 @@ from mongoengine import signals
__all__ = ['queryset_manager', 'Q', 'InvalidQueryError',
'DO_NOTHING', 'NULLIFY', 'CASCADE', 'DENY', 'PULL']
if sys.version_info < (2,6,0):
def product(*args, **kwds):
pools = map(tuple, args) * kwds.get('repeat', 1)
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
else:
from itertools import product
from functools import reduce
# The maximum number of items to display in a QuerySet.__repr__
REPR_OUTPUT_SIZE = 20

View File

@ -6,6 +6,5 @@ detailed-errors = 1
#cover-html = 1
#cover-html-dir = ../htmlcov
#cover-package = mongoengine
where = tests
py3where = build
#tests = test_bugfix.py
where = tests

View File

@ -1,6 +1,6 @@
from setuptools import setup, find_packages
import os
import sys
from setuptools import setup, find_packages
# Hack to silence atexit traceback in newer python versions
try:
@ -16,6 +16,7 @@ try:
except:
pass
def get_version(version_tuple):
version = '%s.%s' % (version_tuple[0], version_tuple[1])
if version_tuple[2]:
@ -38,7 +39,13 @@ CLASSIFIERS = [
'Operating System :: OS Independent',
'Programming Language :: Python',
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.5",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.1",
"Programming Language :: Python :: 3.2",
"Programming Language :: Python :: Implementation :: CPython",
'Topic :: Database',
'Topic :: Software Development :: Libraries :: Python Modules',
]

View File

@ -1,7 +1,7 @@
from __future__ import with_statement
import unittest
from nose.plugins.skip import SkipTest
from mongoengine.python3_support import PY3
from mongoengine.python_support import PY3
from mongoengine import *
try:

View File

@ -43,7 +43,7 @@ class DocumentTest(unittest.TestCase):
self.warning_list = []
showwarning_default = warnings.showwarning
def append_to_warning_list(message,category, *args):
self.warning_list.append({"message":message, "category":category})
@ -55,7 +55,7 @@ class DocumentTest(unittest.TestCase):
class InheritedClass(SimpleBase):
b = IntField()
# restore default handling of warnings
warnings.showwarning = showwarning_default
@ -150,7 +150,7 @@ class DocumentTest(unittest.TestCase):
def append_to_warning_list(message, category, *args):
self.warning_list.append({'message':message, 'category':category})
# add warnings to self.warning_list instead of stderr
warnings.showwarning = append_to_warning_list
warnings.simplefilter("always")
@ -209,7 +209,6 @@ class DocumentTest(unittest.TestCase):
}
self.assertEqual(Dog._superclasses, dog_superclasses)
def test_external_superclasses(self):
"""Ensure that the correct list of sub and super classes is assembled.
when importing part of the model
@ -568,22 +567,22 @@ class DocumentTest(unittest.TestCase):
class Drinker(Document):
drink = GenericReferenceField()
try:
warnings.simplefilter("error")
class AcloholicDrink(Drink):
meta = {'collection': 'booze'}
except SyntaxWarning, w:
warnings.simplefilter("ignore")
class AlcoholicDrink(Drink):
meta = {'collection': 'booze'}
else:
raise AssertionError("SyntaxWarning should be triggered")
warnings.resetwarnings()
Drink.drop_collection()

View File

@ -14,7 +14,7 @@ from nose.plugins.skip import SkipTest
from mongoengine import *
from mongoengine.connection import get_db
from mongoengine.base import _document_registry, NotRegistered
from mongoengine.python3_support import PY3, b, StringIO, bin_type
from mongoengine.python_support import PY3, b, StringIO, bin_type
TEST_IMAGE_PATH = os.path.join(os.path.dirname(__file__), 'mongoengine.png')
@ -383,7 +383,7 @@ class FieldTest(unittest.TestCase):
self.assertNotEqual(log.date, d1)
self.assertEqual(log.date, d2)
if not PY3:
if not PY3:
# Pre UTC dates microseconds below 1000 are dropped
# This does not seem to be true in PY3
d1 = datetime.datetime(1969, 12, 31, 23, 59, 59, 999)
@ -1744,7 +1744,7 @@ class FieldTest(unittest.TestCase):
self.assertEqual(doc_b.the_file.grid_id, doc_c.the_file.grid_id)
# Test with default
doc_d = GridDocument(the_file=b(''))
doc_d = GridDocument(the_file=b(''))
doc_d.save()
doc_e = GridDocument.objects.with_id(doc_d.id)
@ -2157,11 +2157,11 @@ class FieldTest(unittest.TestCase):
post = Post(title='hello world')
post.comments.append(Comment(content='hello', author=bob))
post.comments.append(Comment(author=bob))
self.assertRaises(ValidationError, post.validate)
try:
post.validate()
except ValidationError, error:
except ValidationError, error:
# ValidationError.errors property
self.assertTrue(hasattr(error, 'errors'))
self.assertTrue(isinstance(error.errors, dict))

View File

@ -9,7 +9,7 @@ from bson import ObjectId
from mongoengine import *
from mongoengine.connection import get_connection
from mongoengine.python3_support import PY3
from mongoengine.python_support import PY3
from mongoengine.tests import query_counter
from mongoengine.queryset import (QuerySet, QuerySetManager,
MultipleObjectsReturned, DoesNotExist,
@ -1455,6 +1455,8 @@ class QuerySetTest(unittest.TestCase):
name = StringField()
parent = ReferenceField('self', reverse_delete_rule=CASCADE)
Category.drop_collection()
num_children = 3
base = Category(name='Root')
base.save()