Skip to content

Commit 4d61618

Browse files
committed
Merge pull request #619 from sliverc/add_reset_sequences_support
Support reset sequences
2 parents 2cb64e9 + 04f117b commit 4d61618

File tree

5 files changed

+186
-45
lines changed

5 files changed

+186
-45
lines changed

docs/changelog.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ Features
88
^^^^^^^^
99

1010
* Added new fixture :fixture:`django_assert_max_num_queries` (#547).
11-
* Assed support for ``connection`` and returning the wrapped context manager
11+
* Added support for ``connection`` and returning the wrapped context manager
1212
with :fixture:`django_assert_num_queries` (#547).
13+
* Added support for resetting sequences via
14+
:fixture:`django_db_reset_sequences` (#619).
1315

1416
3.3.3 (2018-07-26)
1517
------------------

docs/helpers.rst

+43-11
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ on what marks are and for notes on using_ them.
1313
.. _using: https://pytest.org/en/latest/example/markers.html#marking-whole-classes-or-modules
1414

1515

16-
``pytest.mark.django_db(transaction=False)`` - request database access
17-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16+
``pytest.mark.django_db`` - request database access
17+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1818

19-
.. :py:function:: pytest.mark.django_db:
19+
.. :py:function:: pytest.mark.django_db([transaction=False, reset_sequences=False]):
2020
2121
This is used to mark a test function as requiring the database. It
2222
will ensure the database is set up correctly for the test. Each test
@@ -25,9 +25,9 @@ of the test. This behavior is the same as Django's standard
2525
`django.test.TestCase`_ class.
2626

2727
In order for a test to have access to the database it must either
28-
be marked using the ``django_db`` mark or request one of the ``db``
29-
or ``transactional_db`` fixtures. Otherwise the test will fail
30-
when trying to access the database.
28+
be marked using the ``django_db`` mark or request one of the ``db``,
29+
``transactional_db`` or ``django_db_reset_sequences`` fixtures. Otherwise the
30+
test will fail when trying to access the database.
3131

3232
:type transaction: bool
3333
:param transaction:
@@ -38,14 +38,23 @@ when trying to access the database.
3838
uses. When ``transaction=True``, the behavior will be the same as
3939
`django.test.TransactionTestCase`_
4040

41+
42+
:type reset_sequences: bool
43+
:param reset_sequences:
44+
The ``reset_sequences`` argument will ask to reset auto increment sequence
45+
values (e.g. primary keys) before running the test. Defaults to
46+
``False``. Must be used together with ``transaction=True`` to have an
47+
effect. Please be aware that not all databases support this feature.
48+
For details see :py:attr:`django.test.TransactionTestCase.reset_sequences`.
49+
4150
.. note::
4251

4352
If you want access to the Django database *inside a fixture*
4453
this marker will not help even if the function requesting your
4554
fixture has this marker applied. To access the database in a
46-
fixture, the fixture itself will have to request the ``db`` or
47-
``transactional_db`` fixture. See below for a description of
48-
them.
55+
fixture, the fixture itself will have to request the ``db``,
56+
``transactional_db`` or ``django_db_reset_sequences`` fixture. See below
57+
for a description of them.
4958

5059
.. note:: Automatic usage with ``django.test.TestCase``.
5160

@@ -217,8 +226,19 @@ mark to signal it needs the database.
217226

218227
This fixture can be used to request access to the database including
219228
transaction support. This is only required for fixtures which need
220-
database access themselves. A test function would normally use the
221-
``pytest.mark.django_db`` mark to signal it needs the database.
229+
database access themselves. A test function should normally use the
230+
``pytest.mark.django_db`` mark with ``transaction=True``.
231+
232+
``django_db_reset_sequences``
233+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
234+
235+
.. fixture:: django_db_reset_sequences
236+
237+
This fixture provides the same transactional database access as
238+
``transactional_db``, with additional support for reset of auto increment
239+
sequences (if your database supports it). This is only required for
240+
fixtures which need database access themselves. A test function should
241+
normally use the ``pytest.mark.django_db`` mark with ``transaction=True`` and ``reset_sequences=True``.
222242

223243
``live_server``
224244
~~~~~~~~~~~~~~~
@@ -229,6 +249,18 @@ or by requesting it's string value: ``unicode(live_server)``. You can
229249
also directly concatenate a string to form a URL: ``live_server +
230250
'/foo``.
231251

252+
.. note:: Combining database access fixtures.
253+
254+
When using multiple database fixtures together, only one of them is
255+
used. Their order of precedence is as follows (the last one wins):
256+
257+
* ``db``
258+
* ``transactional_db``
259+
* ``django_db_reset_sequences``
260+
261+
In addition, using ``live_server`` will also trigger transactional
262+
database access, if not specified.
263+
232264
``settings``
233265
~~~~~~~~~~~~
234266

pytest_django/fixtures.py

+43-13
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
from .lazy_django import skip_if_no_django
1717

18-
__all__ = ['django_db_setup', 'db', 'transactional_db', 'admin_user',
19-
'django_user_model', 'django_username_field',
18+
__all__ = ['django_db_setup', 'db', 'transactional_db', 'django_db_reset_sequences',
19+
'admin_user', 'django_user_model', 'django_username_field',
2020
'client', 'admin_client', 'rf', 'settings', 'live_server',
2121
'_live_server_helper', 'django_assert_num_queries',
2222
'django_assert_max_num_queries']
@@ -109,7 +109,8 @@ def teardown_database():
109109
request.addfinalizer(teardown_database)
110110

111111

112-
def _django_db_fixture_helper(transactional, request, django_db_blocker):
112+
def _django_db_fixture_helper(request, django_db_blocker,
113+
transactional=False, reset_sequences=False):
113114
if is_django_unittest(request):
114115
return
115116

@@ -122,6 +123,11 @@ def _django_db_fixture_helper(transactional, request, django_db_blocker):
122123

123124
if transactional:
124125
from django.test import TransactionTestCase as django_case
126+
127+
if reset_sequences:
128+
class ResetSequenceTestCase(django_case):
129+
reset_sequences = True
130+
django_case = ResetSequenceTestCase
125131
else:
126132
from django.test import TestCase as django_case
127133

@@ -141,7 +147,7 @@ def _disable_native_migrations():
141147

142148
@pytest.fixture(scope='function')
143149
def db(request, django_db_setup, django_db_blocker):
144-
"""Require a django test database
150+
"""Require a django test database.
145151
146152
This database will be setup with the default fixtures and will have
147153
the transaction management disabled. At the end of the test the outer
@@ -150,30 +156,54 @@ def db(request, django_db_setup, django_db_blocker):
150156
This is more limited than the ``transactional_db`` resource but
151157
faster.
152158
153-
If both this and ``transactional_db`` are requested then the
154-
database setup will behave as only ``transactional_db`` was
155-
requested.
159+
If multiple database fixtures are requested, they take precedence
160+
over each other in the following order (the last one wins): ``db``,
161+
``transactional_db``, ``django_db_reset_sequences``.
156162
"""
163+
if 'django_db_reset_sequences' in request.funcargnames:
164+
request.getfixturevalue('django_db_reset_sequences')
157165
if 'transactional_db' in request.funcargnames \
158166
or 'live_server' in request.funcargnames:
159167
request.getfixturevalue('transactional_db')
160168
else:
161-
_django_db_fixture_helper(False, request, django_db_blocker)
169+
_django_db_fixture_helper(request, django_db_blocker, transactional=False)
162170

163171

164172
@pytest.fixture(scope='function')
165173
def transactional_db(request, django_db_setup, django_db_blocker):
166-
"""Require a django test database with transaction support
174+
"""Require a django test database with transaction support.
167175
168176
This will re-initialise the django database for each test and is
169177
thus slower than the normal ``db`` fixture.
170178
171179
If you want to use the database with transactions you must request
172-
this resource. If both this and ``db`` are requested then the
173-
database setup will behave as only ``transactional_db`` was
174-
requested.
180+
this resource.
181+
182+
If multiple database fixtures are requested, they take precedence
183+
over each other in the following order (the last one wins): ``db``,
184+
``transactional_db``, ``django_db_reset_sequences``.
185+
"""
186+
if 'django_db_reset_sequences' in request.funcargnames:
187+
request.getfuncargvalue('django_db_reset_sequences')
188+
_django_db_fixture_helper(request, django_db_blocker,
189+
transactional=True)
190+
191+
192+
@pytest.fixture(scope='function')
193+
def django_db_reset_sequences(request, django_db_setup, django_db_blocker):
194+
"""Require a transactional test database with sequence reset support.
195+
196+
This behaves like the ``transactional_db`` fixture, with the addition
197+
of enforcing a reset of all auto increment sequences. If the enquiring
198+
test relies on such values (e.g. ids as primary keys), you should
199+
request this resource to ensure they are consistent across tests.
200+
201+
If multiple database fixtures are requested, they take precedence
202+
over each other in the following order (the last one wins): ``db``,
203+
``transactional_db``, ``django_db_reset_sequences``.
175204
"""
176-
_django_db_fixture_helper(True, request, django_db_blocker)
205+
_django_db_fixture_helper(request, django_db_blocker,
206+
transactional=True, reset_sequences=True)
177207

178208

179209
@pytest.fixture()

pytest_django/plugin.py

+14-8
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from .fixtures import django_user_model # noqa
3232
from .fixtures import django_username_field # noqa
3333
from .fixtures import live_server # noqa
34+
from .fixtures import django_db_reset_sequences # noqa
3435
from .fixtures import rf # noqa
3536
from .fixtures import settings # noqa
3637
from .fixtures import transactional_db # noqa
@@ -384,13 +385,15 @@ def django_db_blocker():
384385
def _django_db_marker(request):
385386
"""Implement the django_db marker, internal to pytest-django.
386387
387-
This will dynamically request the ``db`` or ``transactional_db``
388-
fixtures as required by the django_db marker.
388+
This will dynamically request the ``db``, ``transactional_db`` or
389+
``django_db_reset_sequences`` fixtures as required by the django_db marker.
389390
"""
390391
marker = request.node.get_closest_marker('django_db')
391392
if marker:
392-
transaction = validate_django_db(marker)
393-
if transaction:
393+
transaction, reset_sequences = validate_django_db(marker)
394+
if reset_sequences:
395+
request.getfixturevalue('django_db_reset_sequences')
396+
elif transaction:
394397
request.getfixturevalue('transactional_db')
395398
else:
396399
request.getfixturevalue('db')
@@ -672,11 +675,14 @@ def restore(self):
672675
def validate_django_db(marker):
673676
"""Validate the django_db marker.
674677
675-
It checks the signature and creates the `transaction` attribute on
676-
the marker which will have the correct value.
678+
It checks the signature and creates the ``transaction`` and
679+
``reset_sequences`` attributes on the marker which will have the
680+
correct values.
681+
682+
A sequence reset is only allowed when combined with a transaction.
677683
"""
678-
def apifun(transaction=False):
679-
return transaction
684+
def apifun(transaction=False, reset_sequences=False):
685+
return transaction, reset_sequences
680686
return apifun(*marker.args, **marker.kwargs)
681687

682688

0 commit comments

Comments
 (0)