From e97c601038a4fe0e8b40f32675b6fac9c4aae10e Mon Sep 17 00:00:00 2001 From: Jan-Jelle Kester Date: Mon, 16 Feb 2015 22:17:22 +0100 Subject: [PATCH 1/9] First try at making Auditlog work with Python 3 Issue #15 --- src/auditlog/__init__.py | 1 + src/auditlog/diff.py | 11 +++++++---- src/auditlog/middleware.py | 2 ++ src/auditlog/models.py | 20 +++++++++++++------- src/auditlog/receivers.py | 3 +++ src/auditlog/registry.py | 17 +++++++++++++---- 6 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/auditlog/__init__.py b/src/auditlog/__init__.py index e69de29..baffc48 100644 --- a/src/auditlog/__init__.py +++ b/src/auditlog/__init__.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/src/auditlog/diff.py b/src/auditlog/diff.py index e92855c..b8194e2 100644 --- a/src/auditlog/diff.py +++ b/src/auditlog/diff.py @@ -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 diff --git a/src/auditlog/middleware.py b/src/auditlog/middleware.py index a61f65f..b62a9f4 100644 --- a/src/auditlog/middleware.py +++ b/src/auditlog/middleware.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import time from django.conf import settings diff --git a/src/auditlog/models.py b/src/auditlog/models.py index 1223a6b..04bfe8c 100644 --- a/src/auditlog/models.py +++ b/src/auditlog/models.py @@ -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) @@ -75,6 +79,7 @@ class LogEntryManager(models.Manager): return getattr(instance, pk_field, None) +@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) @@ -119,7 +124,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: @@ -142,7 +147,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 @@ -150,8 +155,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], @@ -191,5 +196,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 diff --git a/src/auditlog/receivers.py b/src/auditlog/receivers.py index 1fd8349..016fc2e 100644 --- a/src/auditlog/receivers.py +++ b/src/auditlog/receivers.py @@ -1,4 +1,7 @@ +from __future__ import unicode_literals + import json + from auditlog.diff import model_instance_diff from auditlog.models import LogEntry diff --git a/src/auditlog/registry.py b/src/auditlog/registry.py index bd791dd..0a530bd 100644 --- a/src/auditlog/registry.py +++ b/src/auditlog/registry.py @@ -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() From 0bf829f2967d3a007b4a28a2bde3ba3dd5ec20fc Mon Sep 17 00:00:00 2001 From: Jan-Jelle Kester Date: Thu, 14 May 2015 23:30:05 +0200 Subject: [PATCH 2/9] Fix exclude model test --- src/testapp/models.py | 2 +- src/testapp/tests.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/testapp/models.py b/src/testapp/models.py index 4d5d0eb..9a05d26 100644 --- a/src/testapp/models.py +++ b/src/testapp/models.py @@ -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', ]) diff --git a/src/testapp/tests.py b/src/testapp/tests.py index 53c73ae..80e36dd 100644 --- a/src/testapp/tests.py +++ b/src/testapp/tests.py @@ -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") From 5f7fdc5a1df7a7a14f0db032674b17e300a2e477 Mon Sep 17 00:00:00 2001 From: Jan-Jelle Kester Date: Thu, 14 May 2015 23:51:37 +0200 Subject: [PATCH 3/9] Add Travis CI support --- .travis.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..333af70 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +language: python +python: + - "2.7" + - "3.3" + - "3.4" +env: + - DJANGO_VERSION=1.5 + - DJANGO_VERSION=1.7 + - DJANGO_VERSION=1.8 +install: "pip install Django==$DJANGO_VERSION" +script: "python src/manage.py test testapp.tests \ No newline at end of file From fd16002ce2b1d1c9382f89ea5ed2c112aba89c58 Mon Sep 17 00:00:00 2001 From: Jan-Jelle Kester Date: Thu, 14 May 2015 23:55:58 +0200 Subject: [PATCH 4/9] Fix broken Travis CI config --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 333af70..966de9f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,5 +7,7 @@ env: - DJANGO_VERSION=1.5 - DJANGO_VERSION=1.7 - DJANGO_VERSION=1.8 -install: "pip install Django==$DJANGO_VERSION" -script: "python src/manage.py test testapp.tests \ No newline at end of file +install: + - "pip install -r requirements.txt" + - "pip install -u Django==$DJANGO_VERSION" +script: "python src/manage.py test testapp.tests" From 718595f5559a9c3f71cd1df5226dc180a04a39ef Mon Sep 17 00:00:00 2001 From: Jan-Jelle Kester Date: Fri, 15 May 2015 00:02:02 +0200 Subject: [PATCH 5/9] Fix broken Travis CI config again --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 966de9f..9da6e74 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,5 +9,5 @@ env: - DJANGO_VERSION=1.8 install: - "pip install -r requirements.txt" - - "pip install -u Django==$DJANGO_VERSION" + - "pip install Django==$DJANGO_VERSION" script: "python src/manage.py test testapp.tests" From 2affded385688f5b5bae0638c613c9cf4c12dd55 Mon Sep 17 00:00:00 2001 From: Jan-Jelle Kester Date: Fri, 15 May 2015 00:05:59 +0200 Subject: [PATCH 6/9] Reduce number of Travis environments --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9da6e74..11745b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: python python: - "2.7" - - "3.3" - "3.4" env: - DJANGO_VERSION=1.5 From b4a0144bfa457b7d1a46ad24a3ed1a15de89b02f Mon Sep 17 00:00:00 2001 From: Jan-Jelle Kester Date: Fri, 15 May 2015 00:15:12 +0200 Subject: [PATCH 7/9] Try to make migrations work for Django 1.7 --- src/auditlog/migrations/0002_auto_support_long_primary_keys.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/auditlog/migrations/0002_auto_support_long_primary_keys.py b/src/auditlog/migrations/0002_auto_support_long_primary_keys.py index 3da4843..5ea87f6 100644 --- a/src/auditlog/migrations/0002_auto_support_long_primary_keys.py +++ b/src/auditlog/migrations/0002_auto_support_long_primary_keys.py @@ -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, ), ] From bafce4d72cf40c7e13f66a94cecefafbaf9c0c95 Mon Sep 17 00:00:00 2001 From: Jan-Jelle Kester Date: Fri, 15 May 2015 00:15:50 +0200 Subject: [PATCH 8/9] Change Travis CI config test script to work with Django 1.5 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 11745b0..cc6cfcd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,4 +9,4 @@ env: install: - "pip install -r requirements.txt" - "pip install Django==$DJANGO_VERSION" -script: "python src/manage.py test testapp.tests" +script: "python src/manage.py test testapp" From 42d9d767acd6f29ec34bde499d3bdf579e474517 Mon Sep 17 00:00:00 2001 From: Jan-Jelle Kester Date: Fri, 15 May 2015 00:17:50 +0200 Subject: [PATCH 9/9] Drop Django 1.5 support (unsupported version) --- .travis.yml | 1 - requirements.txt | 2 +- setup.py | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index cc6cfcd..71eb5d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ python: - "2.7" - "3.4" env: - - DJANGO_VERSION=1.5 - DJANGO_VERSION=1.7 - DJANGO_VERSION=1.8 install: diff --git a/requirements.txt b/requirements.txt index be600a3..e38f742 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -Django>=1.5 +Django>=1.7 diff --git a/setup.py b/setup.py index 969439f..7e669dd 100644 --- a/setup.py +++ b/setup.py @@ -11,6 +11,6 @@ setup( author_email='janjelle@jjkester.nl', description='Audit log app for Django', install_requires=[ - 'Django>=1.5' + 'Django>=1.7' ] )