diff --git a/.gitignore b/.gitignore index dcd2e24..dbd22bc 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,6 @@ build *.db3 .pydevproject .idea -.eggs \ No newline at end of file +.eggs +.tox +.coverage \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index ca5198a..c8c6082 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,36 +1,45 @@ # Config file for automatic testing at travis-ci.org language: python +python: + - 3.5 sudo: false -python: - - "2.7" - - "3.4" - - "3.5" +cache: + directories: + - $HOME/.pip-accel + - $HOME/.cache/pip env: - - DJANGO='1.8' REVERSION='1.9' EXTRA='' - - DJANGO='1.8' REVERSION='1.10' EXTRA='' - - DJANGO='1.9' REVERSION='1.10' EXTRA='' - - DJANGO='1.8' REVERSION='1.9' EXTRA='diff-match-patch' - - DJANGO='1.8' REVERSION='1.10' EXTRA='diff-match-patch' - - DJANGO='1.9' REVERSION='1.10' EXTRA='diff-match-patch' + matrix: + - TOXENV=py27-django18-dmp + - TOXENV=py27-django18 + - TOXENV=py27-django19-dmp + - TOXENV=py27-django19 + - TOXENV=py27-django110-dmp + - TOXENV=py27-django110 + - TOXENV=py34-django18-dmp + - TOXENV=py34-django18 + - TOXENV=py34-django19-dmp + - TOXENV=py34-django19 + - TOXENV=py34-django110-dmp + - TOXENV=py34-django110 + - TOXENV=py35-django18-dmp + - TOXENV=py35-django18 + - TOXENV=py35-django19-dmp + - TOXENV=py35-django19 + - TOXENV=py35-django110-dmp + - TOXENV=py35-django110 + +matrix: + fast_finish: true install: - pip install --upgrade pip - - pip install Django==$DJANGO.\* - - pip install django-reversion==$REVERSION.\* - - pip install . django-tools coveralls $EXTRA + - travis_retry pip install 'tox>=2.3.1' coveralls script: - - python --version - - pip freeze - - coverage run --source=reversion_compare runtests.py - -after_success: - - coverage combine - - coverage report - - coveralls + - travis_retry tox notifications: irc: "irc.freenode.org#pylucid" diff --git a/AUTHORS b/AUTHORS index 3822f06..dfddd84 100644 --- a/AUTHORS +++ b/AUTHORS @@ -33,6 +33,8 @@ CONTRIBUTORS are and/or have been (alphabetic order): Github: * Spencer, Samuel Github: +* Shannon, Michael + Github: * C. Barrionuevo da Luz, Fabio Github: * Wickström, Frank diff --git a/README.creole b/README.creole index 0f9997d..b2aad3b 100644 --- a/README.creole +++ b/README.creole @@ -222,6 +222,7 @@ e.g.: == Version compatibility == |= Reversion-Compare |=django-reversion |= Django |= Python +|v0.7.x | v2.0 | v1.8, v1.9 | v2.7, v3.4, v3.5 |v0.6.x | v1.9, v1.10 | v1.8, v1.9 | v2.7, v3.4, v3.5 |>=v0.5.2 | v1.9 | v1.7, v1.8 | v2.7, v3.4 |>=v0.4 | v1.8 | v1.7 | v2.7, v3.4 @@ -232,6 +233,10 @@ Maybe other versions are compatible, too. == Changelog == +* [[https://github.com/jedie/django-reversion-compare/compare/v0.6.3...v0.7.0|v0.7.0 - 25.08.2016]]: +** [[https://github.com/jedie/django-reversion-compare/pull/76|support only django-reversion >= 2.0]] based on a contribution by [[https://github.com/jedie/django-reversion-compare/pull/73|mshannon1123]] +** remove internal **reversion_api** +** Use tox * [[https://github.com/jedie/django-reversion-compare/compare/v0.6.2...v0.6.3|v0.6.3 - 14.06.2016]]: ** [[https://github.com/jedie/django-reversion-compare/pull/69|Remove unused and deprecated patters]] contributed by [[https://github.com/codingjoe|codingjoe]] ** [[https://github.com/jedie/django-reversion-compare/pull/66|Fix django 1.10 warning #66]] contributed by [[https://github.com/pypetey|pypetey]] diff --git a/requirements-test.txt b/requirements-test.txt new file mode 100644 index 0000000..6a6dcba --- /dev/null +++ b/requirements-test.txt @@ -0,0 +1,3 @@ +tox +coveralls +django-tools diff --git a/reversion_compare/__init__.py b/reversion_compare/__init__.py index 6d8c55a..91eadea 100644 --- a/reversion_compare/__init__.py +++ b/reversion_compare/__init__.py @@ -1,3 +1,3 @@ # coding: utf-8 -__version__ = "0.6.3" +__version__ = "0.7.0" diff --git a/reversion_compare/admin.py b/reversion_compare/admin.py index 5717f6b..f3c60ea 100644 --- a/reversion_compare/admin.py +++ b/reversion_compare/admin.py @@ -20,7 +20,7 @@ from django.contrib import admin try: from django.contrib.admin.utils import unquote, quote -except ImportError: # Django < 1.7 +except ImportError: # Django < 1.7 # pragma: no cover from django.contrib.admin.util import unquote, quote from django.core.urlresolvers import reverse from django.http import Http404 @@ -28,11 +28,6 @@ from django.utils.text import capfirst from django.utils.translation import ugettext as _ -try: - from reversion import revisions as reversion # django-reversion >= 1.10 -except ImportError: - import reversion # django-reversion <= 1.9 - from reversion.admin import VersionAdmin from reversion_compare.forms import SelectDiffForm @@ -111,7 +106,7 @@ def _get_action_list(self, request, object_id, extra_context=None): args=(quote(version.object_id), version.id)), } for version - in self._order_version_queryset(self.revision_manager.get_for_object_reference( + in self._order_version_queryset(Version.objects.get_for_object_reference( self.model, object_id, ).select_related("revision__user")) @@ -168,7 +163,7 @@ def compare_view(self, request, object_id, extra_context=None): object_id = unquote(object_id) # Underscores in primary key get quoted to "_5F" obj = get_object_or_404(self.model, pk=object_id) - queryset = self.revision_manager.get_for_object(obj) + queryset = Version.objects.get_for_object(obj) version1 = get_object_or_404(queryset, pk=version_id1) version2 = get_object_or_404(queryset, pk=version_id2) diff --git a/reversion_compare/compare.py b/reversion_compare/compare.py index ea470ee..1fbedd0 100644 --- a/reversion_compare/compare.py +++ b/reversion_compare/compare.py @@ -17,9 +17,8 @@ from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.translation import ugettext as _ - -from reversion_compare import reversion_api - +from reversion.models import Version +from reversion.revisions import _get_options logger = logging.getLogger(__name__) @@ -36,21 +35,21 @@ def __str__(self): class CompareObject(object): - def __init__(self, field, field_name, obj, version, has_int_pk, adapter): + + def __init__(self, field, field_name, obj, version_record, follow): self.field = field self.field_name = field_name self.obj = obj - self.version = version # instance of reversion.models.Version() - self.has_int_pk = has_int_pk - self.adapter = adapter + self.version_record = version_record # instance of reversion.models.Version() + self.follow = follow # try and get a value, if none punt - self.value = version.field_dict.get(field_name, DOES_NOT_EXIST) + self.value = version_record.field_dict.get(field_name, DOES_NOT_EXIST) def _obj_repr(self, obj): # FIXME: How to create a better representation of the current value? try: return str(obj) - except Exception as e: + except Exception: return repr(obj) def _choices_repr(self, obj): @@ -58,12 +57,10 @@ def _choices_repr(self, obj): strings_only=True) def _to_string_ManyToManyField(self): - queryset = self.get_many_to_many() - return ", ".join([self._obj_repr(item) for item in queryset]) + return ", ".join([self._obj_repr(item) for item in self.get_many_to_many()]) def _to_string_ForeignKey(self): - obj = self.get_related() - return self._obj_repr(obj) + return self._obj_repr(self.get_related()) def to_string(self): internal_type = self.field.get_internal_type() @@ -91,9 +88,9 @@ def __eq__(self, other): return False # see - https://hynek.me/articles/hasattr/ - internal_type = getattr(self.field,'get_internal_type',None) + internal_type = getattr(self.field, 'get_internal_type', None) if internal_type is None or internal_type() == "ForeignKey": # FIXME! - if self.version.field_dict != other.version.field_dict: + if self.version_record.field_dict != other.version_record.field_dict: return False return True @@ -101,35 +98,46 @@ def __eq__(self, other): def __ne__(self, other): return not self.__eq__(other) + def get_object_version(self): + if hasattr(self.version_record, '_object_version'): + return getattr(self.version_record, '_object_version') + else: + return getattr(self.version_record, 'object_version') + def get_related(self): if getattr(self.field, 'rel', None): - obj = self.version.object_version.object + obj = self.get_object_version().object try: return getattr(obj, self.field.name, None) except ObjectDoesNotExist: return None def get_reverse_foreign_key(self): - obj = self.version.object_version.object - if self.has_int_pk and self.field.related_name and hasattr(obj, self.field.related_name): + obj = self.get_object_version().object + if self.field.related_name and hasattr(obj, self.field.related_name): if isinstance(self.field, models.fields.related.OneToOneRel): try: - ids = [getattr(obj, str(self.field.related_name)).pk] + ids = {force_text(getattr(obj, str(self.field.related_name)).pk), } except ObjectDoesNotExist: - ids = [] + ids = set() else: - ids = [v.id for v in getattr(obj, str(self.field.related_name)).all()] # is: version.field_dict[field.name] - if ids == [] and any([f.name.endswith('_ptr') for f in obj._meta.fields]): - # If there is a _ptr this is a multiinheritance table and inherits from a non-abstract class + # If there is a _ptr this is a multi-inheritance table and inherits from a non-abstract class + ids = {force_text(v.id) for v in getattr(obj, str(self.field.related_name)).all()} + if not ids and any([f.name.endswith('_ptr') for f in obj._meta.get_fields()]): + # If there is a _ptr this is a multi-inheritance table and inherits from a non-abstract class # lets try and get the parent items associated entries for this field - others = self.version.revision.version_set.filter(object_id=self.version.object_id) + others = self.version_record.revision.version_set.filter( + object_id=self.version_record.object_id + ).all() for p in others: - p_obj = p.object_version.object - if type(p_obj) != type(obj) and hasattr(p_obj,str(self.field.related_name)): - ids = [v.id for v in getattr(p_obj, str(self.field.related_name)).all()] - + if hasattr(p, '_object_version'): + p_obj = getattr(p, '_object_version').object + else: + p_obj = getattr(p, 'object_version').object + if type(p_obj) != type(obj) and hasattr(p_obj, str(self.field.related_name)): + ids = {force_text(v.id) for v in getattr(p_obj, str(self.field.related_name)).all()} else: - return ([], [], [], []) # TODO: refactory that + return {}, {}, [] # TODO: refactor that # Get the related model of the current field: related_model = self.field.field.model @@ -140,66 +148,55 @@ def get_many_to_many(self): returns a queryset with all many2many objects """ if self.field.get_internal_type() != "ManyToManyField": # FIXME! - return ([], [], [], []) # TODO: refactory that + return {}, {}, [] # TODO: refactor that elif self.value is DOES_NOT_EXIST: - return ([], [], [], []) # TODO: refactory that - - related_model = self.field.rel.to + return {}, {}, [] # TODO: refactor that - ids = None - if reversion_api.has_int_pk(related_model): - ids = [int(v) for v in self.value] # is: version.field_dict[field.name] + ids = frozenset(map(force_text, self.value)) # Get the related model of the current field: - return self.get_many_to_something(ids, related_model) - - def get_many_to_something(self, ids, related_model, is_reverse=False): + return self.get_many_to_something(ids, self.field.rel.to) + def get_many_to_something(self, target_ids, related_model, is_reverse=False): # get instance of reversion.models.Revision(): # A group of related object versions. - old_revision = self.version.revision + old_revision = self.version_record.revision # Get a queryset with all related objects. - versions = old_revision.version_set.filter( - content_type=ContentType.objects.get_for_model(related_model), - object_id__in=ids - ) - - if self.has_int_pk: - # The primary_keys would be stored in a text field -> convert it to integers - # This is interesting in different places! - for version in versions: - version.object_id = int(version.object_id) + versions = { + ver.object_id: ver for ver in old_revision.version_set.filter( + content_type=ContentType.objects.get_for_model(related_model), + object_id__in=target_ids + ).all() + } - missing_objects = [] - missing_ids = [] + missing_objects_dict = {} + deleted = [] - if self.field_name not in self.adapter.follow: + if not self.follow: # This models was not registered with follow relations # Try to fill missing related objects - target_ids = set(ids) - actual_ids = set([version.object_id for version in versions]) - missing_ids1 = target_ids.difference(actual_ids) - - # logger.debug(self.field_name, "target: %s - actual: %s - missing: %s" % (target_ids, actual_ids, missing_ids1)) - if missing_ids1: - missing_objects = related_model.objects.all().filter(pk__in=missing_ids1) - missing_ids = list(target_ids.difference(set(missing_objects.values_list('pk', flat=True)))) + potentially_missing_ids = target_ids.difference(frozenset(versions)) + # logger.debug(self.field_name, "target: %s - actual: %s - missing: %s" % (target_ids, versions, potentially_missing_ids)) + if potentially_missing_ids: + missing_objects_dict = { + force_text(rel.pk): rel + for rel in related_model.objects.filter(pk__in=potentially_missing_ids).iterator() + } - deleted = [] if is_reverse: - true_missing_objects = [] - for o in missing_objects: - for ver in reversion_api.get_for_object(o): - # An object can only be missing if it actually existed prior to this version - # Otherwise its a new item - if ver.revision.date_created < old_revision.date_created: - true_missing_objects.append(o) - missing_objects = true_missing_objects - deleted = [d for d in reversion_api.get_deleted(related_model) if d.revision == old_revision] - return versions, missing_objects, missing_ids, deleted - - def get_debug(self): + missing_objects_dict = { + ver.object_id: ver + for o in missing_objects_dict.values() + for ver in Version.objects.get_for_object(o) + if ver.revision.date_created < old_revision.date_created + } + + deleted = [d for d in Version.objects.get_deleted(related_model) if d.revision == old_revision] + + return versions, missing_objects_dict, deleted + + def get_debug(self): # pragma: no cover if not settings.DEBUG: return @@ -207,11 +204,9 @@ def get_debug(self): "field..............: %r" % self.field, "field_name.........: %r" % self.field_name, "field internal type: %r" % self.field.get_internal_type(), - "field_dict.........: %s" % repr(self.version.field_dict), - "adapter............: %r (follow: %r)" % (self.adapter, ", ".join(self.adapter.follow)), - "has_int_pk ........: %r" % self.has_int_pk, + "field_dict.........: %s" % repr(self.version_record.field_dict), "obj................: %r (pk: %s, id: %s)" % (self.obj, self.obj.pk, id(self.obj)), - "version............: %r (pk: %s, id: %s)" % (self.version, self.version.pk, id(self.version)), + "version............: %r (pk: %s, id: %s)" % (self.version_record, self.version_record.pk, id(self.version_record)), "value..............: %r" % self.value, "to string..........: %s" % repr(self.to_string()), "related............: %s" % repr(self.get_related()), @@ -220,12 +215,12 @@ def get_debug(self): if m2m_versions or missing_objects or missing_ids: result.append( "many-to-many.......: %s" % ", ".join( - ["%s (%s)" % ( - item, - item.type - ) for item in m2m_versions] + ["%s (%s)" % ( + item, + item.type + ) for item in m2m_versions] + ) ) - ) if missing_objects: result.append("missing m2m objects: %s" % repr(missing_objects)) @@ -241,7 +236,7 @@ def get_debug(self): return result - def debug(self): + def debug(self): # pragma: no cover if not settings.DEBUG: return for item in self.get_debug(): @@ -249,31 +244,30 @@ def debug(self): class CompareObjects(object): - def __init__(self, field, field_name, obj, version1, version2, manager, is_reversed): + def __init__(self, field, field_name, obj, version1, version2, is_reversed): self.field = field self.field_name = field_name self.obj = obj - model = self.obj.__class__ - self.has_int_pk = reversion_api.has_int_pk(model) - self.adapter = manager.get_adapter(model) # VersionAdapter instance - # is a related field (ForeignKey, ManyToManyField etc.) self.is_related = getattr(self.field, 'rel', None) is not None self.is_reversed = is_reversed if not self.is_related: self.follow = None - elif self.field_name in self.adapter.follow: + elif self.field_name in _get_options(self.obj.__class__).follow: self.follow = True else: self.follow = False - self.compare_obj1 = CompareObject(field, field_name, obj, version1, self.has_int_pk, self.adapter) - self.compare_obj2 = CompareObject(field, field_name, obj, version2, self.has_int_pk, self.adapter) + self.compare_obj1 = CompareObject(field, field_name, obj, version1, self.follow) + self.compare_obj2 = CompareObject(field, field_name, obj, version2, self.follow) self.value1 = self.compare_obj1.value self.value2 = self.compare_obj2.value + self.M2O_CHANGE_INFO = None + self.M2M_CHANGE_INFO = None + def changed(self): """ return True if at least one field has changed values. """ @@ -294,31 +288,17 @@ def changed(self): return self.compare_obj1 != self.compare_obj2 - def _get_result(self, compare_obj, func_name): - func = getattr(compare_obj, func_name) - result = func() - return result - - def _get_both_results(self, func_name): - result1 = self._get_result(self.compare_obj1, func_name) - result2 = self._get_result(self.compare_obj2, func_name) - return (result1, result2) - def to_string(self): - return self._get_both_results("to_string") + return self.compare_obj1.to_string(), self.compare_obj2.to_string() def get_related(self): - return self._get_both_results("get_related") + return self.compare_obj1.get_related(), self.compare_obj2.get_related() def get_many_to_many(self): - # return self._get_both_results("get_many_to_many") - m2m_data1, m2m_data2 = self._get_both_results("get_many_to_many") - return m2m_data1, m2m_data2 + return self.compare_obj1.get_many_to_many(), self.compare_obj2.get_many_to_many() def get_reverse_foreign_key(self): - return self._get_both_results("get_reverse_foreign_key") - - M2O_CHANGE_INFO = None + return self.compare_obj1.get_reverse_foreign_key(), self.compare_obj2.get_reverse_foreign_key() def get_m2o_change_info(self): if self.M2O_CHANGE_INFO is not None: @@ -329,8 +309,6 @@ def get_m2o_change_info(self): self.M2O_CHANGE_INFO = self.get_m2s_change_info(m2o_data1, m2o_data2) return self.M2O_CHANGE_INFO - M2M_CHANGE_INFO = None - def get_m2m_change_info(self): if self.M2M_CHANGE_INFO is not None: return self.M2M_CHANGE_INFO @@ -341,51 +319,39 @@ def get_m2m_change_info(self): return self.M2M_CHANGE_INFO # Abstract Many-to-Something (either -many or -one) as both - # many2many and many2one relationships looks the same from the refered object. + # many2many and many2one relationships looks the same from the referred object. def get_m2s_change_info(self, obj1_data, obj2_data): - result1, missing_objects1, missing_ids1, deleted1 = obj1_data - result2, missing_objects2, missing_ids2, deleted2 = obj2_data - - # missing_objects_pk1 = [obj.pk for obj in missing_objects1] - # missing_objects_pk2 = [obj.pk for obj in missing_objects2] - missing_objects_dict2 = dict([(obj.pk, obj) for obj in missing_objects2]) - - # logger.debug("missing_objects1: %s", missing_objects1) - # logger.debug("missing_objects2: %s", missing_objects2) - # logger.debug("missing_ids1: %s", missing_ids1) - # logger.debug("missing_ids2: %s", missing_ids2) - - missing_object_set1 = set(missing_objects1) - missing_object_set2 = set(missing_objects2) - # logger.debug("%s %s", missing_object_set1, missing_object_set2) - - same_missing_objects = missing_object_set1.intersection(missing_object_set2) - removed_missing_objects = missing_object_set1.difference(missing_object_set2) - added_missing_objects = missing_object_set2.difference(missing_object_set1) - - # logger.debug("same_missing_objects: %s", same_missing_objects) - # logger.debug("removed_missing_objects: %s", removed_missing_objects) - # logger.debug("added_missing_objects: %s", added_missing_objects) - + result_dict1, missing_objects_dict1, deleted1 = obj1_data + result_dict2, missing_objects_dict2, deleted2 = obj2_data # Create same_items, removed_items, added_items with related m2m items - changed_items = [] removed_items = [] added_items = [] same_items = [] - primary_keys1 = [version.object_id for version in result1] - primary_keys2 = [version.object_id for version in result2] - - result_dict1 = dict([(version.object_id, version) for version in result1]) - result_dict2 = dict([(version.object_id, version) for version in result2]) + same_missing_objects_dict = { + k: v for k, v in + missing_objects_dict1.items() + if k in missing_objects_dict2 + } + removed_missing_objects_dict = { + k: v for k, v in + missing_objects_dict1.items() + if k not in missing_objects_dict2 + } + added_missing_objects_dict = { + k: v for k, v in + missing_objects_dict2.items() + if k not in missing_objects_dict1 + } - # logger.debug(result_dict1) - # logger.debug(result_dict2) + # logger.debug("same_missing_objects: %s", same_missing_objects_dict) + # logger.debug("removed_missing_objects: %s", removed_missing_objects_dict) + # logger.debug("added_missing_objects: %s", added_missing_objects_dict) - for primary_key in set(primary_keys1).union(set(primary_keys2)): + for primary_key in set().union(result_dict1.keys(), result_dict2.keys()): if primary_key in result_dict1: version1 = result_dict1[primary_key] else: @@ -396,33 +362,40 @@ def get_m2s_change_info(self, obj1_data, obj2_data): else: version2 = None - #logger.debug("%r - %r - %r", primary_key, version1, version2) + # logger.debug("%r - %r - %r", primary_key, version1, version2) if version1 is not None and version2 is not None: # In both -> version changed or the same if version1.serialized_data == version2.serialized_data: - #logger.debug("same item: %s", version1) + # logger.debug("same item: %s", version1) same_items.append(version1) else: changed_items.append((version1, version2)) elif version1 is not None and version2 is None: # In 1 but not in 2 -> removed - #logger.debug("%s %s", primary_key, missing_objects_pk2) - #logger.debug("%s %s", repr(primary_key), repr(missing_objects_pk2)) - if primary_key in missing_objects_dict2: - missing_object = missing_objects_dict2[primary_key] - added_missing_objects.remove(missing_object) - same_missing_objects.add(missing_object) + # logger.debug("%s %s", primary_key, missing_objects_dict2) + # logger.debug("%s %s", repr(primary_key), repr(missing_objects_dict2)) + if primary_key in added_missing_objects_dict: + added_missing_objects_dict.pop(primary_key) + same_missing_objects_dict[primary_key] = missing_objects_dict2[primary_key] continue - removed_items.append(version1) elif version1 is None and version2 is not None: # In 2 but not in 1 -> added - #logger.debug("added: %s", version2) + # logger.debug("added: %s", version2) added_items.append(version2) else: raise RuntimeError() + # In Place Sorting of Lists (exclude changed since its a tuple) + removed_items.sort(key=lambda item: str(item)) + added_items.sort(key=lambda item: str(item)) + same_items.sort(key=lambda item: str(item)) + deleted1.sort(key=lambda item: str(item)) + same_missing_objects = sorted(same_missing_objects_dict.values(), key=lambda item: str(item)) + removed_missing_objects = sorted(removed_missing_objects_dict.values(), key=lambda item: str(item)) + added_missing_objects = sorted(added_missing_objects_dict.values(), key=lambda item: str(item)) + return { "changed_items": changed_items, "removed_items": removed_items, @@ -434,8 +407,7 @@ def get_m2s_change_info(self, obj1_data, obj2_data): "deleted_items": deleted1, } - - def debug(self): + def debug(self): # pragma: no cover if not settings.DEBUG: return logger.debug("_______________________________") @@ -469,4 +441,3 @@ def debug(self): logger.debug(item) logger.debug("-" * 79) - diff --git a/reversion_compare/forms.py b/reversion_compare/forms.py index f80b51b..d9471c7 100644 --- a/reversion_compare/forms.py +++ b/reversion_compare/forms.py @@ -2,6 +2,7 @@ from django import forms + class SelectDiffForm(forms.Form): version_id1 = forms.IntegerField(min_value=1) version_id2 = forms.IntegerField(min_value=1) diff --git a/reversion_compare/helpers.py b/reversion_compare/helpers.py index 8df0f84..00a63e6 100644 --- a/reversion_compare/helpers.py +++ b/reversion_compare/helpers.py @@ -15,7 +15,6 @@ :license: GNU GPL v3 or above, see LICENSE for more details. """ - import difflib import logging @@ -34,11 +33,9 @@ # http://code.google.com/p/google-diff-match-patch/ from diff_match_patch import diff_match_patch except ImportError: - google_diff_match_patch = False + dmp = None else: - google_diff_match_patch = True dmp = diff_match_patch() -#google_diff_match_patch = False # manually disable, for testing def highlight_diff(diff_text): @@ -67,22 +64,6 @@ def highlight_diff(diff_text): LINE_COUNT_4_UNIFIED_DIFF = 4 -def format_range(start, stop): - """ - Convert range to the "ed" format - difflib._format_range_unified() is new in python 2.7 - see also: https://github.com/jedie/django-reversion-compare/issues/5 - """ - # Per the diff spec at http://www.unix.org/single_unix_specification/ - beginning = start + 1 # lines start numbering with one - length = stop - start - if length == 1: - return '{0}'.format(beginning) - if not length: - beginning -= 1 # empty ranges begin at line just before the range - return '{0},{1}'.format(beginning, length) - - def unified_diff(a, b, n=3, lineterm='\n'): r""" simmilar to the original difflib.unified_diff except: @@ -105,8 +86,8 @@ def unified_diff(a, b, n=3, lineterm='\n'): started = False for group in difflib.SequenceMatcher(None, a, b).get_grouped_opcodes(n): first, last = group[0], group[-1] - file1_range = format_range(first[1], last[2]) - file2_range = format_range(first[3], last[4]) + file1_range = difflib._format_range_unified(first[1], last[2]) + file2_range = difflib._format_range_unified(first[3], last[4]) if not started: started = True @@ -136,7 +117,7 @@ def html_diff(value1, value2, cleanup=SEMANTIC): """ value1 = force_text(value1) value2 = force_text(value2) - if google_diff_match_patch: + if dmp is not None: # Generate the diff with google-diff-match-patch diff = dmp.diff_main(value1, value2) if cleanup == SEMANTIC: @@ -220,10 +201,9 @@ class PatchedModelAdmin(AdminClass, ModelAdmin): admin_site.register(model, PatchedModelAdmin) - if __name__ == "__main__": import doctest print(doctest.testmod( -# verbose=True verbose=False + # verbose=True )) diff --git a/reversion_compare/mixins.py b/reversion_compare/mixins.py index c69748f..98b54f3 100644 --- a/reversion_compare/mixins.py +++ b/reversion_compare/mixins.py @@ -12,14 +12,12 @@ from django.template.loader import render_to_string from reversion_compare.helpers import html_diff -from reversion.revisions import default_revision_manager - from reversion_compare.compare import CompareObjects + class CompareMixin(object, ): """A mixin to add comparison capabilities to your views""" - - revision_manager = default_revision_manager + # list/tuple of field names for the compare view. Set to None for all existing fields compare_fields = None @@ -45,8 +43,8 @@ def _get_compare(self, obj_compare): """ def _get_compare_func(suffix): - func_name = "compare_%s" % suffix # logger.debug("func_name: %s", func_name) + func_name = "compare_%s" % suffix if hasattr(self, func_name): func = getattr(self, func_name) return func @@ -102,7 +100,7 @@ def compare(self, obj, version1, version2): ) if isinstance(f, models.ForeignKey) and f not in fields: self.reverse_fields.append(f.rel) - #print(self.reverse_fields) + fields += self.reverse_fields has_unfollowed_fields = False @@ -121,8 +119,8 @@ def compare(self, obj, version1, version2): continue is_reversed = field in self.reverse_fields - obj_compare = CompareObjects(field, field_name, obj, version1, version2, self.revision_manager, is_reversed) - #obj_compare.debug() + obj_compare = CompareObjects(field, field_name, obj, version1, version2, is_reversed) + # obj_compare.debug() is_related = obj_compare.is_related follow = obj_compare.follow @@ -171,9 +169,8 @@ def generic_add_remove(self, raw_value1, raw_value2, value1, value2): def compare_ForeignKey(self, obj_compare): related1, related2 = obj_compare.get_related() - obj_compare.debug() + # obj_compare.debug() value1, value2 = str(related1), str(related2) - # value1, value2 = repr(related1), repr(related2) return self.generic_add_remove(related1, related2, value1, value2) def simple_compare_ManyToManyField(self, obj_compare): @@ -215,7 +212,7 @@ def compare_FileField(self, obj_compare): return self.generic_add_remove(value1, value2, value1, value2) def compare_DateTimeField(self, obj_compare): - ''' compare all model datetime field in ISO format ''' + """ compare all model datetime field in ISO format """ context = { "date1": obj_compare.value1, "date2": obj_compare.value2, @@ -223,7 +220,7 @@ def compare_DateTimeField(self, obj_compare): return render_to_string("reversion-compare/compare_DateTimeField.html", context) def compare_BooleanField(self, obj_compare): - ''' compare booleans as a complete field, rather than as a string ''' + """ compare booleans as a complete field, rather than as a string """ context = { "bool1": obj_compare.value1, "bool2": obj_compare.value2, diff --git a/reversion_compare/reversion_api.py b/reversion_compare/reversion_api.py deleted file mode 100644 index 2bfe2ab..0000000 --- a/reversion_compare/reversion_api.py +++ /dev/null @@ -1,19 +0,0 @@ - -import reversion -if reversion.__version__ > (1,10): - from reversion import revisions as reversion - from reversion.revisions import ( - register, unregister, is_registered, - get_for_object, get_registered_models, get_deleted, - create_revision, set_comment - ) -else: - # django-reversion <= 1.9 - from reversion import ( - register, unregister, is_registered, - get_for_object, get_registered_models, get_deleted, - create_revision, set_comment - ) - - -from reversion.models import Revision, Version, has_int_pk \ No newline at end of file diff --git a/reversion_compare/views.py b/reversion_compare/views.py index 754b7ed..7b49587 100644 --- a/reversion_compare/views.py +++ b/reversion_compare/views.py @@ -2,9 +2,12 @@ from django.shortcuts import get_object_or_404 from django.views.generic.detail import DetailView +from reversion.models import Version + from reversion_compare.forms import SelectDiffForm from reversion_compare.mixins import CompareMixin, CompareMethodsMixin + class HistoryCompareDetailView(CompareMixin, CompareMethodsMixin, DetailView): """This class can be used to add a non-admin view for comparing your object's versions. @@ -49,14 +52,13 @@ class SimpleModelHistoryCompareView(HistoryCompareDetailView): """ def _get_action_list(self, ): - opts = self.model._meta action_list = [ { "version": version, "revision": version.revision, } for version - in self._order_version_queryset(self.revision_manager.get_for_object( + in self._order_version_queryset(Version.objects.get_for_object( self.get_object(), ).select_related("revision__user")) ] @@ -93,7 +95,7 @@ def get_context_data(self, **kwargs): version_id1, version_id2 = version_id2, version_id1 obj = self.get_object() - queryset = self.revision_manager.get_for_object(obj) + queryset = Version.objects.get_for_object(obj) version1 = get_object_or_404(queryset, pk=version_id1) version2 = get_object_or_404(queryset, pk=version_id2) @@ -120,7 +122,6 @@ def get_context_data(self, **kwargs): ) context.update({'prev_url': prev_url}) - # Compile the context. context.update({ "action_list": action_list, diff --git a/setup.py b/setup.py index 2e6ad62..7b478b9 100755 --- a/setup.py +++ b/setup.py @@ -182,10 +182,6 @@ def rmtree(path): sys.exit(0) - - - - def get_authors(): try: with open(os.path.join(PACKAGE_ROOT, "AUTHORS"), "r") as f: @@ -207,29 +203,27 @@ def get_authors(): url='https://github.com/jedie/django-reversion-compare/', download_url='http://pypi.python.org/pypi/django-reversion-compare/', packages=find_packages(), - include_package_data=True, # include package data under svn source control + include_package_data=True, install_requires=[ "Django>=1.8", - "django-reversion>=1.9", + "django-reversion>=2.0,<2.1", ], tests_require=[ "django-tools", # https://github.com/jedie/django-tools/ ], zip_safe=False, classifiers=[ -# "Development Status :: 4 - Beta", "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", -# "Intended Audience :: Education", -# "Intended Audience :: End Users/Desktop", "License :: OSI Approved :: GNU General Public License (GPL)", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", "Framework :: Django", - "Framework :: Django :: 1.7", "Framework :: Django :: 1.8", + "Framework :: Django :: 1.9", "Topic :: Database :: Front-Ends", "Topic :: Documentation", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", diff --git a/tests/admin.py b/tests/admin.py index f6da10d..4152ab5 100644 --- a/tests/admin.py +++ b/tests/admin.py @@ -12,10 +12,6 @@ from __future__ import unicode_literals, print_function - -from reversion.models import Revision, Version -from reversion.revisions import RevisionManager - from django.contrib import admin from reversion_compare.admin import CompareVersionAdmin @@ -23,7 +19,6 @@ VariantModel, CustomModel, Identity - class SimpleModelAdmin(CompareVersionAdmin): pass admin.site.register(SimpleModel, SimpleModelAdmin) @@ -33,6 +28,7 @@ class FactoryAdmin(CompareVersionAdmin): pass admin.site.register(Factory, FactoryAdmin) + class CarAdmin(CompareVersionAdmin): pass admin.site.register(Car, CarAdmin) @@ -42,6 +38,7 @@ class PersonAdmin(CompareVersionAdmin): pass admin.site.register(Person, PersonAdmin) + class PetAdmin(CompareVersionAdmin): pass admin.site.register(Pet, PetAdmin) @@ -52,16 +49,14 @@ class VariantModelAdmin(CompareVersionAdmin): admin.site.register(VariantModel, VariantModelAdmin) -custom_revision_manager = RevisionManager("custom") - class CustomModelAdmin(CompareVersionAdmin): - revision_manager = custom_revision_manager + pass + admin.site.register(CustomModel, CustomModelAdmin) admin.site.register(Identity, CustomModelAdmin) - """ class RelatedModelInline(admin.StackedInline): model = RelatedModel diff --git a/tests/models.py b/tests/models.py index 74e3205..f55e42d 100644 --- a/tests/models.py +++ b/tests/models.py @@ -17,17 +17,17 @@ from django.utils.encoding import python_2_unicode_compatible from django.db import models - -from reversion_compare import reversion_api +from reversion import revisions @python_2_unicode_compatible class SimpleModel(models.Model): text = models.CharField(max_length=255) + def __str__(self): return "SimpleModel pk: %r text: %r" % (self.pk, self.text) -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ """ models with relationships @@ -42,23 +42,29 @@ def __str__(self): https://github.com/etianen/django-reversion/wiki/Low-level-API """ + @python_2_unicode_compatible class Building(models.Model): address = models.CharField(max_length=128) + def __str__(self): return self.address + @python_2_unicode_compatible class Factory(Building): name = models.CharField(max_length=128) + def __str__(self): return self.name + @python_2_unicode_compatible class Car(models.Model): name = models.CharField(max_length=128) manufacturer = models.ForeignKey(Factory, related_name="cars") supplier = models.ManyToManyField(Factory, related_name="suppliers", blank=True) + def __str__(self): return "%s from %s supplier(s): %s" % (self.name, self.manufacturer, ", ".join([s.name for s in self.supplier.all()])) @@ -66,28 +72,32 @@ def __str__(self): @python_2_unicode_compatible class Pet(models.Model): name = models.CharField(max_length=100) + def __str__(self): return self.name + @python_2_unicode_compatible class Person(models.Model): name = models.CharField(max_length=100) pets = models.ManyToManyField(Pet, blank=True) # If you work someone, its at a build, but maybe not a factory! workplace = models.ForeignKey(Building, related_name="workers", null=True) + def __str__(self): return self.name + @python_2_unicode_compatible class Identity(models.Model): id_numer = models.CharField(max_length=100) person = models.OneToOneField(Person, related_name='_identity') + def __str__(self): return self.id_numer -reversion_api.register(Person, follow=["pets"]) -#reversion_api.register(Pet, follow=["person_set"]) -reversion_api.register(Pet) +revisions.register(Person, follow=["pets"]) +revisions.register(Pet) @python_2_unicode_compatible @@ -130,6 +140,8 @@ class VariantModel(models.Model): email = models.EmailField(blank=True, null=True) url = models.URLField(blank=True, null=True) + file_field = models.FileField(blank=True, null=True) + filepath = models.FilePathField( path=settings.UNITTEST_TEMP_PATH, blank=True, null=True @@ -140,10 +152,9 @@ class VariantModel(models.Model): def __str__(self): return "VariantModel instance pk: %i" % self.pk -#------------------------------------------------------------------------------ class CustomModel(models.Model): - "Model which uses a custom version manager." + """Model which uses a custom version manager.""" text = models.TextField() """ diff --git a/tests/test_custom_model.py b/tests/test_custom_model.py index 2ee73b8..0c659cd 100644 --- a/tests/test_custom_model.py +++ b/tests/test_custom_model.py @@ -17,7 +17,8 @@ from __future__ import absolute_import, division, print_function -from django.core.urlresolvers import reverse +from reversion import create_revision +from reversion.models import Revision, Version try: import django_tools @@ -29,21 +30,15 @@ ) % err raise ImportError(msg) - -from reversion_compare import reversion_api - +from django.core.urlresolvers import reverse from tests.models import CustomModel - -# Needs to import admin module to register all models via CompareVersionAdmin/VersionAdmin -from tests.admin import custom_revision_manager - from .test_utils.test_cases import BaseTestCase from .test_utils.test_data import TestData class CustomModelTest(BaseTestCase): - "Test a model which uses a custom reversion manager." + """Test a model which uses a custom reversion manager.""" def setUp(self): super(CustomModelTest, self).setUp() @@ -51,18 +46,17 @@ def setUp(self): self.item = test_data.create_CustomModel_data() def test_initial_state(self): - "Test initial data creation and model registration." - self.assertTrue(custom_revision_manager.is_registered(CustomModel)) + """"Test initial data creation and model registration.""" self.assertEqual(CustomModel.objects.count(), 1) - self.assertEqual(custom_revision_manager.get_for_object(self.item).count(), 1) - self.assertEqual(reversion_api.Revision.objects.all().count(), 1) + self.assertEqual(Version.objects.get_for_object(self.item).count(), 1) + self.assertEqual(Revision.objects.all().count(), 1) def test_text_diff(self): - "Generate a new revision and check for a correctly generated diff." - with reversion_api.create_revision(): + """"Generate a new revision and check for a correctly generated diff.""" + with create_revision(): self.item.text = "version two" self.item.save() - queryset = custom_revision_manager.get_for_object(self.item) + queryset = Version.objects.get_for_object(self.item) version_ids = queryset.values_list("pk", flat=True) self.assertEqual(len(version_ids), 2) url_name = 'admin:%s_%s_compare' % (CustomModel._meta.app_label, CustomModel._meta.model_name) @@ -73,20 +67,21 @@ def test_text_diff(self): self.assertContains(response, "+ version two") def test_version_selection(self): - "Generate two revisions and view the version history selection." - with reversion_api.create_revision(): + """Generate two revisions and view the version history selection.""" + with create_revision(): self.item.text = "version two" self.item.save() - with reversion_api.create_revision(): + with create_revision(): self.item.text = "version three" self.item.save() - queryset = custom_revision_manager.get_for_object(self.item) + queryset = Version.objects.get_for_object(self.item) version_ids = queryset.values_list("pk", flat=True) self.assertEqual(len(version_ids), 3) url_name = 'admin:%s_%s_history' % (CustomModel._meta.app_label, CustomModel._meta.model_name) history_url = reverse(url_name, args=(self.item.pk, )) response = self.client.get(history_url) - self.assertContainsHtml(response, + self.assertContainsHtml( + response, '', '' % version_ids[0], '' % version_ids[0], diff --git a/tests/test_factory_car_models.py b/tests/test_factory_car_models.py index 17d70f3..a53b380 100644 --- a/tests/test_factory_car_models.py +++ b/tests/test_factory_car_models.py @@ -17,6 +17,9 @@ from __future__ import absolute_import, division, print_function +from reversion import create_revision +from reversion import is_registered +from reversion.models import Revision, Version try: import django_tools @@ -27,18 +30,13 @@ " - Original error: %s" ) % err raise ImportError(msg) -from django_tools.unittest_utils.BrowserDebug import debug_response -from reversion_compare import reversion_api - - -from reversion_compare import helpers - from .models import Factory, Car from .test_utils.test_cases import BaseTestCase from .test_utils.test_data import TestData + class FactoryCarModelTest(BaseTestCase): """ unittests that used: @@ -52,24 +50,25 @@ def setUp(self): super(FactoryCarModelTest, self).setUp() test_data = TestData(verbose=False) -# test_data = TestData(verbose=True) + # test_data = TestData(verbose=True) self.car = test_data.create_FactoryCar_data() - queryset = reversion_api.get_for_object(self.car) + queryset = Version.objects.get_for_object(self.car) self.version_ids = queryset.values_list("pk", flat=True) def test_initial_state(self): - self.assertTrue(reversion_api.is_registered(Factory)) - self.assertTrue(reversion_api.is_registered(Car)) + self.assertTrue(is_registered(Factory)) + self.assertTrue(is_registered(Car)) - self.assertEqual(reversion_api.Revision.objects.all().count(), 3) + self.assertEqual(Revision.objects.all().count(), 3) self.assertEqual(len(self.version_ids), 3) - self.assertEqual(reversion_api.Version.objects.all().count(), 17) + self.assertEqual(Version.objects.all().count(), 17) def test_select_compare(self): response = self.client.get("/admin/tests/car/%s/history/" % self.car.pk) -# debug_response(response) # from django-tools - self.assertContainsHtml(response, + # debug_response(response) # from django-tools + self.assertContainsHtml( + response, '', '' % self.version_ids[0], '' % self.version_ids[0], @@ -82,11 +81,11 @@ def test_select_compare(self): def test_diff1(self): response = self.client.get( "/admin/tests/car/%s/history/compare/" % self.car.pk, - data={"version_id2":self.version_ids[1], "version_id1":self.version_ids[2]} + data={"version_id2": self.version_ids[1], "version_id1": self.version_ids[2]} ) -# debug_response(response) # from django-tools - - self.assertContainsHtml(response, + # debug_response(response) # from django-tools + self.assertContainsHtml( + response, '

manufacturer

', '

supplier

', ''' @@ -97,18 +96,18 @@ def test_diff1(self): always the same supplier

''', - '', # info for non-follow related informations - '
version 2: change ForeignKey and ManyToManyField.
', # edit comment + '', # info for non-follow related informations + '
version 2: change ForeignKey and ManyToManyField.
', ) def test_diff2(self): response = self.client.get( "/admin/tests/car/%s/history/compare/" % self.car.pk, - data={"version_id2":self.version_ids[0], "version_id1":self.version_ids[1]} + data={"version_id2": self.version_ids[0], "version_id1":self.version_ids[1]} ) -# debug_response(response) # from django-tools - - self.assertContainsHtml(response, + # debug_response(response) # from django-tools + self.assertContainsHtml( + response, "- motor-car one", "+ motor-car II", @@ -120,12 +119,11 @@ def test_diff2(self): always the same supplier

''', - '', # info for non-follow related informations - '
version 3: change CharField, ForeignKey and ManyToManyField.
', # edit comment + '', # info for non-follow related informations + '
version 3: change CharField, ForeignKey and ManyToManyField.
', ) - class FactoryCarModelTest2(BaseTestCase): """ unittests that used: @@ -137,14 +135,14 @@ class FactoryCarModelTest2(BaseTestCase): """ def test_initial_state(self): - self.assertTrue(reversion_api.is_registered(Factory)) - self.assertTrue(reversion_api.is_registered(Car)) + self.assertTrue(is_registered(Factory)) + self.assertTrue(is_registered(Car)) self.assertEqual(Factory.objects.all().count(), 0) self.assertEqual(Car.objects.all().count(), 0) - self.assertEqual(reversion_api.Revision.objects.all().count(), 0) - self.assertEqual(reversion_api.Version.objects.all().count(), 0) + self.assertEqual(Revision.objects.all().count(), 0) + self.assertEqual(Version.objects.all().count(), 0) def test_deleted_objects(self): """ @@ -152,30 +150,29 @@ def test_deleted_objects(self): https://github.com/jedie/django-reversion-compare/commit/ba22008130f4c16a32eeb900381c2d82ca6fdd9e https://travis-ci.org/jedie/django-reversion-compare/builds/72317520 """ - with reversion_api.create_revision(): + with create_revision(): factory1 = Factory.objects.create(name="factory one", address="1 Fake Plaza") car = Car.objects.create( name="car", manufacturer=factory1 ) - with reversion_api.create_revision(): + with create_revision(): factory2 = Factory.objects.create(name="factory two", address="1 Fake Plaza") - car.manufacturer=factory2 + car.manufacturer = factory2 car.save() - with reversion_api.create_revision(): + with create_revision(): factory1.delete() - queryset = reversion_api.get_for_object(car) + queryset = Version.objects.get_for_object(car) version_ids = queryset.values_list("pk", flat=True) # [3, 2] # print("\n", version_ids) # response = self.client.get("/admin/tests/car/%s/history/" % car.pk) # debug_response(response) # from django-tools - - response = self.client.get( + self.client.get( "/admin/tests/car/%s/history/compare/" % car.pk, - data={"version_id2":version_ids[0], "version_id1":version_ids[1]} + data={"version_id2": version_ids[0], "version_id1": version_ids[1]} ) # debug_response(response) # from django-tools diff --git a/tests/test_factory_car_reverse_models.py b/tests/test_factory_car_reverse_models.py index b034d07..b471543 100644 --- a/tests/test_factory_car_reverse_models.py +++ b/tests/test_factory_car_reverse_models.py @@ -17,6 +17,9 @@ from __future__ import absolute_import, division, print_function +from reversion import is_registered +from reversion import unregister, revisions +from reversion.models import Version, Revision try: import django_tools @@ -27,14 +30,12 @@ " - Original error: %s" ) % err raise ImportError(msg) -from django_tools.unittest_utils.BrowserDebug import debug_response - -from reversion_compare import reversion_api from .models import Factory, Car, Person from .test_utils.test_cases import BaseTestCase from .test_utils.test_data import TestData + class FactoryCarReverseRelationModelTest(BaseTestCase): """ unittests that used: @@ -45,31 +46,32 @@ class FactoryCarReverseRelationModelTest(BaseTestCase): so no relation data would be stored """ def setUp(self): - reversion_api.unregister(Person) - reversion_api.unregister(Car) - reversion_api.unregister(Factory) - reversion_api.register(Factory, follow=["building_ptr","cars","workers"]) - reversion_api.register(Car) - reversion_api.register(Person, follow=["pets"]) + unregister(Person) + unregister(Car) + unregister(Factory) + revisions.register(Factory, follow=["building_ptr", "cars", "workers"]) + revisions.register(Car) + revisions.register(Person, follow=["pets"]) super(FactoryCarReverseRelationModelTest, self).setUp() test_data = TestData(verbose=False) self.factory = test_data.create_Factory_reverse_relation_data() - queryset = reversion_api.get_for_object(self.factory) + queryset = Version.objects.get_for_object(self.factory) self.version_ids = queryset.values_list("pk", flat=True) def test_initial_state(self): - self.assertTrue(reversion_api.is_registered(Factory)) - self.assertTrue(reversion_api.is_registered(Car)) - self.assertEqual(reversion_api.Revision.objects.all().count(), 3) + self.assertTrue(is_registered(Factory)) + self.assertTrue(is_registered(Car)) + self.assertTrue(is_registered(Person)) + self.assertEqual(Revision.objects.all().count(), 3) self.assertEqual(len(self.version_ids), 3) - self.assertEqual(reversion_api.Version.objects.all().count(), 19) + self.assertEqual(Version.objects.all().count(), 19) def test_select_compare(self): response = self.client.get("/admin/tests/factory/%s/history/" % self.factory.pk) -# debug_response(response) # from django-tools - - self.assertContainsHtml(response, + # debug_response(response) # from django-tools + self.assertContainsHtml( + response, '', '' % self.version_ids[0], '' % self.version_ids[0], @@ -79,14 +81,14 @@ def test_select_compare(self): '' % self.version_ids[2], ) - def test_diff1(self): response = self.client.get( "/admin/tests/factory/%s/history/compare/" % self.factory.pk, - data={"version_id2":self.version_ids[2], "version_id1":self.version_ids[1]} + data={"version_id2": self.version_ids[1], "version_id1": self.version_ids[2]} ) - #debug_response(response) # from django-tools - self.assertContainsHtml(response, + # debug_response(response) # from django-tools + self.assertContainsHtml( + response, '''

- motor-car three from factory one supplier(s): → Deleted
@@ -99,6 +101,5 @@ def test_diff1(self): + Bob Bobertson

''', - '
version 2: discontinued car-three, add car-four, add Bob the worker
', # edit comment + '
version 2: discontinued car-three, add car-four, add Bob the worker
', # edit comment ) - diff --git a/tests/test_onetoone_field.py b/tests/test_onetoone_field.py index 01ed783..2f8e0ba 100644 --- a/tests/test_onetoone_field.py +++ b/tests/test_onetoone_field.py @@ -10,12 +10,13 @@ TODO: * models.IntegerField() - :copyleft: 2012-2015 by the django-reversion-compare team, see AUTHORS for more details. + :copyleft: 2012-2016 by the django-reversion-compare team, see AUTHORS for more details. :license: GNU GPL v3 or above, see LICENSE for more details. """ from __future__ import absolute_import, division, print_function +from reversion.models import Version try: import django_tools @@ -27,10 +28,6 @@ ) % err raise ImportError(msg) -try: - from reversion.revisions import get_for_object -except ImportError: - from reversion import get_for_object from .test_utils.test_cases import BaseTestCase from .test_utils.test_data import TestData @@ -44,13 +41,14 @@ def setUp(self): test_data = TestData(verbose=False) self.person, self.item = test_data.create_PersonIdentity_data() - queryset = get_for_object(self.person) + queryset = Version.objects.get_for_object(self.person) self.version_ids = queryset.values_list("pk", flat=True) def test_select_compare(self): response = self.client.get("/admin/tests/person/%s/history/" % self.person.pk) - self.assertContainsHtml(response, + self.assertContainsHtml( + response, '', '' % self.version_ids[0], '' % self.version_ids[0], @@ -61,10 +59,11 @@ def test_select_compare(self): def test_compare(self): response = self.client.get( "/admin/tests/person/%s/history/compare/" % self.person.pk, - data={"version_id2":self.version_ids[0], "version_id1":self.version_ids[1]} + data={"version_id2": self.version_ids[0], "version_id1": self.version_ids[1]} ) - self.assertContainsHtml(response, + self.assertContainsHtml( + response, """
                 - Dave
diff --git a/tests/test_person_pet_models.py b/tests/test_person_pet_models.py
index 6bf7dab..905982b 100644
--- a/tests/test_person_pet_models.py
+++ b/tests/test_person_pet_models.py
@@ -17,6 +17,10 @@
 
 from __future__ import absolute_import, division, print_function
 
+from reversion import create_revision
+from reversion import is_registered
+from reversion import set_comment
+from reversion.models import Version, Revision
 
 try:
     import django_tools
@@ -29,16 +33,13 @@
     raise ImportError(msg)
 
 
-from reversion_compare import reversion_api
-
-
 from tests.models import Person, Pet
 
 # Needs to import admin module to register all models via CompareVersionAdmin/VersionAdmin
-
 from .test_utils.test_cases import BaseTestCase
 from .test_utils.test_data import TestData
 
+
 class PersonPetModelTest(BaseTestCase):
     """
     unittests that used:
@@ -55,25 +56,26 @@ def setUp(self):
         super(PersonPetModelTest, self).setUp()
 
         test_data = TestData(verbose=False)
-#        test_data = TestData(verbose=True)
+        # test_data = TestData(verbose=True)
         self.pet1, self.pet2, self.person = test_data.create_PersonPet_data()
 
-        queryset = reversion_api.get_for_object(self.person)
+        queryset = Version.objects.get_for_object(self.person)
         self.version_ids = queryset.values_list("pk", flat=True)
 
     def test_initial_state(self):
-        self.assertTrue(reversion_api.is_registered(Pet))
-        self.assertTrue(reversion_api.is_registered(Person))
+        self.assertTrue(is_registered(Pet))
+        self.assertTrue(is_registered(Person))
 
         self.assertEqual(Pet.objects.count(), 3)
 
-        self.assertEqual(reversion_api.get_for_object(self.pet1).count(), 2)
-        self.assertEqual(reversion_api.Revision.objects.all().count(), 2)
+        self.assertEqual(Version.objects.get_for_object(self.pet1).count(), 2)
+        self.assertEqual(Revision.objects.all().count(), 2)
 
     def test_select_compare(self):
         response = self.client.get("/admin/tests/person/%s/history/" % self.person.pk)
-#        debug_response(response) # from django-tools
-        self.assertContainsHtml(response,
+        # debug_response(response) # from django-tools
+        self.assertContainsHtml(
+            response,
             '',
             '' % self.version_ids[0],
             '' % self.version_ids[0],
@@ -84,11 +86,11 @@ def test_select_compare(self):
     def test_diff(self):
         response = self.client.get(
             "/admin/tests/person/%s/history/compare/" % self.person.pk,
-            data={"version_id2":self.version_ids[0], "version_id1":self.version_ids[1]}
+            data={"version_id2": self.version_ids[0], "version_id1": self.version_ids[1]}
         )
-#        debug_response(response) # from django-tools
-
-        self.assertContainsHtml(response,
+        # debug_response(response) # from django-tools
+        self.assertContainsHtml(
+            response,
             """
             

would be changed petIs changed pet
@@ -97,30 +99,32 @@ def test_diff(self): always the same pet

""", - "
version 2: change follow related pets.
", # edit comment + "
version 2: change follow related pets.
", # edit comment ) - self.assertNotContainsHtml(response, - "

name

", # person name doesn't changed - 'class="follow"'# All fields are under reversion control + self.assertNotContainsHtml( + response, + "

name

", # person name doesn't changed + 'class="follow"' # All fields are under reversion control ) def test_add_m2m(self): - with reversion_api.create_revision(): + with create_revision(): new_pet = Pet.objects.create(name="added pet") self.person.pets.add(new_pet) self.person.save() - reversion_api.set_comment("version 3: add a pet") + set_comment("version 3: add a pet") - self.assertEqual(reversion_api.Revision.objects.all().count(), 3) - self.assertEqual(reversion_api.Version.objects.all().count(), 12) + self.assertEqual(Revision.objects.all().count(), 3) + self.assertEqual(Version.objects.all().count(), 12) - queryset = reversion_api.get_for_object(self.person) + queryset = Version.objects.get_for_object(self.person) version_ids = queryset.values_list("pk", flat=True) self.assertEqual(len(version_ids), 3) response = self.client.get("/admin/tests/person/%s/history/" % self.person.pk) -# debug_response(response) # from django-tools - self.assertContainsHtml(response, + # debug_response(response) # from django-tools + self.assertContainsHtml( + response, '', '' % version_ids[0], '' % version_ids[0], @@ -132,11 +136,12 @@ def test_add_m2m(self): response = self.client.get( "/admin/tests/person/%s/history/compare/" % self.person.pk, - data={"version_id2":version_ids[0], "version_id1":version_ids[1]} + data={"version_id2": version_ids[0], "version_id1": version_ids[1]} ) -# debug_response(response) # from django-tools + # debug_response(response) # from django-tools - self.assertContainsHtml(response, + self.assertContainsHtml( + response, """

+ added pet
@@ -144,29 +149,31 @@ def test_add_m2m(self): always the same pet

""", - "
version 3: add a pet
", # edit comment + "
version 3: add a pet
", # edit comment ) - self.assertNotContainsHtml(response, - "

name

", # person name doesn't changed - 'class="follow"'# All fields are under reversion control + self.assertNotContainsHtml( + response, + "

name

", # person name doesn't changed + 'class="follow"' # All fields are under reversion control ) def test_m2m_not_changed(self): - with reversion_api.create_revision(): + with create_revision(): self.person.name = "David" self.person.save() - reversion_api.set_comment("version 3: change the name") + set_comment("version 3: change the name") - self.assertEqual(reversion_api.Revision.objects.all().count(), 3) - self.assertEqual(reversion_api.Version.objects.all().count(), 11) + self.assertEqual(Revision.objects.all().count(), 3) + self.assertEqual(Version.objects.all().count(), 11) - queryset = reversion_api.get_for_object(self.person) + queryset = Version.objects.get_for_object(self.person) version_ids = queryset.values_list("pk", flat=True) self.assertEqual(len(version_ids), 3) response = self.client.get("/admin/tests/person/%s/history/" % self.person.pk) -# debug_response(response) # from django-tools - self.assertContainsHtml(response, + # debug_response(response) # from django-tools + self.assertContainsHtml( + response, '', '' % version_ids[0], '' % version_ids[0], @@ -178,22 +185,22 @@ def test_m2m_not_changed(self): response = self.client.get( "/admin/tests/person/%s/history/compare/" % self.person.pk, - data={"version_id2":version_ids[0], "version_id1":version_ids[1]} + data={"version_id2": version_ids[0], "version_id1": version_ids[1]} ) -# debug_response(response) # from django-tools + # debug_response(response) # from django-tools - self.assertContainsHtml(response, + self.assertContainsHtml( + response, '''

             - Dave
             + David
             

''', - "
version 3: change the name
", # edit comment + "
version 3: change the name
", # edit comment ) - self.assertNotContainsHtml(response, + self.assertNotContainsHtml( + response, "pet", - 'class="follow"'# All fields are under reversion control + 'class="follow"' # All fields are under reversion control ) - - diff --git a/tests/test_settings.py b/tests/test_settings.py index 1e378a2..bc00297 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -15,8 +15,6 @@ 'django.contrib.messages.middleware.MessageMiddleware', "reversion.middleware.RevisionMiddleware", - - #'django_tools.middlewares.QueryLogMiddleware.QueryLogMiddleware', ) LANGUAGE_CODE = "en" @@ -58,7 +56,7 @@ } } -DEBUG=True +DEBUG = True # add reversion models to django admin: -ADD_REVERSION_ADMIN=True \ No newline at end of file +ADD_REVERSION_ADMIN = True \ No newline at end of file diff --git a/tests/test_simple_model.py b/tests/test_simple_model.py index c542a12..91da30e 100644 --- a/tests/test_simple_model.py +++ b/tests/test_simple_model.py @@ -17,6 +17,12 @@ from __future__ import absolute_import, division, print_function +import unittest + +from reversion import is_registered +from reversion.models import Version, Revision +from reversion_compare import helpers + try: import django_tools except ImportError as err: @@ -26,11 +32,6 @@ " - Original error: %s" ) % err raise ImportError(msg) -from django_tools.unittest_utils.BrowserDebug import debug_response - - -from reversion_compare import reversion_api, helpers - from .test_utils.test_cases import BaseTestCase from .models import SimpleModel @@ -46,25 +47,25 @@ class SimpleModelTest(BaseTestCase): def setUp(self): super(SimpleModelTest, self).setUp() test_data = TestData(verbose=False) -# test_data = TestData(verbose=True) + # test_data = TestData(verbose=True) self.item1, self.item2 = test_data.create_Simple_data() - queryset = reversion_api.get_for_object(self.item1) + queryset = Version.objects.get_for_object(self.item1) self.version_ids1 = queryset.values_list("pk", flat=True) - queryset = reversion_api.get_for_object(self.item2) + queryset = Version.objects.get_for_object(self.item2) self.version_ids2 = queryset.values_list("pk", flat=True) def test_initial_state(self): - self.assertTrue(reversion_api.is_registered(SimpleModel)) + self.assertTrue(is_registered(SimpleModel)) self.assertEqual(SimpleModel.objects.count(), 2) self.assertEqual(SimpleModel.objects.all()[0].text, "version two") - self.assertEqual(reversion_api.get_for_object(self.item1).count(), 2) - self.assertEqual(reversion_api.get_for_object(self.item2).count(), 5) - self.assertEqual(reversion_api.Revision.objects.all().count(), 7) - self.assertEqual(reversion_api.Version.objects.all().count(), 7) + self.assertEqual(Version.objects.get_for_object(self.item1).count(), 2) + self.assertEqual(Version.objects.get_for_object(self.item2).count(), 5) + self.assertEqual(Revision.objects.all().count(), 7) + self.assertEqual(Version.objects.all().count(), 7) # query.ValuesListQuerySet() -> list(): self.assertEqual(list(self.version_ids1), [2, 1]) @@ -72,8 +73,9 @@ def test_initial_state(self): def test_select_compare1(self): response = self.client.get("/admin/tests/simplemodel/%s/history/" % self.item1.pk) -# debug_response(response) # from django-tools - self.assertContainsHtml(response, + # debug_response(response) # from django-tools + self.assertContainsHtml( + response, '', '' % self.version_ids1[0], '' % self.version_ids1[0], @@ -85,12 +87,13 @@ def test_select_compare2(self): response = self.client.get("/admin/tests/simplemodel/%s/history/" % self.item2.pk) # debug_response(response) # from django-tools for i in range(4): - if i==0: + if i == 0: comment = "create v%i" % i else: comment = "change to v%i" % i - self.assertContainsHtml(response, + self.assertContainsHtml( + response, "%s" % comment, '', ) @@ -98,42 +101,48 @@ def test_select_compare2(self): def test_diff(self): response = self.client.get( "/admin/tests/simplemodel/%s/history/compare/" % self.item1.pk, - data={"version_id2":self.version_ids1[0], "version_id1":self.version_ids1[1]} + data={"version_id2": self.version_ids1[0], "version_id1": self.version_ids1[1]} ) - #debug_response(response) # from django-tools - - self.assertContainsHtml(response, + # debug_response(response) # from django-tools + self.assertContainsHtml( + response, '- version one', '+ version two', - '
simply change the CharField text.
', # edit comment + '
simply change the CharField text.
', # edit comment + ) + + @unittest.skipIf(not hasattr(helpers, "diff_match_patch"), "No google-diff-match-patch available") + def test_google_diff_match_patch(self): + self.activate_google_diff_match_patch() + response = self.client.get( + "/admin/tests/simplemodel/%s/history/compare/" % self.item1.pk, + data={"version_id2": self.version_ids1[0], "version_id1": self.version_ids1[1]} + ) + # debug_response(response) # from django-tools + self.assertContainsHtml( + response, + """ +

version + one + two +

+ """, + '
simply change the CharField text.
', # edit comment ) - if self.google_diff_match_patch: - # google-diff-match-patch is available - helpers.google_diff_match_patch = True - try: - self.assertContainsHtml(response, - """ -

version - one - two -

- """, - '
simply change the CharField text.
', # edit comment - ) - finally: - helpers.google_diff_match_patch = False # revert def test_prev_next_buttons(self): - base_url="/admin/tests/simplemodel/%s/history/compare/" % self.item2.pk + base_url = "/admin/tests/simplemodel/%s/history/compare/" % self.item2.pk for i in range(4): # IDs: 3,4,5,6 - id1=i+3 - id2=i+4 - response = self.client.get(base_url, - data={"version_id2":id2, "version_id1":id1} + id1 = i+3 + id2 = i+4 + response = self.client.get( + base_url, + data={"version_id2": id2, "version_id1": id1} ) - self.assertContainsHtml(response, + self.assertContainsHtml( + response, '- v%i' % i, '+ v%i' % (i+1), '
change to v%i
' % (i+1), @@ -142,7 +151,6 @@ def test_prev_next_buttons(self): # for line in response.content.decode("utf-8").split("\n"): # if "next" in line or "previous" in line: # print(line) - """ +++ 0
  • next ›
  • @@ -157,17 +165,17 @@ def test_prev_next_buttons(self): """ next = 'next ›' % (i+4, i+5) - prev = '‹ previous' % (i+2,i+3) + prev = '‹ previous' % (i+2, i+3) - if i==0: + if i == 0: self.assertNotContains(response, "previous") self.assertContains(response, "next") self.assertContainsHtml(response, next) - elif i==3: + elif i == 3: self.assertContains(response, "previous") self.assertNotContains(response, "next") self.assertContainsHtml(response, prev) else: self.assertContains(response, "previous") self.assertContains(response, "next") - self.assertContainsHtml(response, prev, next) \ No newline at end of file + self.assertContainsHtml(response, prev, next) diff --git a/tests/test_utils/test_cases.py b/tests/test_utils/test_cases.py index c946d89..90a365e 100644 --- a/tests/test_utils/test_cases.py +++ b/tests/test_utils/test_cases.py @@ -20,6 +20,9 @@ from django.apps import apps from django.test import TestCase +from reversion import get_registered_models +from reversion.models import Revision, Version + try: import django_tools except ImportError as err: @@ -29,14 +32,12 @@ " - Original error: %s" ) % err raise ImportError(msg) -from django_tools.unittest_utils.BrowserDebug import debug_response - -from reversion_compare import reversion_api, helpers +from django_tools.unittest_utils.BrowserDebug import debug_response +from reversion_compare import helpers # Needs to import admin module to register all models via CompareVersionAdmin/VersionAdmin -from tests.admin import custom_revision_manager from .test_data import TestData @@ -54,26 +55,27 @@ def setUp(self): ) # http://code.google.com/p/google-diff-match-patch/ - if helpers.google_diff_match_patch: + if hasattr(helpers, "diff_match_patch"): # run all tests without google-diff-match-patch as default # some tests can activate it temporary - helpers.google_diff_match_patch = False - self.google_diff_match_patch = True - else: - self.google_diff_match_patch = False + helpers.dmp = None + + def activate_google_diff_match_patch(self): + assert hasattr(helpers, "diff_match_patch") + helpers.dmp = helpers.diff_match_patch() def tearDown(self): super(BaseTestCase, self).tearDown() - reversion_api.Revision.objects.all().delete() - reversion_api.Version.objects.all().delete() + Revision.objects.all().delete() + Version.objects.all().delete() def assertContainsHtml(self, response, *args): for html in args: try: self.assertContains(response, html, html=True) except AssertionError as e: - debug_response(response, msg="%s" % e) # from django-tools + debug_response(response, msg="%s" % e) # from django-tools raise def assertNotContainsHtml(self, response, *args): @@ -81,7 +83,7 @@ def assertNotContainsHtml(self, response, *args): try: self.assertNotContains(response, html, html=True) except AssertionError as e: - debug_response(response, msg="%s" % e) # from django-tools + debug_response(response, msg="%s" % e) # from django-tools raise @@ -96,6 +98,5 @@ def test_model_registering(self): models = test_app_config.get_models( include_auto_created=False, include_deferred=False, include_swapped=False ) - default_registered = len(reversion_api.get_registered_models()) - custom_registered = len(custom_revision_manager.get_registered_models()) - self.assertEqual(default_registered + custom_registered, len(tuple(models))) + default_registered = len(list(get_registered_models())) + self.assertEqual(default_registered, len(tuple(models))) diff --git a/tests/test_utils/test_data.py b/tests/test_utils/test_data.py index 9e892c1..2382edb 100644 --- a/tests/test_utils/test_data.py +++ b/tests/test_utils/test_data.py @@ -20,11 +20,14 @@ import datetime import os from decimal import Decimal -from django.conf import settings +from django.conf import settings from django.contrib.auth.models import User from django.db.models import BigIntegerField +from reversion import create_revision +from reversion import set_comment + try: import django_tools except ImportError as err: @@ -35,13 +38,7 @@ ) % err raise ImportError(msg) - -from reversion_compare import reversion_api - - -from tests.models import SimpleModel, Person, Pet, \ - Factory, Car, VariantModel, CustomModel, Identity - +from tests.models import SimpleModel, Person, Pet, Factory, Car, VariantModel, CustomModel, Identity class TestData(object): @@ -50,8 +47,8 @@ class TestData(object): This will be also used from external scripts, too! """ - TEST_USERNAME="test" - TEST_USERPASS="12345678" + TEST_USERNAME = "test" + TEST_USERPASS = "12345678" def __init__(self, verbose=False): self.verbose = verbose @@ -68,7 +65,6 @@ def create_all(self): func = getattr(self, method_name) func() - def create_testuser_data(self): if self.verbose: print("\t+++ user name.......: %r" % self.TEST_USERNAME) @@ -78,34 +74,34 @@ def create_testuser_data(self): self.user.save() def create_Simple_data(self): - with reversion_api.create_revision(): + with create_revision(): item1 = SimpleModel.objects.create(text="version one") if self.verbose: print("version 1:", item1) - with reversion_api.create_revision(): + with create_revision(): item1.text = "version two" item1.save() - reversion_api.set_comment("simply change the CharField text.") + set_comment("simply change the CharField text.") if self.verbose: print("version 2:", item1) for no in range(5): - with reversion_api.create_revision(): - if no==0: + with create_revision(): + if no == 0: item2 = SimpleModel.objects.create(text="v0") - reversion_api.set_comment("create v%i" % no) + set_comment("create v%i" % no) else: item2.text = "v%i" % no item2.save() - reversion_api.set_comment("change to v%i" % no) + set_comment("change to v%i" % no) return item1, item2 def create_FactoryCar_data(self): - with reversion_api.create_revision(): + with create_revision(): manufacture = Factory.objects.create(name="factory one", address="1 Fake Plaza") supplier1 = Factory.objects.create(name="always the same supplier", address="1 Fake Plaza") supplier2 = Factory.objects.create(name="would be deleted supplier", address="1 Fake Plaza") @@ -116,7 +112,7 @@ def create_FactoryCar_data(self): ) car.supplier.add(supplier1, supplier2, supplier3) car.save() - reversion_api.set_comment("initial version 1") + set_comment("initial version 1") if self.verbose: print("version 1:", car) @@ -134,7 +130,7 @@ def create_FactoryCar_data(self): = always the same supplier """ - with reversion_api.create_revision(): + with create_revision(): manufacture.name = "factory I" manufacture.save() supplier2.delete() # - would be deleted supplier @@ -142,7 +138,7 @@ def create_FactoryCar_data(self): car.supplier.add(supplier4) # + new, would be renamed supplier car.supplier.remove(supplier3) # - would be removed supplier car.save() - reversion_api.set_comment("version 2: change ForeignKey and ManyToManyField.") + set_comment("version 2: change ForeignKey and ManyToManyField.") if self.verbose: print("version 2:", car) @@ -161,13 +157,13 @@ def create_FactoryCar_data(self): = always the same supplier """ - with reversion_api.create_revision(): + with create_revision(): car.name = "motor-car II" manufacture.name = "factory II" supplier4.name = "not new anymore supplier" supplier4.save() car.save() - reversion_api.set_comment("version 3: change CharField, ForeignKey and ManyToManyField.") + set_comment("version 3: change CharField, ForeignKey and ManyToManyField.") if self.verbose: print("version 3:", car) @@ -178,7 +174,7 @@ def create_FactoryCar_data(self): def create_Factory_reverse_relation_data(self): from django.db import transaction - with transaction.atomic(), reversion_api.create_revision(): + with transaction.atomic(), create_revision(): manufacturer = Factory.objects.create(name="factory one", address="1 Fake Plaza") different_manufacturer = Factory.objects.create(name="factory two", address="1 Fake Plaza") car1 = Car.objects.create( @@ -197,7 +193,7 @@ def create_Factory_reverse_relation_data(self): car2.save() car3.save() manufacturer.save() - reversion_api.set_comment("initial version 1") + set_comment("initial version 1") if self.verbose: print("version 1:", manufacturer) @@ -215,7 +211,7 @@ def create_Factory_reverse_relation_data(self): = always the same supplier """ - with transaction.atomic(), reversion_api.create_revision(): + with transaction.atomic(), create_revision(): car3.delete() car4 = Car.objects.create( name="motor-car four", @@ -227,9 +223,10 @@ def create_Factory_reverse_relation_data(self): name="Bob Bobertson", workplace=manufacturer ) + worker1.save() manufacturer.save() - reversion_api.set_comment("version 2: discontinued car-three, add car-four, add Bob the worker") + set_comment("version 2: discontinued car-three, add car-four, add Bob the worker") if self.verbose: print("version 2:", manufacturer) @@ -248,11 +245,11 @@ def create_Factory_reverse_relation_data(self): = always the same supplier """ - with transaction.atomic(), reversion_api.create_revision(): + with transaction.atomic(), create_revision(): car2.manufacturer = different_manufacturer car2.save() manufacturer.save() - reversion_api.set_comment("version 3: car2 now built by someone else.") + set_comment("version 3: car2 now built by someone else.") if self.verbose: print("version 3:", manufacturer) @@ -262,7 +259,7 @@ def create_Factory_reverse_relation_data(self): def create_PersonPet_data(self): - with reversion_api.create_revision(): + with create_revision(): pet1 = Pet.objects.create(name="would be changed pet") pet2 = Pet.objects.create(name="would be deleted pet") pet3 = Pet.objects.create(name="would be removed pet") @@ -270,7 +267,7 @@ def create_PersonPet_data(self): person = Person.objects.create(name="Dave") person.pets.add(pet1, pet2, pet3, pet4) person.save() - reversion_api.set_comment("initial version 1") + set_comment("initial version 1") if self.verbose: print("version 1:", person, person.pets.all()) @@ -285,13 +282,13 @@ def create_PersonPet_data(self): = always the same pet """ - with reversion_api.create_revision(): + with create_revision(): pet1.name = "Is changed pet" pet1.save() pet2.delete() person.pets.remove(pet3) person.save() - reversion_api.set_comment("version 2: change follow related pets.") + set_comment("version 2: change follow related pets.") if self.verbose: print("version 2:", person, person.pets.all()) @@ -300,7 +297,7 @@ def create_PersonPet_data(self): return pet1, pet2, person def create_VariantModel_data(self): - with reversion_api.create_revision(): + with create_revision(): item = VariantModel.objects.create( boolean = False, null_boolean = None, @@ -329,12 +326,14 @@ def create_VariantModel_data(self): email = "one@foo-bar.com", url = "http://www.pylucid.org/", + file_field = os.path.join(settings.UNITTEST_TEMP_PATH, "foo"), + filepath = os.path.join(settings.UNITTEST_TEMP_PATH, "foo"), ip_address = "192.168.0.1", # skip: models.GenericIPAddressField() ) - reversion_api.set_comment("initial version") + set_comment("initial version") test_data = ( ("boolean", True), @@ -357,19 +356,20 @@ def create_VariantModel_data(self): ("float", 3.1415), ("email", "two@foo-bar.com"), ("url", "https://github.com/jedie/"), + ("file_field", os.path.join(settings.UNITTEST_TEMP_PATH, "bar")), ("filepath", os.path.join(settings.UNITTEST_TEMP_PATH, "bar")), ("ip_address", "10.0.0.0"), ) for no, (field_name, value) in enumerate(test_data): - with reversion_api.create_revision(): + with create_revision(): setattr(item, field_name, value) item.save() - reversion_api.set_comment("%i change: %r field." % (no, field_name)) + set_comment("%i change: %r field." % (no, field_name)) return item, test_data def create_CustomModel_data(self): - with reversion_api.create_revision(): + with create_revision(): item1 = CustomModel.objects.create(text="version one") if self.verbose: @@ -377,19 +377,18 @@ def create_CustomModel_data(self): return item1 - def create_PersonIdentity_data(self): - with reversion_api.create_revision(): + with create_revision(): person = Person.objects.create(name="Dave") identity = Identity.objects.create(id_numer="1234", person=person) if self.verbose: print("version 1:", person, identity) - with reversion_api.create_revision(): + with create_revision(): person.name = "John" person.save() - reversion_api.set_comment("version 2: change person name.") + set_comment("version 2: change person name.") return person, identity diff --git a/tests/test_variant_model.py b/tests/test_variant_model.py index 31e31c3..87e5d3a 100644 --- a/tests/test_variant_model.py +++ b/tests/test_variant_model.py @@ -18,8 +18,12 @@ from __future__ import absolute_import, division, print_function import os + from django.conf import settings +from reversion import create_revision +from reversion import is_registered +from reversion.models import Version, Revision try: import django_tools @@ -30,15 +34,9 @@ " - Original error: %s" ) % err raise ImportError(msg) -from django_tools.unittest_utils.BrowserDebug import debug_response - -from reversion_compare import reversion_api - -from tests.models import VariantModel - -# Needs to import admin module to register all models via CompareVersionAdmin/VersionAdmin from .test_utils.test_cases import BaseTestCase +from .models import VariantModel from .test_utils.test_data import TestData @@ -47,7 +45,7 @@ class VariantModelNoDataTest(BaseTestCase): Tests with a empty VariantModel """ def test_textfield(self): - with reversion_api.create_revision(): + with create_revision(): item = VariantModel.objects.create( text="""\ first line @@ -60,7 +58,7 @@ def test_textfield(self): ) item.save() - with reversion_api.create_revision(): + with create_revision(): item.text = """\ first line Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut @@ -71,12 +69,10 @@ def test_textfield(self): last line""" item.save() - # debug_response(self.client.get("/admin/tests/variantmodel/1/history/")) response = self.client.get( "/admin/tests/variantmodel/1/history/compare/", data={"version_id2": 1, "version_id1": 2} ) - # debug_response(response) # from django-tools self.assertContains(response, """\ -nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit @@ -95,23 +91,22 @@ def setUp(self): self.item, self.test_data = TestData(verbose=False).create_VariantModel_data() - queryset = reversion_api.get_for_object(self.item) + queryset = Version.objects.get_for_object(self.item) self.version_ids = queryset.values_list("pk", flat=True) def test_initial_state(self): - self.assertTrue(reversion_api.is_registered(VariantModel)) + self.assertTrue(is_registered(VariantModel)) self.assertEqual(VariantModel.objects.count(), 1) count = len(self.test_data) + 1 # incl. initial - self.assertEqual(reversion_api.get_for_object(self.item).count(), count) - self.assertEqual(reversion_api.Revision.objects.all().count(), count) + self.assertEqual(Version.objects.get_for_object(self.item).count(), count) + self.assertEqual(Revision.objects.all().count(), count) self.assertEqual(len(self.version_ids), count) def test_all_changes(self): # debug_response(self.client.get("/admin/tests/variantmodel/1/history/")) - # compare initial with last version response = self.client.get( "/admin/tests/variantmodel/1/history/compare/", @@ -120,14 +115,14 @@ def test_all_changes(self): "version_id1": len(self.test_data) + 1 # incl. initial } ) - # debug_response(response) # from django-tools field_headlines = [ "

    %s

    " % field_name.replace("_", " ") for field_name, value in self.test_data ] self.assertContainsHtml(response, *field_headlines) - self.assertContainsHtml(response, + self.assertContainsHtml( + response, "

    boolean

    ", '

    False changed to: True

    ', @@ -191,8 +186,8 @@ def test_all_changes(self): "+ https://github.com/jedie/", "

    filepath

    ", - #"- %s/foo" % settings.UNITTEST_TEMP_PATH, - #"+ %s/bar" % settings.UNITTEST_TEMP_PATH, + # "- %s/foo" % settings.UNITTEST_TEMP_PATH, + # "+ %s/bar" % settings.UNITTEST_TEMP_PATH, "- %s" % os.path.join(settings.UNITTEST_TEMP_PATH, 'foo'), "+ %s" % os.path.join(settings.UNITTEST_TEMP_PATH, 'bar'), diff --git a/tests/test_view.py b/tests/test_view.py index 50885f9..7a30ca8 100644 --- a/tests/test_view.py +++ b/tests/test_view.py @@ -13,6 +13,8 @@ from __future__ import absolute_import, division, print_function +from reversion import is_registered +from reversion.models import Version try: import django_tools @@ -23,11 +25,8 @@ " - Original error: %s" ) % err raise ImportError(msg) -from django_tools.unittest_utils.BrowserDebug import debug_response -from reversion_compare import reversion_api - from .test_utils.test_cases import BaseTestCase from .models import SimpleModel @@ -45,19 +44,19 @@ def setUp(self): test_data = TestData(verbose=False) self.item1, self.item2 = test_data.create_Simple_data() - queryset = reversion_api.get_for_object(self.item1) + queryset = Version.objects.get_for_object(self.item1) self.version_ids1 = queryset.values_list("pk", flat=True) - queryset = reversion_api.get_for_object(self.item2) + queryset = Version.objects.get_for_object(self.item2) self.version_ids2 = queryset.values_list("pk", flat=True) def test_initial_state(self): - self.assertTrue(reversion_api.is_registered(SimpleModel)) + self.assertTrue(is_registered(SimpleModel)) self.assertEqual(SimpleModel.objects.count(), 2) self.assertEqual(SimpleModel.objects.all()[0].text, "version two") - self.assertEqual(reversion_api.get_for_object(self.item1).count(), 2) + self.assertEqual(Version.objects.get_for_object(self.item1).count(), 2) self.assertEqual(list(self.version_ids1), [2, 1]) self.assertEqual(list(self.version_ids1), [2, 1]) @@ -65,7 +64,8 @@ def test_initial_state(self): def test_select_compare1(self): response = self.client.get("/test_view/%s" % self.item1.pk) - self.assertContainsHtml(response, + self.assertContainsHtml( + response, '', '' % self.version_ids1[0], '' % self.version_ids1[0], @@ -75,56 +75,63 @@ def test_select_compare1(self): def test_select_compare2(self): response = self.client.get("/test_view/%s" % self.item2.pk) - # debug_response(response) # from django-tools for i in range(4): - if i==0: + if i == 0: comment = "create v%i" % i else: comment = "change to v%i" % i - self.assertContainsHtml(response, + self.assertContainsHtml( + response, "%s" % comment, '', ) def test_select_compare_and_diff(self): - response = self.client.get("/test_view/%s" % self.item1.pk, data={"version_id2":self.version_ids1[0], "version_id1":self.version_ids1[1]}) - self.assertContainsHtml(response, + response = self.client.get("/test_view/%s" % self.item1.pk, data={ + "version_id2": self.version_ids1[0], + "version_id1": self.version_ids1[1] + }) + self.assertContainsHtml( + response, '', '' % self.version_ids1[0], '' % self.version_ids1[0], '' % self.version_ids1[1], '' % self.version_ids1[1], ) - self.assertContainsHtml(response, + self.assertContainsHtml( + response, '- version one', '+ version two', - '
    simply change the CharField text.
    ', # edit comment + '
    simply change the CharField text.
    ', # edit comment ) def test_prev_next_buttons(self): - base_url="/test_view/%s" % self.item2.pk + base_url = "/test_view/%s" % self.item2.pk for i in range(4): # IDs: 3,4,5,6 - id1=i+3 - id2=i+4 - response = self.client.get(base_url, - data={"version_id2":id2, "version_id1":id1} + id1 = i+3 + id2 = i+4 + response = self.client.get( + base_url, + data={"version_id2": id2, "version_id1": id1} ) - self.assertContainsHtml(response, + self.assertContainsHtml( + response, '- v%i' % i, '+ v%i' % (i+1), '
    change to v%i
    ' % (i+1), ) next = 'next ›' % (i+4, i+5) - prev = '‹ previous' % (i+2,i+3) + prev = '‹ previous' % (i+2, i+3) - if i==0: + if i == 0: self.assertNotContains(response, "previous") self.assertContains(response, "next") self.assertContainsHtml(response, next) - elif i==3: + elif i == 3: self.assertContains(response, "previous") self.assertNotContains(response, "next") self.assertContainsHtml(response, prev) diff --git a/tests/views.py b/tests/views.py index ac94a22..b9c856f 100644 --- a/tests/views.py +++ b/tests/views.py @@ -2,6 +2,6 @@ from reversion_compare.views import HistoryCompareDetailView from .models import SimpleModel + class SimpleModelHistoryCompareView(HistoryCompareDetailView): model = SimpleModel - \ No newline at end of file diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..0274388 --- /dev/null +++ b/tox.ini @@ -0,0 +1,24 @@ +# Tox (http://tox.testrun.org/) is a tool for running tests +# in multiple virtualenvs. This configuration file will run the +# test suite on all supported python versions. To use it, "pip install tox" +# and then run "tox" from this directory. + +[tox] +envlist = + {py27,py34,py35}-django{18,19,110}{-dmp,} + +[testenv] +passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH +usedevelop = True + +deps = + django18: Django>=1.8,<1.9 + django19: Django>=1.9,<1.10 + dmp: diff-match-patch + -r{toxinidir}/requirements-test.txt + +commands = + python --version + coverage run --source=reversion_compare runtests.py + coverage report + coveralls