Skip to content

Commit 1c3bdc1

Browse files
committed
minor tests cleanup
1 parent 8358c9e commit 1c3bdc1

File tree

13 files changed

+142
-52
lines changed

13 files changed

+142
-52
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ install:
4646
- pip install tox "coverage<=4.0" python-coveralls>=2.5 coveralls>=0.5 codecov
4747

4848
script:
49-
- tox -e "py${TRAVIS_PYTHON_VERSION//.}-d${DJANGO//.}-${DB}" -- py.test tests -v -W ignore::DeprecationWarning --capture=no --cov=concurrency --cov-report=xml --cov-config=tests/.coveragerc
49+
- tox -e "py${TRAVIS_PYTHON_VERSION//.}-d${DJANGO//.}-${DB}" -- py.test tests src/concurrency -v
5050

5151
before_success:
5252
- coverage erase

src/concurrency/admin.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def action_checkbox(self, obj):
3838
return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME,
3939
force_text("%s,%s" % (obj.pk,
4040
get_revision_of_object(obj))))
41-
else:
41+
else: # pragma: no cover
4242
return super(ConcurrencyActionMixin, self).action_checkbox(obj)
4343

4444
action_checkbox.short_description = mark_safe('<input type="checkbox" id="action-toggle" />')
@@ -69,7 +69,7 @@ def response_action(self, request, queryset): # noqa
6969
# Use the action whose button was pushed
7070
try:
7171
data.update({'action': data.getlist('action')[action_index]})
72-
except IndexError:
72+
except IndexError: # pragma: no cover
7373
# If we didn't get an action from the chosen form that's invalid
7474
# POST data, so by deleting action it'll fail the validation check
7575
# below. So no need to do anything here
@@ -90,10 +90,11 @@ def response_action(self, request, queryset): # noqa
9090
else:
9191
selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME)
9292

93-
revision_field = self.model._concurrencymeta.field
9493
if not selected:
9594
return None
9695

96+
revision_field = self.model._concurrencymeta.field
97+
9798
if self.check_concurrent_action:
9899
self.delete_selected_confirmation_template = self.get_confirmation_template()
99100

src/concurrency/api.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from concurrency.config import conf
99
from concurrency.core import _select_lock, get_version_fieldname # _wrap_model_save
1010
from concurrency.exceptions import RecordModifiedError
11+
from concurrency.utils import deprecated
1112

1213
__all__ = ['apply_concurrency_check', 'concurrency_check', 'get_revision_of_object',
1314
'RecordModifiedError', 'disable_concurrency',
@@ -66,10 +67,11 @@ def apply_concurrency_check(model, fieldname, versionclass):
6667

6768
class_prepared_concurrency_handler(model)
6869

69-
if not model._concurrencymeta.versioned_save:
70-
versionclass._wrap_model_save(model)
70+
# if not model._concurrencymeta.versioned_save:
71+
# versionclass._wrap_model_save(model)
7172

7273

74+
@deprecated(version="1.5")
7375
def concurrency_check(model_instance, force_insert=False, force_update=False, using=None, **kwargs):
7476
if not force_insert:
7577
_select_lock(model_instance)

src/concurrency/compat.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
try:
1616
from django.urls.utils import get_callable
1717
except ImportError:
18-
from django.core.urlresolvers import get_callable
18+
from django.core.urlresolvers import get_callable # noqa

src/concurrency/config.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,29 @@ class AppSettings(object):
2323
"""
2424
Class to manage application related settings
2525
How to use:
26-
26+
>>> import pytest
2727
>>> from django.conf import settings
28+
>>> from concurrency.utils import fqn
2829
>>> settings.APP_OVERRIDE = 'overridden'
29-
>>> settings.MYAPP_CALLBACK = 100
3030
>>> class MySettings(AppSettings):
31-
... defaults = {'ENTRY1': 'abc', 'ENTRY2': 123, 'OVERRIDE': None, 'CALLBACK':10}
32-
... def set_CALLBACK(self, value):
33-
... setattr(self, 'CALLBACK', value*2)
31+
... defaults = {'ENTRY1': 'abc', 'ENTRY2': 123, 'OVERRIDE': None, 'CALLBACK': fqn(fqn)}
3432
3533
>>> conf = MySettings("APP")
36-
>>> conf.ENTRY1, settings.APP_ENTRY1
34+
>>> str(conf.ENTRY1), str(settings.APP_ENTRY1)
3735
('abc', 'abc')
38-
>>> conf.OVERRIDE, settings.APP_OVERRIDE
36+
>>> str(conf.OVERRIDE), str(settings.APP_OVERRIDE)
3937
('overridden', 'overridden')
4038
4139
>>> conf = MySettings("MYAPP")
4240
>>> conf.ENTRY2, settings.MYAPP_ENTRY2
4341
(123, 123)
42+
>>> settings.MYAPP_CALLBACK = fqn
4443
>>> conf = MySettings("MYAPP")
45-
>>> conf.CALLBACK
46-
200
44+
>>> conf.CALLBACK == fqn
45+
True
46+
>>> with pytest.raises(ImproperlyConfigured):
47+
... settings.OTHER_CALLBACK = 222
48+
... conf = MySettings("OTHER")
4749
4850
"""
4951
defaults = {
@@ -81,7 +83,7 @@ def _set_attr(self, prefix_name, value):
8183
elif callable(value):
8284
func = value
8385
else:
84-
raise ImproperlyConfigured("`CALLBACK` must be a callable or a fullpath to callable")
86+
raise ImproperlyConfigured("{} is not a valid value for `CALLBACK`. It must be a callable or a fullpath to callable. ".format(value))
8587
self._callback = func
8688

8789
setattr(self, name, value)

src/concurrency/management/commands/triggers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,5 @@ def handle(self, *args, **options):
7676
self.stdout.write('')
7777
else:
7878
raise Exception()
79-
except ImproperlyConfigured as e:
79+
except ImproperlyConfigured as e: # pragma: no cover
8080
self.stdout.write(self.style.ERROR(e))

src/concurrency/triggers.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from .fields import _TRIGGERS # noqa
1111

12+
1213
def get_trigger_name(field):
1314
"""
1415
@@ -48,6 +49,8 @@ def drop_triggers(*databases):
4849
f.drop(field)
4950
field._trigger_exists = False
5051
ret[alias].append([model, field, field.trigger_name])
52+
else: # pragma: no cover
53+
pass
5154
return ret
5255

5356

@@ -60,14 +63,15 @@ def create_triggers(databases):
6063
field = model._concurrencymeta.field
6164
storage = model._concurrencymeta.triggers
6265
alias = router.db_for_write(model)
63-
if alias in databases:
64-
if field not in storage:
65-
storage.append(field)
66-
connection = connections[alias]
67-
f = factory(connection)
68-
f.create(field)
69-
ret[alias].append([model, field, field.trigger_name])
70-
# _TRIGGERS = []
66+
if (alias in databases) and field not in storage:
67+
storage.append(field)
68+
connection = connections[alias]
69+
f = factory(connection)
70+
f.create(field)
71+
ret[alias].append([model, field, field.trigger_name])
72+
else: # pragma: no cover
73+
pass
74+
7175
return ret
7276

7377

@@ -168,5 +172,5 @@ def factory(conn):
168172
'sqlite3': Sqlite3,
169173
'sqlite': Sqlite3,
170174
}[conn.vendor](conn)
171-
except KeyError:
175+
except KeyError: # pragma: no cover
172176
raise ValueError('{} is not supported by TriggerVersionField'.format(conn))

src/concurrency/utils.py

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,26 @@ def deprecated(replacement=None, version=None):
1414
"""A decorator which can be used to mark functions as deprecated.
1515
replacement is a callable that will be called with the same args
1616
as the decorated function.
17-
17+
>>> import pytest
1818
>>> @deprecated()
19-
... def foo(x):
19+
... def foo1(x):
2020
... return x
2121
...
22-
>>> ret = foo(1)
23-
DeprecationWarning: foo is deprecated
24-
>>> ret
22+
>>> pytest.warns(DeprecationWarning, foo1, 1)
2523
1
26-
>>>
27-
>>>
2824
>>> def newfun(x):
2925
... return 0
3026
...
31-
>>> @deprecated(newfun)
32-
... def foo(x):
27+
>>> @deprecated(newfun, '1.1')
28+
... def foo2(x):
3329
... return x
3430
...
35-
>>> ret = foo(1)
36-
DeprecationWarning: foo is deprecated; use newfun instead
37-
>>> ret
31+
>>> pytest.warns(DeprecationWarning, foo2, 1)
3832
0
3933
>>>
4034
"""
4135

42-
def outer(oldfun): # pragma: no cover
36+
def outer(oldfun):
4337
def inner(*args, **kwargs):
4438
msg = "%s is deprecated" % oldfun.__name__
4539
if version is not None:
@@ -148,20 +142,27 @@ def fqn(o):
148142
:param o: object or class
149143
:return: class name
150144
145+
>>> import concurrency.fields
151146
>>> fqn('str')
152147
Traceback (most recent call last):
153148
...
154149
ValueError: Invalid argument `str`
155-
>>> class A(object): pass
156-
>>> fqn(A)
157-
'wfp_commonlib.python.reflect.A'
150+
>>> class A(object):
151+
... def method(self):
152+
... pass
153+
>>> str(fqn(A))
154+
'concurrency.utils.A'
155+
156+
>>> str(fqn(A()))
157+
'concurrency.utils.A'
158+
159+
>>> str(fqn(concurrency.fields))
160+
'concurrency.fields'
161+
162+
>>> str(fqn(A.method))
163+
'concurrency.utils.A.method'
158164
159-
>>> fqn(A())
160-
'wfp_commonlib.python.reflect.A'
161165
162-
>>> from wfp_commonlib.python import RexList
163-
>>> fqn(RexList.append)
164-
'wfp_commonlib.python.structure.RexList.append'
165166
"""
166167
parts = []
167168

src/concurrency/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ def conflict(request, target=None, template_name='409.html'):
3030
"""
3131
try:
3232
template = loader.get_template(template_name)
33-
except TemplateDoesNotExist:
33+
except TemplateDoesNotExist: # pragma: no cover
3434
template = Template(
3535
'<h1>Conflict</h1>'
3636
'<p>The request was unsuccessful due to a conflict. '
3737
'The object changed during the transaction.</p>')
3838
try:
3939
saved = target.__class__._default_manager.get(pk=target.pk)
40-
except target.__class__.DoesNotExist:
40+
except target.__class__.DoesNotExist: # pragma: no cover
4141
saved = None
4242
ctx = {'target': target,
4343
'saved': saved,

tests/test_api.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,9 @@ def test_apply_concurrency_check():
5151

5252
with pytest.raises(RecordModifiedError):
5353
instance.save()
54+
55+
56+
@pytest.mark.django_db(transaction=False)
57+
def test_apply_concurrency_check_ignore_multiple_call():
58+
apply_concurrency_check(Group, 'version', IntegerVersionField)
59+
apply_concurrency_check(Group, 'version', IntegerVersionField)

0 commit comments

Comments
 (0)