Skip to content

Commit

Permalink
Merge branch 'release/1.4'
Browse files Browse the repository at this point in the history
* release/1.4:
  bump 1.4
  improve django version detection
  fixes travis config
  updates CHANGES
  open 1.4
  fixes django 1.11 compat issue
  updates changes add South FAQ
  restores and fixes some tests skipped in django 1.10
  add django 1.10 to travis config
  • Loading branch information
saxix committed May 2, 2017
2 parents aa1862a + 3f83bb1 commit ff45e55
Show file tree
Hide file tree
Showing 23 changed files with 171 additions and 75 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ __pycache__
*.pyc
*.egg-info
*.sqlite
.testmondata
17 changes: 15 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ env:
- TOXENV=py27-d19-pg
- TOXENV=py27-d19-sqlite
- TOXENV=py27-d19-mysql
- TOXENV=py27-d110-pg
- TOXENV=py27-d110-sqlite
- TOXENV=py27-d110-mysql
- TOXENV=py27-d111-pg
- TOXENV=py27-d111-sqlite
- TOXENV=py27-d111-mysql

- TOXENV=py33-d18-pg
- TOXENV=py33-d18-sqlite
Expand All @@ -31,19 +37,26 @@ env:
- TOXENV=py35-d18-sqlite
- TOXENV=py35-d19-pg
- TOXENV=py35-d19-sqlite
- TOXENV=py35-d110-pg
- TOXENV=py35-d110-sqlite
- TOXENV=py35-d111-pg
- TOXENV=py35-d111-sqlite

- TOXENV=pypy-d18-pg
- TOXENV=pypy-d18-sqlite
- TOXENV=pypy-d19-pg
- TOXENV=pypy-d19-sqlite

- TOXENV=pypy-d110-pg
- TOXENV=pypy-d110-sqlite



install:
- pip install tox "coverage<=4.0" python-coveralls>=2.5 coveralls>=0.5 codecov

script:
- tox -e $TOXENV -- py.test tests -v --capture=no --cov=concurrency \
--cov-report=xml --cov-config=tests/.coveragerc
- tox -e $TOXENV -- py.test tests -v --capture=no --cov=concurrency --cov-report=xml --cov-config=tests/.coveragerc

before_success:
- coverage erase
Expand Down
5 changes: 5 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
Release 1.4 (dev)
-----------------
* Django 1.11 compatibility
* some minor support for Django 2.0

Release 1.3.2 (10 Sep 2016)
-------------------------
* fixes bug in ConditionalVersionField that produced 'maximum recursion error' when a model had a ManyToManyField with a field to same model (self-relation)
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Django Concurrency

django-concurrency is an optimistic lock [1]_ implementation for Django.

Supported Django versions: 1.6.x, 1.7.x, 1.8.x, 1.9.
Supported Django versions: 1.8.x, 1.9.x, 1.10.x., 1.11.x

It prevents users from doing concurrent editing in Django both from UI and from a
django command.
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
version = ".".join(map(str, concurrency.VERSION[0:2]))
# The full version, including alpha/beta/rc tags.
release = concurrency.get_version()
next_version = '1.4'
next_version = '1.5'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
15 changes: 15 additions & 0 deletions docs/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,23 @@ FAQ
.. contents::
:local:

.. _south:

South support ?
---------------
South support has been removed after version 1.0
when Django <1.6 support has been removed as well.

If needed add these lines to your ``models.py``::


from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^concurrency\.fields\.IntegerVersionField"])


.. _update_fields:


How is managed `update_fields`
------------------------------

Expand Down
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ def run_tests(self):
'Programming Language :: Python',
'Framework :: Django :: 1.8',
'Framework :: Django :: 1.9',
'Framework :: Django :: 1.10',
'Framework :: Django :: 1.11',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
Expand Down
2 changes: 1 addition & 1 deletion src/concurrency/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
__author__ = 'sax'
default_app_config = 'concurrency.apps.ConcurrencyConfig'

VERSION = __version__ = (1, 3, 2, 'final', 0)
VERSION = __version__ = (1, 4, 0, 'final', 0)
NAME = 'django-concurrency'


Expand Down
5 changes: 4 additions & 1 deletion src/concurrency/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from __future__ import absolute_import, unicode_literals

from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import get_callable
try:
from django.core.urlresolvers import get_callable
except ImportError:
from django.urls.utils import get_callable
from django.test.signals import setting_changed
from django.utils import six

Expand Down
14 changes: 13 additions & 1 deletion src/concurrency/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,30 @@
from __future__ import absolute_import, unicode_literals

from django.core.signals import got_request_exception
from django.core.urlresolvers import get_callable

from concurrency.config import conf
from concurrency.exceptions import RecordModifiedError

try:
from django.core.urlresolvers import get_callable
except ImportError:
from django.urls.utils import get_callable



class ConcurrencyMiddleware(object):
""" Intercept :ref:`RecordModifiedError` and invoke a callable defined in
:setting:`CONCURRECY_HANDLER409` passing the request and the object.
"""

def __init__(self, get_response=None):
self.get_response = get_response

def __call__(self, request):
response = self.get_response(request)
return response

def process_exception(self, request, exception):
if isinstance(exception, RecordModifiedError):
got_request_exception.send(sender=self, request=request)
Expand Down
8 changes: 4 additions & 4 deletions src/concurrency/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from django.http import HttpResponse
from django.template import loader
from django.template.base import Template
from django.template.context import RequestContext
from django.utils.translation import ugettext as _

from concurrency.compat import TemplateDoesNotExist
Expand Down Expand Up @@ -40,7 +39,8 @@ def conflict(request, target=None, template_name='409.html'):
saved = target.__class__._default_manager.get(pk=target.pk)
except target.__class__.DoesNotExist:
saved = None
ctx = RequestContext(request, {'target': target,
'saved': saved,
'request_path': request.path})
ctx = {'target': target,
'saved': saved,
'request_path': request.path}

return ConflictResponse(template.render(ctx))
3 changes: 1 addition & 2 deletions src/requirements/develop.pip
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
autopep8
coverage
django_extensions
flake8
ipython
ipython<6.0
pdbpp
psycopg2
sphinx
18 changes: 11 additions & 7 deletions src/requirements/testing.pip
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
django-webtest>=1.7.5
mock>=1.0.1
check-manifest==0.30
django-webtest>=1.9.1
mock>=1.0.1
pytest-cache>=1.0
pytest-cov>=1.6
pytest-django>=2.8
pytest-django>=3.0.0
pytest-echo>=1.3
pytest-pythonpath
pytest>=2.8
tox>=2.3
WebTest>=2.0.11
pytest-pythonpath>=0.7.1
pytest>=3.0.3
pytest-watch
pytest-testmon
pdbpp
readline
tox>=2.4.1
WebTest>=2.0.23
2 changes: 2 additions & 0 deletions tests/demoapp/demo/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ def setUp(self):
last_login=timezone.now(),
email='sax@example.com',
username='sax')
# self.user.set_password('123')
# self.user.save()
admin_register_models()


Expand Down
9 changes: 6 additions & 3 deletions tests/demoapp/demo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ class ConditionalVersionModel(models.Model):
field1 = models.CharField(max_length=30, blank=True, null=True, unique=True)
field2 = models.CharField(max_length=30, blank=True, null=True, unique=True)
field3 = models.CharField(max_length=30, blank=True, null=True, unique=True)
user = models.ForeignKey(User, null=True)
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)

class Meta:
app_label = 'demo'
Expand All @@ -224,7 +224,8 @@ class Anything(models.Model):
ConditionalVersionModelWithoutMeta instances.
"""
name = models.CharField(max_length=10)
a_relation = models.ForeignKey('demo.ConditionalVersionModelWithoutMeta')
a_relation = models.ForeignKey('demo.ConditionalVersionModelWithoutMeta',
on_delete=models.CASCADE)

class Meta:
app_label = 'demo'
Expand All @@ -238,7 +239,7 @@ class ConditionalVersionModelWithoutMeta(models.Model):
field1 = models.CharField(max_length=30, blank=True, null=True, unique=True)
field2 = models.CharField(max_length=30, blank=True, null=True, unique=True)
field3 = models.CharField(max_length=30, blank=True, null=True, unique=True)
user = models.ForeignKey(User, null=True)
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
anythings = models.ManyToManyField(Anything)

class Meta:
Expand All @@ -248,8 +249,10 @@ class Meta:
class ThroughRelation(models.Model):
version = ConditionalVersionField()
left = models.ForeignKey('demo.ConditionalVersionModelSelfRelation',
on_delete=models.CASCADE,
related_name='+')
right = models.ForeignKey('demo.ConditionalVersionModelSelfRelation',
on_delete=models.CASCADE,
related_name='+')

class Meta:
Expand Down
42 changes: 30 additions & 12 deletions tests/demoapp/demo/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
except ImportError:
pass


DEBUG = True
STATIC_URL = '/static/'

Expand All @@ -32,35 +31,54 @@
'demo'
]


MIGRATION_MODULES = {
'demo': 'demo.migrations',
'auth': 'demo.auth_migrations',
}

MIDDLEWARE_CLASSES = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
]
if django.VERSION[0] == 2 or django.VERSION[1] >= 10:
MIDDLEWARE_CLASSES = []
MIDDLEWARE = [
# 'concurrency.middleware.ConcurrencyMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

if django.VERSION[1] >= 10:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
],
# ... some options here ...
},
},
]
else:
TEMPLATE_DIRS = ['demo/templates']
MIDDLEWARE_CLASSES = [
# 'concurrency.middleware.ConcurrencyMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
]

LOGGING = {
'version': 1,
Expand Down
2 changes: 1 addition & 1 deletion tests/demoapp/demo/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@
UpdateView.as_view(model=SimpleConcurrentModel),
name='concurrent-edit'),
url(r'^admin/',
include(admin.site.urls))
admin.site.urls)
)
1 change: 0 additions & 1 deletion tests/test_admin_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from demo.util import unique_id


@pytest.mark.xfail("django.VERSION[:2] == (1, 10)", strict=True)
class TestAdminActions(AdminTestCase):
def _create_conflict(self, pk):
u = SimpleConcurrentModel.objects.get(pk=pk)
Expand Down
8 changes: 6 additions & 2 deletions tests/test_admin_edit.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from django.core.urlresolvers import reverse
import pytest
from django.utils.translation import ugettext as _

import pytest
from demo.base import SENTINEL, AdminTestCase
from demo.models import SimpleConcurrentModel
from demo.util import nextname

from concurrency.forms import VersionFieldSigner

try:
from django.core.urlresolvers import reverse
except ImportError:
from django.urls import reverse


@pytest.mark.django_db
@pytest.mark.admin
Expand Down
3 changes: 2 additions & 1 deletion tests/test_admin_list_editable.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from django.contrib.admin.sites import site
from django.contrib.contenttypes.models import ContentType
from django.db import transaction
from django.test import modify_settings
from django.utils.encoding import force_text

import pytest
Expand All @@ -18,7 +19,7 @@
from concurrency.exceptions import RecordModifiedError


@pytest.mark.xfail("django.VERSION[:2] == (1, 10)", strict=True)
# @pytest.mark.xfail(django.VERSION[:2] == (1, 10), reason="Django 1.10")
class TestListEditable(AdminTestCase):
TARGET = ListEditableConcurrentModel

Expand Down
Loading

0 comments on commit ff45e55

Please sign in to comment.