django-dbdiff 0.9.6__py3-none-any.whl

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 (38) hide show
  1. dbdiff/__init__.py +3 -0
  2. dbdiff/apps.py +44 -0
  3. dbdiff/exceptions.py +72 -0
  4. dbdiff/fixture.py +172 -0
  5. dbdiff/plugin.py +35 -0
  6. dbdiff/sequence.py +57 -0
  7. dbdiff/serializers/__init__.py +1 -0
  8. dbdiff/serializers/base.py +80 -0
  9. dbdiff/serializers/json.py +15 -0
  10. dbdiff/test.py +58 -0
  11. dbdiff/tests/__init__.py +1 -0
  12. dbdiff/tests/decimal_test/__init__.py +1 -0
  13. dbdiff/tests/decimal_test/migrations/0001_initial.py +17 -0
  14. dbdiff/tests/decimal_test/migrations/0002_auto_20160102_0914.py +16 -0
  15. dbdiff/tests/decimal_test/migrations/__init__.py +0 -0
  16. dbdiff/tests/decimal_test/models.py +5 -0
  17. dbdiff/tests/inheritance/__init__.py +1 -0
  18. dbdiff/tests/inheritance/models.py +9 -0
  19. dbdiff/tests/nonintpk/__init__.py +1 -0
  20. dbdiff/tests/nonintpk/models.py +8 -0
  21. dbdiff/tests/project/__init__.py +1 -0
  22. dbdiff/tests/project/settings.py +107 -0
  23. dbdiff/tests/project/settings_mysql.py +21 -0
  24. dbdiff/tests/project/settings_postgresql.py +16 -0
  25. dbdiff/tests/project/settings_sqlite.py +8 -0
  26. dbdiff/tests/project/urls.py +1 -0
  27. dbdiff/tests/test_compare.py +102 -0
  28. dbdiff/tests/test_decimal.py +54 -0
  29. dbdiff/tests/test_fixture.py +25 -0
  30. dbdiff/tests/test_mixin.py +22 -0
  31. dbdiff/tests/test_plugin.py +34 -0
  32. dbdiff/tests/test_utils.py +49 -0
  33. dbdiff/utils.py +179 -0
  34. django_dbdiff-0.9.6.dist-info/METADATA +151 -0
  35. django_dbdiff-0.9.6.dist-info/RECORD +38 -0
  36. django_dbdiff-0.9.6.dist-info/WHEEL +5 -0
  37. django_dbdiff-0.9.6.dist-info/entry_points.txt +2 -0
  38. django_dbdiff-0.9.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,107 @@
1
+ """
2
+ Django settings for project project.
3
+
4
+ Generated by 'django-admin startproject' using Django 1.8.3.dev20150604012123.
5
+
6
+ For more information on this file, see
7
+ https://docs.djangoproject.com/en/dev/topics/settings/
8
+
9
+ For the full list of settings and their values, see
10
+ https://docs.djangoproject.com/en/dev/ref/settings/
11
+ """
12
+
13
+ # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
14
+ import os
15
+
16
+ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17
+
18
+
19
+ # Quick-start development settings - unsuitable for production
20
+ # See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/
21
+
22
+ # SECURITY WARNING: keep the secret key used in production secret!
23
+ SECRET_KEY = '9kq$zffboob0)(sn_mr+^cw*3hair=vp=@616u#gk!31dymqgo'
24
+
25
+ # SECURITY WARNING: don't run with debug turned on in production!
26
+ DEBUG = True
27
+
28
+ ALLOWED_HOSTS = []
29
+
30
+
31
+ # Application definition
32
+
33
+ INSTALLED_APPS = (
34
+ 'django.contrib.admin',
35
+ 'django.contrib.auth',
36
+ 'django.contrib.contenttypes',
37
+ 'django.contrib.sessions',
38
+ 'django.contrib.messages',
39
+ 'django.contrib.staticfiles',
40
+ 'dbdiff',
41
+
42
+ 'dbdiff.tests.decimal_test',
43
+ 'dbdiff.tests.nonintpk',
44
+ 'dbdiff.tests.inheritance',
45
+ )
46
+
47
+ MIDDLEWARE_CLASSES = (
48
+ 'django.contrib.sessions.middleware.SessionMiddleware',
49
+ 'django.middleware.common.CommonMiddleware',
50
+ 'django.middleware.csrf.CsrfViewMiddleware',
51
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
52
+ 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
53
+ 'django.contrib.messages.middleware.MessageMiddleware',
54
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
55
+ 'django.middleware.security.SecurityMiddleware',
56
+ )
57
+
58
+ ROOT_URLCONF = 'dbdiff.tests.project.urls'
59
+
60
+ TEMPLATES = [
61
+ {
62
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
63
+ 'DIRS': [],
64
+ 'APP_DIRS': True,
65
+ 'OPTIONS': {
66
+ 'context_processors': [
67
+ 'django.template.context_processors.debug',
68
+ 'django.template.context_processors.request',
69
+ 'django.contrib.auth.context_processors.auth',
70
+ 'django.contrib.messages.context_processors.messages',
71
+ ],
72
+ },
73
+ },
74
+ ]
75
+
76
+ WSGI_APPLICATION = 'dbdiff.tests.project.wsgi.application'
77
+
78
+
79
+ # Database
80
+ # https://docs.djangoproject.com/en/dev/ref/settings/#databases
81
+
82
+ DATABASES = {
83
+ 'default': {
84
+ 'ENGINE': 'django.db.backends.sqlite3',
85
+ 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
86
+ }
87
+ }
88
+
89
+
90
+ # Internationalization
91
+ # https://docs.djangoproject.com/en/dev/topics/i18n/
92
+
93
+ LANGUAGE_CODE = 'en-us'
94
+
95
+ TIME_ZONE = 'UTC'
96
+
97
+ USE_I18N = True
98
+
99
+ USE_L10N = True
100
+
101
+ USE_TZ = True
102
+
103
+
104
+ # Static files (CSS, JavaScript, Images)
105
+ # https://docs.djangoproject.com/en/dev/howto/static-files/
106
+
107
+ STATIC_URL = '/static/'
@@ -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_psycopg2',
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
+ }
@@ -0,0 +1,8 @@
1
+ from .settings import * # noqa
2
+
3
+ DATABASES = {
4
+ 'default': {
5
+ 'ENGINE': 'django.db.backends.sqlite3',
6
+ 'NAME': ':memory:',
7
+ }
8
+ }
@@ -0,0 +1 @@
1
+ urlpatterns = []
@@ -0,0 +1,102 @@
1
+ """Public API tests."""
2
+
3
+ import os
4
+ import tempfile
5
+
6
+ from django import test
7
+ from django.contrib.auth.models import Group
8
+
9
+ from ..exceptions import DiffFound, FixtureCreated
10
+ from ..fixture import Fixture
11
+
12
+
13
+ class SmokeTest(test.TransactionTestCase):
14
+ def setUp(self):
15
+ fd, self.fixture_path = tempfile.mkstemp(suffix='_dbdiff')
16
+
17
+ def test_000_fixture_auto_create(self):
18
+ fixture = Fixture(self.fixture_path, models=[Group])
19
+
20
+ # Should auto-create the diff
21
+ if fixture.exists:
22
+ os.unlink(fixture.path)
23
+
24
+ Group.objects.create(name='testgroup')
25
+
26
+ with self.assertRaises(FixtureCreated):
27
+ fixture.assertNoDiff()
28
+
29
+ assert fixture.exists
30
+
31
+ with open(self.fixture_path, 'r') as f:
32
+ result = f.read()
33
+
34
+ expected = '''[
35
+ {
36
+ "fields": {
37
+ "name": "testgroup",
38
+ "permissions": []
39
+ },
40
+ "model": "auth.group",
41
+ "pk": 1
42
+ }
43
+ ]'''
44
+
45
+ assert expected.strip() == result.strip()
46
+
47
+ # It should pass now
48
+ fixture.assertNoDiff()
49
+
50
+ # It should break now !
51
+ Group.objects.all().update(name='BOOM')
52
+ expected = '''
53
+ 1 instance(s) of auth.group have not expected fields
54
+ #1:
55
+ name:
56
+ - 'testgroup'
57
+ + 'BOOM'
58
+ '''
59
+
60
+ with self.assertRaises(DiffFound) as result:
61
+ fixture.assertNoDiff()
62
+ self.assert_message_is(expected, result)
63
+
64
+ # Excluding the name parameter, there should be no diff
65
+ fixture.assertNoDiff(exclude={'auth.group': ['name']})
66
+
67
+ # Assert it finds unexpected model
68
+ Group.objects.create(name='unexpected')
69
+ expected = '''
70
+ 1 unexpected instance(s) of auth.group found in the dump:
71
+ #2:
72
+ {'name': 'unexpected', 'permissions': []}
73
+ 1 instance(s) of auth.group have not expected fields
74
+ #1:
75
+ name:
76
+ - 'testgroup'
77
+ + 'BOOM'
78
+ '''
79
+
80
+ with self.assertRaises(DiffFound) as result:
81
+ fixture.assertNoDiff()
82
+ self.assert_message_is(expected, result)
83
+
84
+ # Assert it finds missing model
85
+ Group.objects.get(pk=1).delete()
86
+ expected = '''
87
+ 1 unexpected instance(s) of auth.group found in the dump:
88
+ #2:
89
+ {'name': 'unexpected', 'permissions': []}
90
+ 1 expected instance(s) of auth.group missing from dump:
91
+ #1:
92
+ {'name': 'testgroup', 'permissions': []}
93
+ '''
94
+
95
+ with self.assertRaises(DiffFound) as result:
96
+ fixture.assertNoDiff()
97
+ self.assert_message_is(expected, result)
98
+
99
+ def assert_message_is(self, expected, result):
100
+ msg = result.exception.args[0]
101
+ out = '\n'.join(msg.split('\n')[1:])
102
+ assert out.strip() == expected.strip()
@@ -0,0 +1,54 @@
1
+ import os
2
+
3
+ from django import test
4
+
5
+ from .decimal_test.models import TestModel as DecimalTestModel
6
+ from ..fixture import Fixture
7
+
8
+
9
+ class DecimalDiffTest(test.TransactionTestCase):
10
+ reset_sequences = True
11
+
12
+ expected = os.path.join(
13
+ 'dbdiff',
14
+ 'tests',
15
+ 'decimal_test',
16
+ 'expected.json'
17
+ )
18
+ model = DecimalTestModel
19
+
20
+ def test_data_diff_is_empty_with_two_decimal_float(self):
21
+ self.model.objects.create(test_field=1.10)
22
+ Fixture(self.expected).assertNoDiff()
23
+
24
+ def test_data_diff_is_empty_with_one_decimal_float(self):
25
+ self.model.objects.create(test_field=1.1)
26
+ Fixture(self.expected).assertNoDiff()
27
+
28
+ def test_data_diff_is_empty_with_two_decimal_string(self):
29
+ self.model.objects.create(test_field='1.10')
30
+ Fixture(self.expected).assertNoDiff()
31
+
32
+ def test_data_diff_is_empty_with_one_decimal_string(self):
33
+ self.model.objects.create(test_field='1.1')
34
+ Fixture(self.expected).assertNoDiff()
35
+
36
+
37
+ class NoReminderDecimalDiffTest(test.TransactionTestCase):
38
+ reset_sequences = True
39
+
40
+ expected = os.path.join(
41
+ 'dbdiff',
42
+ 'tests',
43
+ 'decimal_test',
44
+ 'expected_no_reminder.json'
45
+ )
46
+ model = DecimalTestModel
47
+
48
+ def test_data_diff_is_empty_with_no_decimal_string(self):
49
+ self.model.objects.create(test_field=10)
50
+ Fixture(self.expected).assertNoDiff()
51
+
52
+ def test_data_diff_is_empty_with_no_decimal_int(self):
53
+ self.model.objects.create(test_field='10')
54
+ Fixture(self.expected).assertNoDiff()
@@ -0,0 +1,25 @@
1
+ import os
2
+
3
+ from django import test
4
+ from django.contrib.auth.models import Group
5
+
6
+ from ..fixture import Fixture
7
+
8
+
9
+ class FixtureTest(test.TransactionTestCase):
10
+ def setUp(self):
11
+ self.fixture = Fixture('dbdiff/fixtures/dbdiff_test_group.json')
12
+
13
+ def test_fixture_path(self):
14
+ assert self.fixture.path == os.path.abspath(os.path.join(
15
+ os.path.dirname(__file__),
16
+ '..',
17
+ 'fixtures',
18
+ 'dbdiff_test_group.json'
19
+ ))
20
+
21
+ def test_indent(self):
22
+ assert self.fixture.indent == 4
23
+
24
+ def test_models(self):
25
+ assert self.fixture.models == [Group]
@@ -0,0 +1,22 @@
1
+ from dbdiff.test import DbdiffTestMixin
2
+
3
+ from django import test
4
+ from django.contrib.contenttypes.models import ContentType
5
+ from django.db import connection
6
+
7
+
8
+ class ContentTypeTestCase(DbdiffTestMixin, test.TestCase):
9
+ dbdiff_models = [ContentType]
10
+ dbdiff_exclude = {'*': ['created']}
11
+ dbdiff_reset_sequences = True
12
+ dbdiff_expected = 'dbdiff/tests/test_mixin.json'
13
+
14
+ def test_db_import(self):
15
+ if connection.vendor != 'postgresql':
16
+ return # not supported for now
17
+ super(ContentTypeTestCase, self).test_db_import()
18
+ self.assertTrue(self.dbdiff_test_executed)
19
+
20
+ def dbdiff_test(self):
21
+ ContentType.objects.create()
22
+ self.dbdiff_test_executed = True
@@ -0,0 +1,34 @@
1
+ from dbdiff.tests.decimal_test.models import TestModel as DecimalModel
2
+ from dbdiff.tests.inheritance.models import Child, Parent
3
+ from dbdiff.tests.nonintpk.models import Nonintpk
4
+
5
+ import pytest
6
+
7
+
8
+ @pytest.mark.dbdiff(models=[DecimalModel])
9
+ def test_insert_first():
10
+ assert DecimalModel.objects.count() == 0
11
+ assert DecimalModel.objects.create(test_field=1).pk == 1
12
+
13
+
14
+ @pytest.mark.dbdiff(models=[DecimalModel])
15
+ def test_still_first_pk():
16
+ assert DecimalModel.objects.count() == 0
17
+ assert DecimalModel.objects.create(test_field=1).pk == 1
18
+
19
+
20
+ @pytest.mark.dbdiff(models=[DecimalModel, Nonintpk])
21
+ def test_doesnt_reset_nonintpk_which_would_fail():
22
+ assert DecimalModel.objects.count() == 0
23
+
24
+
25
+ @pytest.mark.dbdiff(models=[Child])
26
+ def test_inheritance_sequence_reset():
27
+ assert Child.objects.count() == 0
28
+ assert Child.objects.create(name='1').pk == 1
29
+
30
+
31
+ @pytest.mark.dbdiff(models=[Child])
32
+ def test_inheritance_sequence_reset_again():
33
+ assert Parent.objects.count() == 0
34
+ assert Child.objects.create(name='1').pk == 1
@@ -0,0 +1,49 @@
1
+ import os
2
+
3
+ from dbdiff.utils import diff, get_absolute_path, get_model_names
4
+
5
+ from django.contrib.auth.models import Group
6
+
7
+
8
+ def test_diff_ignore_pk():
9
+ """With ignore_pk=True, records are matched by content, not pk."""
10
+ expected = {
11
+ 'auth.group': {
12
+ 1: {'name': 'testgroup', 'permissions': []},
13
+ },
14
+ }
15
+ result = {
16
+ 'auth.group': {
17
+ 99: {'name': 'testgroup', 'permissions': []}, # same content, diff pk
18
+ },
19
+ }
20
+ unexpected, missing, different = diff(expected, result, ignore_pk=True)
21
+ assert not unexpected and not missing and not different
22
+
23
+
24
+ def test_diff_with_pk_by_default():
25
+ """With ignore_pk=False, same content but different pk yields missing/unexpected."""
26
+ expected = {
27
+ 'auth.group': {
28
+ 1: {'name': 'testgroup', 'permissions': []},
29
+ },
30
+ }
31
+ result = {
32
+ 'auth.group': {
33
+ 99: {'name': 'testgroup', 'permissions': []},
34
+ },
35
+ }
36
+ unexpected, missing, different = diff(expected, result, ignore_pk=False)
37
+ assert missing == {'auth.group': {1: {'name': 'testgroup', 'permissions': []}}}
38
+ assert unexpected == {'auth.group': {99: {'name': 'testgroup', 'permissions': []}}}
39
+
40
+
41
+ def test_get_model_names():
42
+ assert get_model_names([Group, 'auth.user']) == ['auth.group', 'auth.user']
43
+
44
+
45
+ def test_get_absolute_path_starting_with_dot():
46
+ assert get_absolute_path('./foo') == os.path.join(
47
+ os.path.abspath(os.path.dirname('__file__')),
48
+ 'foo',
49
+ )
dbdiff/utils.py ADDED
@@ -0,0 +1,179 @@
1
+ """Utils for dbdiff."""
2
+
3
+ import os
4
+
5
+ from django.apps import apps
6
+ from django.db import connections
7
+
8
+ from importlib.util import find_spec
9
+
10
+ def get_tree(dump, exclude=None):
11
+ """Return a tree of model -> pk -> fields."""
12
+ exclude = exclude or {}
13
+ tree = {}
14
+
15
+ for instance in dump:
16
+ if instance['model'] not in tree:
17
+ tree[instance['model']] = {}
18
+
19
+ exclude_fields = exclude.get(instance['model'], [])
20
+ exclude_fields += exclude.get('*', [])
21
+
22
+ tree[instance['model']][instance['pk']] = {
23
+ name: value for name, value in instance['fields'].items()
24
+ if name not in exclude_fields
25
+ }
26
+
27
+ return tree
28
+
29
+
30
+ def _get_unexpected(expected, result):
31
+ unexpected = {}
32
+
33
+ for model, result_instances in result.items():
34
+ expected_pks = expected.get(model, {}).keys()
35
+
36
+ for pk, result_fields in result_instances.items():
37
+ if pk in expected_pks:
38
+ continue
39
+
40
+ unexpected.setdefault(model, {})
41
+ unexpected[model][pk] = result_fields
42
+
43
+ return unexpected
44
+
45
+
46
+ def diff(expected, result, ignore_pk=False):
47
+ """Return unexpected, missing and diff between expected and result.
48
+
49
+ When ignore_pk is True, records are matched by their field values (content)
50
+ instead of primary key. Records with the same content but different pks
51
+ are considered matching.
52
+ """
53
+ missing, different = {}, {}
54
+
55
+ if ignore_pk:
56
+ unexpected, missing, different = _diff_by_content(expected, result)
57
+ return unexpected, missing, different
58
+
59
+ unexpected = _get_unexpected(expected, result)
60
+
61
+ for model, expected_instances in expected.items():
62
+ for pk, expected_fields in expected_instances.items():
63
+ if pk not in result.get(model, {}):
64
+ missing.setdefault(model, {})
65
+ missing[model][pk] = expected_fields
66
+ continue
67
+
68
+ result_fields = result[model][pk]
69
+ if expected_fields == result_fields:
70
+ continue
71
+
72
+ different.setdefault(model, {})
73
+ different[model].setdefault(pk, {})
74
+
75
+ for expected_field, expected_value in expected_fields.items():
76
+ result_value = result_fields[expected_field]
77
+
78
+ if expected_value == result_value:
79
+ continue
80
+
81
+ different[model][pk][expected_field] = (
82
+ expected_value,
83
+ result_value
84
+ )
85
+ return unexpected, missing, different
86
+
87
+
88
+ def _diff_by_content(expected, result):
89
+ """Diff by matching records on field content instead of primary key."""
90
+ unexpected, missing, different = {}, {}, {}
91
+
92
+ for model in set(expected.keys()) | set(result.keys()):
93
+ expected_list = list(expected.get(model, {}).items())
94
+ result_list = list(result.get(model, {}).items())
95
+ matched_result_indices = set()
96
+
97
+ for exp_pk, exp_fields in expected_list:
98
+ found = False
99
+ for i, (res_pk, res_fields) in enumerate(result_list):
100
+ if i in matched_result_indices:
101
+ continue
102
+ if exp_fields == res_fields:
103
+ matched_result_indices.add(i)
104
+ found = True
105
+ break
106
+ if not found:
107
+ missing.setdefault(model, {})
108
+ missing[model][exp_pk] = exp_fields
109
+
110
+ for i, (res_pk, res_fields) in enumerate(result_list):
111
+ if i not in matched_result_indices:
112
+ unexpected.setdefault(model, {})
113
+ unexpected[model][res_pk] = res_fields
114
+
115
+ return unexpected, missing, different
116
+
117
+
118
+ def get_absolute_path(path):
119
+ """Return the absolute path to an app-relative path."""
120
+ if path.startswith('/'):
121
+ return path
122
+
123
+ if path.startswith('.'):
124
+ module_path = '.'
125
+ else:
126
+ module_path = find_spec(path.split('/')[0]).submodule_search_locations[0]
127
+
128
+ return os.path.abspath(os.path.join(
129
+ module_path,
130
+ *path.split('/')[1:]
131
+ ))
132
+
133
+
134
+ def get_model_names(model_classes):
135
+ """Return model names for model classes."""
136
+ return [
137
+ m if isinstance(m, str)
138
+ else '%s.%s' % (m._meta.app_label, m._meta.model_name)
139
+ for m in model_classes
140
+ ]
141
+
142
+
143
+ def get_models_tables(models):
144
+ """Return the list of tables for the given models."""
145
+ tables = set()
146
+
147
+ for model in models:
148
+ tables.add(model._meta.db_table)
149
+ tables.update(f.m2m_db_table() for f in
150
+ model._meta.local_many_to_many)
151
+
152
+ return list(tables)
153
+
154
+
155
+ def patch_transaction_test_case():
156
+ """Monkeypatch TransactionTestCase._reset_sequences to support SQLite."""
157
+ from django.test.testcases import TransactionTestCase
158
+ TransactionTestCase.old_reset_sequences = \
159
+ TransactionTestCase._reset_sequences
160
+
161
+ def new_reset_sequences(self, db_name):
162
+ self.old_reset_sequences(db_name)
163
+ connection = connections[db_name]
164
+
165
+ if connection.vendor != 'sqlite':
166
+ return
167
+
168
+ tables = get_models_tables(apps.get_models())
169
+ statements = [
170
+ "UPDATE SQLITE_SEQUENCE SET SEQ=0 WHERE NAME='%s';" % t
171
+ for t in tables
172
+ ]
173
+
174
+ cursor = connection.cursor()
175
+
176
+ for statement in statements:
177
+ cursor.execute(statement)
178
+
179
+ TransactionTestCase._reset_sequences = new_reset_sequences