Merge pull request #22 from jjkester/python3

Support Python 3 as well as Python 2
This commit is contained in:
Jan-Jelle Kester 2015-05-15 00:30:47 +02:00
commit ae8461d1fe
12 changed files with 54 additions and 20 deletions

11
.travis.yml Normal file
View file

@ -0,0 +1,11 @@
language: python
python:
- "2.7"
- "3.4"
env:
- DJANGO_VERSION=1.7
- DJANGO_VERSION=1.8
install:
- "pip install -r requirements.txt"
- "pip install Django==$DJANGO_VERSION"
script: "python src/manage.py test testapp"

View file

@ -1 +1 @@
Django>=1.5
Django>=1.7

View file

@ -11,6 +11,6 @@ setup(
author_email='janjelle@jjkester.nl',
description='Audit log app for Django',
install_requires=[
'Django>=1.5'
'Django>=1.7'
]
)

View file

@ -0,0 +1 @@
from __future__ import unicode_literals

View file

@ -1,5 +1,8 @@
from __future__ import unicode_literals
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Model
from django.utils.encoding import smart_text
def model_instance_diff(old, new, **kwargs):
@ -11,9 +14,9 @@ def model_instance_diff(old, new, **kwargs):
from auditlog.registry import auditlog
if not(old is None or isinstance(old, Model)):
raise TypeError('The supplied old instance is not a valid model instance.')
raise TypeError("The supplied old instance is not a valid model instance.")
if not(new is None or isinstance(new, Model)):
raise TypeError('The supplied new instance is not a valid model instance.')
raise TypeError("The supplied new instance is not a valid model instance.")
diff = {}
@ -45,12 +48,12 @@ def model_instance_diff(old, new, **kwargs):
for field in fields:
try:
old_value = unicode(getattr(old, field.name, None))
old_value = smart_text(getattr(old, field.name, None))
except ObjectDoesNotExist:
old_value = None
try:
new_value = unicode(getattr(new, field.name, None))
new_value = smart_text(getattr(new, field.name, None))
except ObjectDoesNotExist:
new_value = None

View file

@ -1,3 +1,5 @@
from __future__ import unicode_literals
import time
from django.conf import settings

View file

@ -15,6 +15,5 @@ class Migration(migrations.Migration):
model_name='logentry',
name='object_id',
field=models.BigIntegerField(db_index=True, null=True, verbose_name='object id', blank=True),
preserve_default=True,
),
]

View file

@ -1,9 +1,13 @@
from __future__ import unicode_literals
import json
from django.conf import settings
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils.encoding import python_2_unicode_compatible, smart_text
from django.utils.six import iteritems, integer_types
from django.utils.translation import ugettext_lazy as _
@ -23,9 +27,9 @@ class LogEntryManager(models.Manager):
if changes is not None:
kwargs.setdefault('content_type', ContentType.objects.get_for_model(instance))
kwargs.setdefault('object_pk', pk)
kwargs.setdefault('object_repr', str(instance))
kwargs.setdefault('object_repr', smart_text(instance))
if isinstance(pk, (int, long)):
if isinstance(pk, integer_types):
kwargs.setdefault('object_id', pk)
# Delete log entries with the same pk as a newly created model. This should only be necessary when an pk is
@ -50,7 +54,7 @@ class LogEntryManager(models.Manager):
content_type = ContentType.objects.get_for_model(instance.__class__)
pk = self._get_pk_value(instance)
if isinstance(pk, (int, long)):
if isinstance(pk, integer_types):
return self.filter(content_type=content_type, object_id=pk)
else:
return self.filter(content_type=content_type, object_pk=pk)
@ -80,6 +84,7 @@ class LogEntryManager(models.Manager):
return pk
@python_2_unicode_compatible
class LogEntry(models.Model):
"""
Represents an entry in the audit log. The content type is saved along with the textual and numeric (if available)
@ -124,7 +129,7 @@ class LogEntry(models.Model):
verbose_name = _("log entry")
verbose_name_plural = _("log entries")
def __unicode__(self):
def __str__(self):
if self.action == self.Action.CREATE:
fstring = _("Created {repr:s}")
elif self.action == self.Action.UPDATE:
@ -147,7 +152,7 @@ class LogEntry(models.Model):
return {}
@property
def changes_str(self, colon=': ', arrow=u' \u2192 ', separator='; '):
def changes_str(self, colon=': ', arrow=smart_text(' \u2192 '), separator='; '):
"""
Return the changes recorded in this log entry as a string. The formatting of the string can be customized by
setting alternate values for colon, arrow and separator. If the formatting is still not satisfying, please use
@ -155,8 +160,8 @@ class LogEntry(models.Model):
"""
substrings = []
for field, values in self.changes_dict.iteritems():
substring = u'{field_name:s}{colon:s}{old:s}{arrow:s}{new:s}'.format(
for field, values in iteritems(self.changes_dict):
substring = smart_text('{field_name:s}{colon:s}{old:s}{arrow:s}{new:s}').format(
field_name=field,
colon=colon,
old=values[0],
@ -196,5 +201,6 @@ class AuditlogHistoryField(generic.GenericRelation):
try:
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^auditlog\.models\.AuditlogHistoryField"])
raise DeprecationWarning("South support will be dropped in django-auditlog 0.4.0 or later.")
except ImportError:
pass

View file

@ -1,4 +1,7 @@
from __future__ import unicode_literals
import json
from auditlog.diff import model_instance_diff
from auditlog.models import LogEntry

View file

@ -1,14 +1,16 @@
from __future__ import unicode_literals
from django.db.models.signals import pre_save, post_save, post_delete
from django.db.models import Model
class AuditLogModelRegistry(object):
class AuditlogModelRegistry(object):
"""
A registry that keeps track of the models that use Auditlog to track changes.
"""
def __init__(self, create=True, update=True, delete=True, custom=None):
from auditlog.receivers import log_create, log_update, log_delete
self._registry = {}
self._signals = {}
@ -37,7 +39,7 @@ class AuditLogModelRegistry(object):
}
self._connect_signals(model)
else:
raise TypeError('Supplied model is not a valid model.')
raise TypeError("Supplied model is not a valid model.")
def contains(self, model):
"""
@ -83,4 +85,11 @@ class AuditLogModelRegistry(object):
'exclude_fields': self._registry[model]['exclude_fields'],
}
auditlog = AuditLogModelRegistry()
class AuditLogModelRegistry(AuditlogModelRegistry):
def __init__(self, *args, **kwargs):
super(AuditLogModelRegistry, self).__init__(*args, **kwargs)
raise DeprecationWarning("Use AuditlogModelRegistry instead of AuditLogModelRegistry, AuditLogModelRegistry will be removed in django-auditlog 0.4.0 or later.")
auditlog = AuditlogModelRegistry()

View file

@ -86,4 +86,4 @@ auditlog.register(SimpleModel)
auditlog.register(AltPrimaryKeyModel)
auditlog.register(ProxyModel)
auditlog.register(SimpleIncludeModel, include_fields=['label', ])
auditlog.register(SimpleExcludeModel, exclude_fields=['label', ])
auditlog.register(SimpleExcludeModel, exclude_fields=['text', ])

View file

@ -165,7 +165,7 @@ class SimpeExcludeModelTest(TestCase):
"""Log only changes that are not in exclude_fields"""
def test_register_exclude_fields(self):
sem = SimpleIncludeModel(label='Exclude model', text='Looong text')
sem = SimpleExcludeModel(label='Exclude model', text='Looong text')
sem.save()
self.assertTrue(sem.history.count() == 1, msg="There is one log entry")