Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python 3 and Django 1.5 support #308

Merged
merged 10 commits into from
Feb 27, 2013
17 changes: 13 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,27 @@ language: python
python:
- 2.6
- 2.7
- 3.3

env:
- DJANGO_VERSION=1.4
- DJANGO_VERSION=1.3
- DJANGO=Django==1.3 --use-mirrors
- DJANGO=Django==1.4 --use-mirrors
- DJANGO=https://www.djangoproject.com/download/1.5c2/tarball/

install:
- pip install -q Django==$DJANGO_VERSION --use-mirrors
- pip install unittest2 flake8 --use-mirrors
- pip install -q $DJANGO
- pip install flake8 --use-mirrors
- pip install -q python-keyczar --use-mirrors
- pip install -q PyYAML --use-mirrors
- pip install -e . --use-mirrors

script:
- flake8 --ignore=E501,W391 .
- python setup.py test

matrix:
exclude:
- python: 3.3
env: DJANGO=Django==1.3 --use-mirrors
- python: 3.3
env: DJANGO=Django==1.4 --use-mirrors
15 changes: 10 additions & 5 deletions django_extensions/db/fields/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
"""
Django Extensions additional model fields
"""

from django.template.defaultfilters import slugify
from django.db.models import DateTimeField, CharField, SlugField
import re

try:
Expand All @@ -12,13 +9,21 @@
except ImportError:
from django_extensions.utils import uuid

from django.template.defaultfilters import slugify
from django.db.models import DateTimeField, CharField, SlugField

try:
from django.utils.timezone import now as datetime_now
assert datetime_now
except ImportError:
import datetime
datetime_now = datetime.datetime.now

try:
from django.utils.encoding import force_unicode
except ImportError:
from django.utils.encoding import force_text as force_unicode


class AutoSlugField(SlugField):
""" AutoSlugField
Expand Down Expand Up @@ -136,7 +141,7 @@ def create_slug(self, model_instance, add):
return slug

def pre_save(self, model_instance, add):
value = unicode(self.create_slug(model_instance, add))
value = force_unicode(self.create_slug(model_instance, add))
setattr(model_instance, self.attname, value)
return value

Expand Down Expand Up @@ -266,7 +271,7 @@ def create_uuid(self):
def pre_save(self, model_instance, add):
value = super(UUIDField, self).pre_save(model_instance, add)
if self.auto and add and value is None:
value = unicode(self.create_uuid())
value = force_unicode(self.create_uuid())
setattr(model_instance, self.attname, value)
return value
else:
Expand Down
2 changes: 1 addition & 1 deletion django_extensions/management/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@ def handle(self, *args, **options):
def execute(self, *args, **options):
try:
super(LoggingBaseCommand, self).execute(*args, **options)
except Exception, e:
except Exception as e:
logger.error(e, exc_info=sys.exc_info(), extra={'status_code': 500})
raise
15 changes: 11 additions & 4 deletions django_extensions/management/commands/dumpscript.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,20 @@
"""

import sys
import datetime
import six

import django
from django.db.models import AutoField, BooleanField, FileField, ForeignKey
from django.core.exceptions import ObjectDoesNotExist
from django.core.management.base import BaseCommand
from django.utils.encoding import smart_unicode, force_unicode

# conditional import, force_unicode was renamed in Django 1.5
from django.contrib.contenttypes.models import ContentType
import datetime
try:
from django.utils.encoding import smart_unicode, force_unicode
except ImportError:
from django.utils.encoding import smart_text as smart_unicode, force_text as force_unicode


def orm_item_locator(orm_obj):
Expand All @@ -63,7 +70,7 @@ def orm_item_locator(orm_obj):

for key in clean_dict:
v = clean_dict[key]
if v is not None and not isinstance(v, (basestring, int, long, float, datetime.datetime)):
if v is not None and not isinstance(v, (six.string_types, int, long, float, datetime.datetime)):
clean_dict[key] = u"%s" % v

output = """ locate_object(%s, "%s", %s, "%s", %s, %s ) """ % (
Expand Down Expand Up @@ -598,7 +605,7 @@ def flatten_blocks(lines, num_indents=-1):
return ""

# If this is a string, add the indentation and finish here
if isinstance(lines, basestring):
if isinstance(lines, six.string_types):
return INDENTATION * num_indents + lines

# If this is not a string, join the lines and recurse
Expand Down
10 changes: 2 additions & 8 deletions django_extensions/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
from django.db import models # NOQA
from django_extensions.tests.test_dumpscript import DumpScriptTests
from django_extensions.tests.utils import UTILS_TRUNCATE_LETTERS_TESTS
from django_extensions.tests.utils import UTILS_UUID_TESTS
from django_extensions.tests.utils import TruncateLetterTests
from django_extensions.tests.json_field import JsonFieldTest
from django_extensions.tests.uuid_field import UUIDFieldTest
from django_extensions.tests.fields import AutoSlugFieldTest
from django_extensions.tests.management_command import CommandTest, ShowTemplateTagsTests

__test__ = {
'UTILS_TRUNCATE_LETTERS_TESTS': UTILS_TRUNCATE_LETTERS_TESTS,
'UTILS_UUID_TESTS': UTILS_UUID_TESTS,
}

__test_classes__ = [
DumpScriptTests, JsonFieldTest, UUIDFieldTest, AutoSlugFieldTest, CommandTest, ShowTemplateTagsTests
DumpScriptTests, JsonFieldTest, UUIDFieldTest, AutoSlugFieldTest, CommandTest, ShowTemplateTagsTests, TruncateLetterTests
]

try:
Expand All @@ -22,4 +17,3 @@
__test_classes__.append(EncryptedFieldsTestCase)
except ImportError:
pass

4 changes: 2 additions & 2 deletions django_extensions/tests/fields.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import unittest

from django.conf import settings
from django.core.management import call_command
from django.db.models import loading
from django.db import models
from django.utils import unittest

from django_extensions.db.fields import AutoSlugField


Expand Down
5 changes: 2 additions & 3 deletions django_extensions/tests/json_field.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import unittest

from django.conf import settings
from django.core.management import call_command
from django.db.models import loading
from django.db import models
from django.utils import unittest

from django_extensions.db.fields.json import JSONField


Expand Down Expand Up @@ -31,4 +31,3 @@ def testEmptyList(self):
j = TestModel.objects.create(a=6, j_field=[])
self.assertTrue(isinstance(j.j_field, list))
self.assertEquals(j.j_field, [])

6 changes: 5 additions & 1 deletion django_extensions/tests/management_command.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# -*- coding: utf-8 -*-
import logging
from cStringIO import StringIO

try:
from cStringIO import StringIO
except ImportError:
from io import StringIO

try:
import importlib # NOQA
Expand Down
21 changes: 15 additions & 6 deletions django_extensions/tests/test_dumpscript.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import sys
import compiler

# conditional imports for python 3
try:
import compiler
from StringIO import StringIO
except ImportError:
import ast as compiler
from io import StringIO
from django.test import TestCase

from django.core.management import call_command
from django_extensions.tests.models import Name, Note, Person

from django.conf import settings
from django.db.models import loading

from StringIO import StringIO


class DumpScriptTests(TestCase):
def setUp(self):
Expand Down Expand Up @@ -46,7 +52,7 @@ def test_replaced_stdout(self):
tmp_out = StringIO()
call_command('dumpscript', 'tests', stdout=tmp_out)
self.assertTrue('Mike' in tmp_out.getvalue()) # script should go to tmp_out
self.assertFalse(sys.stdout.len) # there should not be any output to sys.stdout
self.assertEquals(0, len(sys.stdout.getvalue())) # there should not be any output to sys.stdout
tmp_out.close()

#----------------------------------------------------------------------
Expand All @@ -59,7 +65,7 @@ def test_replaced_stderr(self):
call_command('dumpscript', 'tests', stderr=tmp_err)
self.assertTrue('Fred' in sys.stdout.getvalue()) # script should still go to stdout
self.assertTrue('Name' in tmp_err.getvalue()) # error output should go to tmp_err
self.assertFalse(sys.stderr.len) # there should not be any output to sys.stderr
self.assertEquals(0, len(sys.stderr.getvalue())) # there should not be any output to sys.stderr
tmp_err.close()

#----------------------------------------------------------------------
Expand All @@ -81,6 +87,9 @@ def test_valid_syntax(self):
tmp_out = StringIO()
call_command('dumpscript', 'tests', stdout=tmp_out)
ast_syntax_tree = compiler.parse(tmp_out.getvalue())
self.assertTrue(len(ast_syntax_tree.asList()) > 1)
if hasattr(ast_syntax_tree, 'body'):
self.assertTrue(len(ast_syntax_tree.body) > 1)
else:
self.assertTrue(len(ast_syntax_tree.asList()) > 1)
tmp_out.close()

122 changes: 73 additions & 49 deletions django_extensions/tests/utils.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,75 @@
# -*- coding: utf-8 -*-
import sys

UTILS_TRUNCATE_LETTERS_TESTS = """
>>> from django_extensions.utils.text import truncate_letters
>>> truncate_letters("hello tests", 100)
u'hello tests'
>>> truncate_letters("hello tests", 5)
u'hello...'
>>> for i in range(10,-1,-1): truncate_letters("hello tests", i),i
(u'hello test...', 10)
(u'hello tes...', 9)
(u'hello te...', 8)
(u'hello t...', 7)
(u'hello ...', 6)
(u'hello...', 5)
(u'hell...', 4)
(u'hel...', 3)
(u'he...', 2)
(u'h...', 1)
(u'...', 0)
>>> truncate_letters("峠 (とうげ tōge - mountain pass)", 10)
u'\u5ce0 (\u3068\u3046\u3052 t\u014dg...'

"""

UTILS_UUID_TESTS = """
>>> from django_extensions.utils import uuid

# make a UUID using an MD5 hash of a namespace UUID and a name
>>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')

# make a UUID using a SHA-1 hash of a namespace UUID and a name
>>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')

# make a UUID from a string of hex digits (braces and hyphens ignored)
>>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')

# convert a UUID to a string of hex digits in standard form
>>> str(x)
'00010203-0405-0607-0809-0a0b0c0d0e0f'

# get the raw 16 bytes of the UUID
>>> x.bytes
'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f'

# make a UUID from a 16-byte string
>>> uuid.UUID(bytes=x.bytes)
UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
"""
from django.test import TestCase
from django.utils.unittest import skipIf

from django_extensions.utils.text import truncate_letters
try:
import uuid
assert uuid
except ImportError:
from django_extensions.utils import uuid


class TruncateLetterTests(TestCase):
def test_truncate_more_than_text_length(self):
self.assertEquals(u"hello tests", truncate_letters("hello tests", 100))

def test_truncate_text(self):
self.assertEquals(u"hello...", truncate_letters("hello tests", 5))

def test_truncate_with_range(self):
for i in range(10, -1, -1):
self.assertEqual(
u'hello tests'[:i] + '...',
truncate_letters("hello tests", i)
)

def test_with_non_ascii_characters(self):
self.assertEquals(
u'\u5ce0 (\u3068\u3046\u3052 t\u014dg...',
truncate_letters("峠 (とうげ tōge - mountain pass)", 10)
)


class UUIDTests(TestCase):
@skipIf(sys.version_info >= (2, 5, 0), 'uuid already in stdlib')
def test_uuid3(self):
# make a UUID using an MD5 hash of a namespace UUID and a name
self.assertEquals(
uuid.UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e'),
uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
)

@skipIf(sys.version_info >= (2, 5, 0), 'uuid already in stdlib')
def test_uuid5(self):
# make a UUID using a SHA-1 hash of a namespace UUID and a name
self.assertEquals(
uuid.UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d'),
uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
)

@skipIf(sys.version_info >= (2, 5, 0), 'uuid already in stdlib')
def test_uuid_str(self):
# make a UUID from a string of hex digits (braces and hyphens ignored)
x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
# convert a UUID to a string of hex digits in standard form
self.assertEquals('00010203-0405-0607-0809-0a0b0c0d0e0f', str(x))

@skipIf(sys.version_info >= (2, 5, 0), 'uuid already in stdlib')
def test_uuid_bytes(self):
# make a UUID from a string of hex digits (braces and hyphens ignored)
x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
# get the raw 16 bytes of the UUID
self.assertEquals(
'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f',
x.bytes
)

@skipIf(sys.version_info >= (2, 5, 0), 'uuid already in stdlib')
def test_make_uuid_from_byte_string(self):
self.assertEquals(
uuid.UUID(bytes='\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f'),
uuid.UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
)
5 changes: 2 additions & 3 deletions django_extensions/tests/uuid_field.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import unittest


from django.conf import settings
from django.core.management import call_command
from django.db.models import loading
from django.db import models
from django.utils import unittest

from django_extensions.db.fields import UUIDField


Expand Down