django-dbdiff 0.9.5__tar.gz → 0.9.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. django_dbdiff-0.9.7/PKG-INFO +151 -0
  2. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/README.rst +20 -10
  3. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/apps.py +2 -4
  4. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/exceptions.py +1 -2
  5. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/fixture.py +36 -22
  6. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/sequence.py +2 -3
  7. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/serializers/base.py +4 -8
  8. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/serializers/json.py +0 -1
  9. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/test.py +2 -2
  10. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/decimal_test/migrations/0001_initial.py +1 -4
  11. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/decimal_test/migrations/0002_auto_20160102_0914.py +1 -4
  12. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/project/settings.py +1 -2
  13. django_dbdiff-0.9.7/dbdiff/tests/project/settings_mysql.py +21 -0
  14. django_dbdiff-0.9.7/dbdiff/tests/project/settings_postgresql.py +16 -0
  15. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/test_compare.py +8 -19
  16. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/test_fixture.py +9 -0
  17. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/test_mixin.py +3 -2
  18. django_dbdiff-0.9.7/dbdiff/tests/test_utils.py +53 -0
  19. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/utils.py +81 -21
  20. django_dbdiff-0.9.7/django_dbdiff.egg-info/PKG-INFO +151 -0
  21. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/django_dbdiff.egg-info/SOURCES.txt +3 -2
  22. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/django_dbdiff.egg-info/entry_points.txt +0 -1
  23. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/django_dbdiff.egg-info/requires.txt +0 -1
  24. django_dbdiff-0.9.7/django_dbdiff.egg-info/top_level.txt +3 -0
  25. django_dbdiff-0.9.7/docs/conf.py +22 -0
  26. django_dbdiff-0.9.7/pyproject.toml +62 -0
  27. django-dbdiff-0.9.5/PKG-INFO +0 -133
  28. django-dbdiff-0.9.5/dbdiff/tests/project/settings_mysql.py +0 -9
  29. django-dbdiff-0.9.5/dbdiff/tests/project/settings_postgresql.py +0 -9
  30. django-dbdiff-0.9.5/dbdiff/tests/test_utils.py +0 -16
  31. django-dbdiff-0.9.5/django_dbdiff.egg-info/PKG-INFO +0 -133
  32. django-dbdiff-0.9.5/django_dbdiff.egg-info/top_level.txt +0 -1
  33. django-dbdiff-0.9.5/setup.py +0 -40
  34. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/__init__.py +0 -0
  35. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/plugin.py +0 -0
  36. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/serializers/__init__.py +0 -0
  37. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/__init__.py +0 -0
  38. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/decimal_test/__init__.py +0 -0
  39. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/decimal_test/migrations/__init__.py +0 -0
  40. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/decimal_test/models.py +0 -0
  41. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/inheritance/__init__.py +0 -0
  42. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/inheritance/models.py +0 -0
  43. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/nonintpk/__init__.py +0 -0
  44. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/nonintpk/models.py +0 -0
  45. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/project/__init__.py +0 -0
  46. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/project/settings_sqlite.py +0 -0
  47. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/project/urls.py +0 -0
  48. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/test_decimal.py +1 -1
  49. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/dbdiff/tests/test_plugin.py +2 -2
  50. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/django_dbdiff.egg-info/dependency_links.txt +0 -0
  51. {django-dbdiff-0.9.5 → django_dbdiff-0.9.7}/setup.cfg +0 -0
@@ -0,0 +1,151 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-dbdiff
3
+ Version: 0.9.7
4
+ Summary: Database data diffing against fixtures for testing
5
+ Author-email: James Pic <jamespic@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/yourlabs/django-dbdiff
8
+ Keywords: django,test,database,fixture,diff
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Web Environment
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Framework :: Django
15
+ Classifier: Framework :: Django :: 4.2
16
+ Classifier: Framework :: Django :: 5.2
17
+ Classifier: Framework :: Django :: 6.0
18
+ Classifier: Programming Language :: Python
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
+ Classifier: Topic :: Internet :: WWW/HTTP
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
+ Requires-Python: >=3.10
28
+ Description-Content-Type: text/x-rst
29
+ Requires-Dist: ijson
30
+ Requires-Dist: json_delta
31
+
32
+ .. image:: https://github.com/yourlabs/django-dbdiff/actions/workflows/ci.yml/badge.svg
33
+ :target: https://github.com/yourlabs/django-dbdiff/actions/workflows/ci.yml
34
+ .. image:: https://codecov.io/gh/yourlabs/django-dbdiff/branch/master/graph/badge.svg
35
+ :target: https://codecov.io/gh/yourlabs/django-dbdiff
36
+ .. image:: https://badge.fury.io/py/django-dbdiff.png
37
+ :target: http://badge.fury.io/py/django-dbdiff
38
+
39
+ django-dbdiff
40
+ ~~~~~~~~~~~~~
41
+
42
+ I'm pretty lazy when it comes to writing tests for existing code, however, I'm
43
+ even lazier when it comes to repetitive manual testing action.
44
+
45
+ This package aims at de-duplicating the data import tests from
46
+ django-representatives and django-representatives-votes which is re-used in
47
+ django-cities-light.
48
+
49
+ Database state assertion
50
+ ========================
51
+
52
+ A nice way to test a data import script is to create a source data fixture with
53
+ a subset of data, ie. with only 10 cities instead of 28K or only 3 european
54
+ parliament representatives instead of 3600, feed the import function with that
55
+ and then compare the database state with a django fixture. This looks like what
56
+ I was used to do:
57
+
58
+ - use such a command to create a small data extract
59
+ `shuf -n3 cities15000.txt > cities_light/tests/cities_test_fixture.txt`,
60
+ - use it against the import script on a clean database,
61
+ - verify the database manually, and run
62
+ `django-admin dumpdata --indent=4 cities_light > cities_light/tests/cities_test_expected.txt`
63
+ - then, make a test case that calls the import script against the fixture,
64
+ - write and maintain some funny (fuzzy ?) repetitive test code to ensure that
65
+ the database is in the expected state.
66
+
67
+ When a bug is fixed, just add the case to the fixture and repeat the process to
68
+ create new expected data dumps, use coverage to ensure no case is missed.
69
+
70
+ With django-dbdiff, I just need to maintain to initial data extract, and test
71
+ it with ``Fixture('appname/path/to/fixture',
72
+ models=[YourModelToTest]).assertNoDiff()`` in a
73
+ ``django.test.TransactionTestCase`` which has ``reset_sequences=True``:
74
+
75
+ - if the fixture in question doesn't exist, it'll be automatically created on
76
+ with dumpdata for the concerned models on the first run, raising
77
+ "FixtureCreated" exception to fail the test and inform of the path of the
78
+ created fixture, so that it doesn't mislead the user in thinking the test
79
+ passed with an existing fixture,
80
+ - if the fixture exists, it'll run dumpdata on the models concerned and GNU
81
+ diff it against the fixture, if there's any output it'll be raised in the
82
+ "DiffFound" exception, failing the test and printing the diff.
83
+
84
+ Usage
85
+ =====
86
+
87
+ Example:
88
+
89
+ .. code-block:: python
90
+
91
+ from django.test import TransactionTestCase
92
+ from dbdiff.fixture import Fixture
93
+
94
+
95
+ class YourImportTest(TransactionTestCase):
96
+ reset_sequences = True
97
+
98
+ def test_your_import(self):
99
+ your_import()
100
+
101
+ Fixture('yourapp/tests/yourtest.json',
102
+ models=[YourModel]).assertNoDiff()
103
+
104
+ The first time, it will raise a ``FixtureCreated`` exception, and the test will
105
+ fail. This is to inform the user that the test didn't really run. On the next
106
+ run though, it will pass.
107
+
108
+ If any difference is found between the database and the test fixture, then
109
+ ``diff()`` will return the diff as outputed by GNU diff.
110
+
111
+ If you need to ignore fields globally, set the class-level variable exclude as such:
112
+
113
+ .. code-block:: python
114
+
115
+ Fixture.exclude = {'mrsrequest.mrsrequest': ['token']}
116
+
117
+ If your import produces records with non-deterministic primary keys (e.g.
118
+ UUIDs or sequence gaps), pass ``ignore_pk=True`` to match records by their
119
+ field content instead of by pk:
120
+
121
+ .. code-block:: python
122
+
123
+ Fixture('yourapp/tests/yourtest.json',
124
+ models=[YourModel],
125
+ ignore_pk=True).assertNoDiff()
126
+
127
+ Instead of deleting the fixtures manually before running the tests to
128
+ regenerate them, just run your tests with FIXTURE_REWRITE=1 environment
129
+ variable. This will overwrite the fixtures and make the tests look like it
130
+ passed.
131
+
132
+ See tests and docstrings for crunchy details.
133
+
134
+ Requirements
135
+ ============
136
+
137
+ MySQL, SQLite and PostgreSQL, Python 3.10 to 3.14 are supported along with
138
+ Django 4.2, 5.2, and 6.0 - it's always better to support django's master so
139
+ that we can **upgrade easily when it is released**, which is one of the selling
140
+ points for having 100% coverage.
141
+
142
+ Install
143
+ =======
144
+
145
+ Install ``django-dbdiff`` with pip and add ``dbdiff`` to ``INSTALLED_APPS``.
146
+
147
+ Django model observer
148
+ =====================
149
+
150
+ It is interresting to note that a related, perhaps sort-of similar app exists:
151
+ https://github.com/Griffosx/djmo
@@ -1,7 +1,7 @@
1
- .. image:: https://travis-ci.org/yourlabs/django-dbdiff.svg
2
- :target: https://travis-ci.org/yourlabs/django-dbdiff
3
- .. image:: https://codecov.io/github/yourlabs/django-dbdiff/coverage.svg?branch=master
4
- :target: https://codecov.io/github/yourlabs/django-dbdiff?branch=master
1
+ .. image:: https://github.com/yourlabs/django-dbdiff/actions/workflows/ci.yml/badge.svg
2
+ :target: https://github.com/yourlabs/django-dbdiff/actions/workflows/ci.yml
3
+ .. image:: https://codecov.io/gh/yourlabs/django-dbdiff/branch/master/graph/badge.svg
4
+ :target: https://codecov.io/gh/yourlabs/django-dbdiff
5
5
  .. image:: https://badge.fury.io/py/django-dbdiff.png
6
6
  :target: http://badge.fury.io/py/django-dbdiff
7
7
 
@@ -57,11 +57,11 @@ Example:
57
57
 
58
58
  .. code-block:: python
59
59
 
60
- from django import TransactionTestCase
60
+ from django.test import TransactionTestCase
61
61
  from dbdiff.fixture import Fixture
62
62
 
63
63
 
64
- class YourImportTest(test.TransactionTestCase):
64
+ class YourImportTest(TransactionTestCase):
65
65
  reset_sequences = True
66
66
 
67
67
  def test_your_import(self):
@@ -83,6 +83,16 @@ If you need to ignore fields globally, set the class-level variable exclude as s
83
83
 
84
84
  Fixture.exclude = {'mrsrequest.mrsrequest': ['token']}
85
85
 
86
+ If your import produces records with non-deterministic primary keys (e.g.
87
+ UUIDs or sequence gaps), pass ``ignore_pk=True`` to match records by their
88
+ field content instead of by pk:
89
+
90
+ .. code-block:: python
91
+
92
+ Fixture('yourapp/tests/yourtest.json',
93
+ models=[YourModel],
94
+ ignore_pk=True).assertNoDiff()
95
+
86
96
  Instead of deleting the fixtures manually before running the tests to
87
97
  regenerate them, just run your tests with FIXTURE_REWRITE=1 environment
88
98
  variable. This will overwrite the fixtures and make the tests look like it
@@ -93,10 +103,10 @@ See tests and docstrings for crunchy details.
93
103
  Requirements
94
104
  ============
95
105
 
96
- MySQL, SQLite and PostgreSQL, Python 2.7 and 3.4 are supported along with
97
- Django 1.7 to 1.10 - it's always better to support django's master so that we
98
- can **upgrade easily when it is released**, which is one of the selling points
99
- for having 100% coverage.
106
+ MySQL, SQLite and PostgreSQL, Python 3.10 to 3.14 are supported along with
107
+ Django 4.2, 5.2, and 6.0 - it's always better to support django's master so
108
+ that we can **upgrade easily when it is released**, which is one of the selling
109
+ points for having 100% coverage.
100
110
 
101
111
  Install
102
112
  =======
@@ -9,8 +9,7 @@ from .utils import patch_transaction_test_case
9
9
 
10
10
 
11
11
  class DefaultConfig(AppConfig):
12
- """
13
- Register patched serializers and patch TransactionTestCase for sqlite.
12
+ """Register patched serializers and patch TransactionTestCase for sqlite.
14
13
 
15
14
  .. py:attribute:: debug
16
15
 
@@ -23,8 +22,7 @@ class DefaultConfig(AppConfig):
23
22
  default_indent = 4
24
23
 
25
24
  def ready(self):
26
- """
27
- Register dbdiff.serializers.json and set debug.
25
+ """Register dbdiff.serializers.json and set debug.
28
26
 
29
27
  Enables debug if a DBDIFF_DEBUG environment variable is found.
30
28
 
@@ -59,8 +59,7 @@ class DiffFound(DbDiffException):
59
59
 
60
60
 
61
61
  class FixtureCreated(DbDiffException):
62
- """
63
- Raised when a fixture was created.
62
+ """Raised when a fixture was created.
64
63
 
65
64
  This purposely fails a test, to avoid misleading the user into thinking
66
65
  that the test was properly executed against a versioned fixture. Imagine
@@ -5,11 +5,10 @@ import json
5
5
  import os
6
6
  import tempfile
7
7
 
8
+ import ijson
8
9
  from django.apps import apps
9
10
  from django.core.management import call_command
10
11
 
11
- import ijson
12
-
13
12
  from .exceptions import DiffFound, FixtureCreated
14
13
  from .utils import (
15
14
  diff,
@@ -18,13 +17,11 @@ from .utils import (
18
17
  get_tree,
19
18
  )
20
19
 
21
-
22
20
  REWRITE = os.getenv('FIXTURE_REWRITE')
23
21
 
24
22
 
25
23
  class Fixture(object):
26
- """
27
- Is able to print out diffs between database and a fixture.
24
+ """Is able to print out diffs between database and a fixture.
28
25
 
29
26
  .. py:attribute:: path
30
27
 
@@ -46,9 +43,10 @@ class Fixture(object):
46
43
 
47
44
  exclude = dict()
48
45
 
49
- def __init__(self, relative_path, models=None, database=None):
50
- """
51
- Instanciate a FixtureDiff on a database.
46
+ def __init__(
47
+ self, relative_path, models=None, database=None, ignore_pk=False
48
+ ):
49
+ """Instanciate a FixtureDiff on a database.
52
50
 
53
51
  relative_path is used to calculate :py:attr:`path`, with
54
52
  :py:func:`~utils.get_absolute_path`.
@@ -58,14 +56,19 @@ class Fixture(object):
58
56
 
59
57
  database should be the name of the database to use, `default` by
60
58
  default.
59
+
60
+ ignore_pk when True, matches records by field content instead of
61
+ primary key. Records with the same content but different pks
62
+ are considered equal.
61
63
  """
62
64
  self.path = get_absolute_path(relative_path)
63
65
  self.models = models if models else self.parse_models()
64
66
  self.database = database or 'default'
67
+ self.ignore_pk = ignore_pk
65
68
 
66
69
  def parse_models(self):
67
70
  """Return the list of models inside the fixture file."""
68
- with open(self.path, 'r') as f:
71
+ with open(self.path, 'rb') as f:
69
72
  return [apps.get_model(i.lower())
70
73
  for i in ijson.items(f, 'item.model')]
71
74
 
@@ -91,31 +94,39 @@ class Fixture(object):
91
94
 
92
95
  return len(line) - len(line.lstrip(' '))
93
96
 
94
- def diff(self, exclude=None):
95
- """
96
- Diff the fixture against a datadump of fixture models.
97
+ def diff(self, exclude=None, ignore_pk=None):
98
+ """Diff the fixture against a datadump of fixture models.
97
99
 
98
100
  If passed, exclude should be a list of field names to exclude from
99
101
  being diff'ed.
102
+
103
+ ignore_pk when True, matches records by field content instead of
104
+ primary key. Defaults to the instance's ignore_pk attribute.
100
105
  """
101
106
  fh, dump_path = tempfile.mkstemp('_dbdiff')
102
107
 
103
108
  exclude_final = copy.copy(self.exclude)
104
109
  exclude_final.update(exclude or {})
105
110
 
106
- with os.fdopen(fh, 'w') as f:
107
- self.dump(f)
111
+ try:
112
+ with os.fdopen(fh, 'w') as f:
113
+ self.dump(f)
108
114
 
109
- with open(self.path, 'r') as e, open(dump_path, 'r') as r:
110
- expected, result = json.load(e), json.load(r)
115
+ with open(self.path, 'r') as e, open(dump_path, 'r') as r:
116
+ expected, result = json.load(e), json.load(r)
111
117
 
112
- unexpected, missing, different = diff(
113
- get_tree(expected, exclude_final),
114
- get_tree(result, exclude_final),
115
- )
118
+ if ignore_pk is None:
119
+ ignore_pk = self.ignore_pk
116
120
 
117
- if not unexpected and not missing and not diff:
121
+ unexpected, missing, different = diff(
122
+ get_tree(expected, exclude_final),
123
+ get_tree(result, exclude_final),
124
+ ignore_pk=ignore_pk,
125
+ )
126
+ finally:
118
127
  os.unlink(dump_path)
128
+
129
+ if not unexpected and not missing and not different:
119
130
  return None
120
131
 
121
132
  return unexpected, missing, different
@@ -150,8 +161,11 @@ class Fixture(object):
150
161
  if not REWRITE:
151
162
  raise FixtureCreated(self)
152
163
 
153
- unexpected, missing, different = self.diff(exclude=exclude)
164
+ result = self.diff(exclude=exclude)
165
+ if result is None:
166
+ return
154
167
 
168
+ unexpected, missing, different = result
155
169
  if unexpected or missing or different:
156
170
  raise DiffFound(self, unexpected, missing, different)
157
171
 
@@ -14,8 +14,7 @@ def pk_sequence_get(model):
14
14
 
15
15
 
16
16
  def sequence_reset(model):
17
- """
18
- Better sequence reset than TransactionTestCase.
17
+ """Better sequence reset than TransactionTestCase.
19
18
 
20
19
  The difference with using TransactionTestCase with reset_sequences=True is
21
20
  that this will reset sequences for the given models to their higher value,
@@ -49,7 +48,7 @@ def sequence_reset(model):
49
48
  column=pk_field, table=table
50
49
  )
51
50
  )
52
- result = cursor.fetchone()[0] or 0
51
+ result = cursor.fetchone()[0] or 1
53
52
  reset = 'ALTER TABLE {table} AUTO_INCREMENT = %s' % result
54
53
 
55
54
  connection.cursor().execute(
@@ -10,8 +10,7 @@ class BaseSerializerMixin(object):
10
10
 
11
11
  @classmethod
12
12
  def recursive_dict_sort(cls, data):
13
- """
14
- Return a recursive OrderedDict for a dict.
13
+ """Return a recursive OrderedDict for a dict.
15
14
 
16
15
  Django's default model-to-dict logic - implemented in
17
16
  django.core.serializers.python.Serializer.get_dump_object() - returns a
@@ -28,8 +27,7 @@ class BaseSerializerMixin(object):
28
27
 
29
28
  @classmethod
30
29
  def remove_microseconds(cls, data):
31
- """
32
- Strip microseconds from datetimes for mysql.
30
+ """Strip microseconds from datetimes for mysql.
33
31
 
34
32
  MySQL doesn't have microseconds in datetimes, so dbdiff's serializer
35
33
  removes microseconds from datetimes so that fixtures are cross-database
@@ -51,8 +49,7 @@ class BaseSerializerMixin(object):
51
49
 
52
50
  @classmethod
53
51
  def normalize_decimals(cls, data):
54
- """
55
- Strip trailing zeros for constitency.
52
+ """Strip trailing zeros for consistency.
56
53
 
57
54
  In addition, dbdiff serialization forces Decimal normalization, because
58
55
  trailing zeros could happen in inconsistent ways.
@@ -67,8 +64,7 @@ class BaseSerializerMixin(object):
67
64
  data['fields'][key] = value.normalize()
68
65
 
69
66
  def get_dump_object(self, obj):
70
- """
71
- Actual method used by Django serializers to dump dicts.
67
+ """Actual method used by Django serializers to dump dicts.
72
68
 
73
69
  By overridding this method, we're able to run our various
74
70
  data dump predictability methods.
@@ -4,7 +4,6 @@ from django.core.serializers import json as upstream
4
4
 
5
5
  from .base import BaseSerializerMixin
6
6
 
7
-
8
7
  __all__ = ('Serializer', 'Deserializer')
9
8
 
10
9
 
@@ -6,8 +6,7 @@ from .sequence import sequence_reset
6
6
 
7
7
 
8
8
  class DbdiffTestMixin(object):
9
- """
10
- Convenience mixin with better sequence resetting than TransactionTestCase.
9
+ """Mixin with better sequence resetting than TransactionTestCase.
11
10
 
12
11
  The difference with using TransactionTestCase with reset_sequences=True is
13
12
  that this will reset sequences for the given models to their higher value,
@@ -52,6 +51,7 @@ class DbdiffTestMixin(object):
52
51
  Fixture(
53
52
  self.dbdiff_expected,
54
53
  models=self.dbdiff_models,
54
+ ignore_pk=getattr(self, 'dbdiff_ignore_pk', False),
55
55
  ).assertNoDiff(
56
56
  exclude=self.dbdiff_exclude,
57
57
  )
@@ -1,7 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
- from __future__ import unicode_literals
3
-
4
- from django.db import models, migrations
1
+ from django.db import migrations, models
5
2
 
6
3
 
7
4
  class Migration(migrations.Migration):
@@ -1,7 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
- from __future__ import unicode_literals
3
-
4
- from django.db import models, migrations
1
+ from django.db import migrations, models
5
2
 
6
3
 
7
4
  class Migration(migrations.Migration):
@@ -1,5 +1,4 @@
1
- """
2
- Django settings for project project.
1
+ """Django settings for project project.
3
2
 
4
3
  Generated by 'django-admin startproject' using Django 1.8.3.dev20150604012123.
5
4
 
@@ -0,0 +1,21 @@
1
+ from .settings import * # noqa
2
+
3
+ import os
4
+
5
+ DATABASES = {
6
+ 'default': {
7
+ 'ENGINE': 'django.db.backends.mysql',
8
+ 'HOST': os.environ.get('DB_HOST', ''),
9
+ 'NAME': os.environ.get('DB_NAME', 'dbdiff_test'),
10
+ 'USER': os.environ.get('DB_USER', 'root'),
11
+ 'PASSWORD': os.environ.get('DB_PASSWORD', ''),
12
+ 'PORT': os.environ.get('DB_PORT', ''),
13
+ 'OPTIONS': {
14
+ 'charset': 'utf8mb4',
15
+ },
16
+ 'TEST':{
17
+ 'CHARSET': 'utf8mb4',
18
+ 'COLLATION': 'utf8mb4_unicode_ci',
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,16 @@
1
+ from .settings import * # noqa
2
+
3
+ import os
4
+
5
+ DATABASES = {
6
+ 'default': {
7
+ 'ENGINE': 'django.db.backends.postgresql',
8
+ 'HOST': os.environ.get('DB_HOST', ''),
9
+ 'NAME': os.environ.get('DB_NAME', 'dbdiff_test'),
10
+ 'USER': os.environ.get('DB_USER', 'postgres'),
11
+ 'PASSWORD': os.environ.get('DB_PASSWORD', ''),
12
+ 'PORT': os.environ.get('DB_PORT', '5432'),
13
+ 'OPTIONS': {},
14
+
15
+ }
16
+ }
@@ -1,15 +1,11 @@
1
1
  """Public API tests."""
2
2
 
3
- from __future__ import unicode_literals
4
-
5
3
  import os
6
4
  import tempfile
7
5
 
8
6
  from django import test
9
7
  from django.contrib.auth.models import Group
10
8
 
11
- import six
12
-
13
9
  from ..exceptions import DiffFound, FixtureCreated
14
10
  from ..fixture import Fixture
15
11
 
@@ -57,8 +53,8 @@ class SmokeTest(test.TransactionTestCase):
57
53
  1 instance(s) of auth.group have not expected fields
58
54
  #1:
59
55
  name:
60
- - u'testgroup'
61
- + u'BOOM'
56
+ - 'testgroup'
57
+ + 'BOOM'
62
58
  '''
63
59
 
64
60
  with self.assertRaises(DiffFound) as result:
@@ -73,12 +69,12 @@ class SmokeTest(test.TransactionTestCase):
73
69
  expected = '''
74
70
  1 unexpected instance(s) of auth.group found in the dump:
75
71
  #2:
76
- {u'name': u'unexpected', u'permissions': []}
72
+ {'name': 'unexpected', 'permissions': []}
77
73
  1 instance(s) of auth.group have not expected fields
78
74
  #1:
79
75
  name:
80
- - u'testgroup'
81
- + u'BOOM'
76
+ - 'testgroup'
77
+ + 'BOOM'
82
78
  '''
83
79
 
84
80
  with self.assertRaises(DiffFound) as result:
@@ -90,10 +86,10 @@ class SmokeTest(test.TransactionTestCase):
90
86
  expected = '''
91
87
  1 unexpected instance(s) of auth.group found in the dump:
92
88
  #2:
93
- {u'name': u'unexpected', u'permissions': []}
89
+ {'name': 'unexpected', 'permissions': []}
94
90
  1 expected instance(s) of auth.group missing from dump:
95
91
  #1:
96
- {u'name': u'testgroup', u'permissions': []}
92
+ {'name': 'testgroup', 'permissions': []}
97
93
  '''
98
94
 
99
95
  with self.assertRaises(DiffFound) as result:
@@ -101,13 +97,6 @@ class SmokeTest(test.TransactionTestCase):
101
97
  self.assert_message_is(expected, result)
102
98
 
103
99
  def assert_message_is(self, expected, result):
104
- if six.PY3:
105
- expected = expected.replace("u'", "'")
106
-
107
- msg = (
108
- result.exception.message
109
- if six.PY2 else result.exception.args[0]
110
- )
111
-
100
+ msg = result.exception.args[0]
112
101
  out = '\n'.join(msg.split('\n')[1:])
113
102
  assert out.strip() == expected.strip()
@@ -23,3 +23,12 @@ class FixtureTest(test.TransactionTestCase):
23
23
 
24
24
  def test_models(self):
25
25
  assert self.fixture.models == [Group]
26
+
27
+ def test_diff_exact_match_returns_none(self):
28
+ # Regression: the always-False `not diff` (imported function) bug
29
+ # caused diff() to never return None, leaking temp files and breaking
30
+ # assertNoDiff() with a TypeError on exact matches.
31
+ # Fixture: # [{"model": "auth.group", "pk": 1,
32
+ # "fields": {"name": "initial_name"}}]
33
+ Group.objects.create(id=1, name='initial_name')
34
+ assert self.fixture.diff() is None
@@ -1,14 +1,15 @@
1
- from dbdiff.test import DbdiffTestMixin
2
-
3
1
  from django import test
4
2
  from django.contrib.contenttypes.models import ContentType
5
3
  from django.db import connection
6
4
 
5
+ from dbdiff.test import DbdiffTestMixin
6
+
7
7
 
8
8
  class ContentTypeTestCase(DbdiffTestMixin, test.TestCase):
9
9
  dbdiff_models = [ContentType]
10
10
  dbdiff_exclude = {'*': ['created']}
11
11
  dbdiff_reset_sequences = True
12
+ dbdiff_ignore_pk = True
12
13
  dbdiff_expected = 'dbdiff/tests/test_mixin.json'
13
14
 
14
15
  def test_db_import(self):