diff --git a/.travis.yml b/.travis.yml
index 81e94e68b..74feb4ac1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,7 +6,6 @@ cache:
- $HOME/virtualenv/python$TRAVIS_PYTHON_VERSION/lib/python$TRAVIS_PYTHON_VERSION/site-packages/
- $HOME/virtualenv/python$TRAVIS_PYTHON_VERSION/bin/
python:
- - "3.3"
- "3.4"
- "3.5"
install:
diff --git a/CHANGELOG b/CHANGELOG
index d22c56df9..2a4c17f23 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -29,7 +29,7 @@ Other:
- New OpenSlides logo.
- New design for web interface.
- Added multiple countdown support.
-- Changed supported Python version to >= 3.3.
+- Changed supported Python version to >= 3.4.
- Used Django 1.7 as lowest requirement.
- Added Django's application configuration. Refactored loading of signals
and projector elements/slides.
@@ -56,6 +56,7 @@ Other:
- Used setup.cfg for development tools.
- Removed code for Windows portable version with GUI. Used new repository for
this.
+- Django 1.9 is supported
Translations:
- Added DE and FR translations.
diff --git a/README.rst b/README.rst
index bc46f1f51..0fe08a848 100644
--- a/README.rst
+++ b/README.rst
@@ -26,7 +26,7 @@ Installation on GNU/Linux or Mac OS X
1. Check requirements
- Make sure that you have installed Python Programming Language 3 (>= 3.3)
+ Make sure that you have installed Python Programming Language 3 (>= 3.4)
on your system. You will also need the Python development headers.
For example for Ubuntu run::
@@ -73,7 +73,7 @@ portable version you should observe the following install steps.*
1. Check requirements
- Make sure that you have installed Python Programming Language 3 (>= 3.3)
+ Make sure that you have installed Python Programming Language 3 (>= 3.4)
and Setuptools on your system.
a. Download and run the latest `Python 3.4 32-bit MSI installer
@@ -170,7 +170,7 @@ Installation and start of the development version
1. Check requirements
- You need to have `Python 3 (>=3.3) `_, `Node.js
+ You need to have `Python 3 (>=3.4) `_, `Node.js
(>=0.10) `_ and `Git `_
installed. See also step 1 in the correspondent instruction in section
III.
diff --git a/openslides/agenda/migrations/0006_auto_20160109_1145.py b/openslides/agenda/migrations/0006_auto_20160109_1145.py
new file mode 100644
index 000000000..e8627c51d
--- /dev/null
+++ b/openslides/agenda/migrations/0006_auto_20160109_1145.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.1 on 2016-01-09 11:45
+from __future__ import unicode_literals
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('agenda', '0005_auto_20151210_0016'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='item',
+ name='content_type',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='contenttypes.ContentType'),
+ ),
+ migrations.AlterField(
+ model_name='item',
+ name='parent',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='children', to='agenda.Item'),
+ ),
+ ]
diff --git a/openslides/agenda/models.py b/openslides/agenda/models.py
index 047e9cfb4..4bd241d62 100644
--- a/openslides/agenda/models.py
+++ b/openslides/agenda/models.py
@@ -190,7 +190,12 @@ class Item(RESTModelMixin, models.Model):
The intended duration for the topic.
"""
- parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
+ parent = models.ForeignKey(
+ 'self',
+ on_delete=models.SET_NULL,
+ null=True,
+ blank=True,
+ related_name='children')
"""
The parent item in the agenda tree.
"""
@@ -200,7 +205,11 @@ class Item(RESTModelMixin, models.Model):
Weight to sort the item in the agenda.
"""
- content_type = models.ForeignKey(ContentType, null=True, blank=True)
+ content_type = models.ForeignKey(
+ ContentType,
+ on_delete=models.SET_NULL,
+ null=True,
+ blank=True)
"""
Field for generic relation to a related object. Type of the object.
"""
@@ -318,12 +327,17 @@ class Speaker(RESTModelMixin, models.Model):
objects = SpeakerManager()
- user = models.ForeignKey(settings.AUTH_USER_MODEL)
+ user = models.ForeignKey(
+ settings.AUTH_USER_MODEL,
+ on_delete=models.CASCADE)
"""
ForeinKey to the user who speaks.
"""
- item = models.ForeignKey(Item, related_name='speakers')
+ item = models.ForeignKey(
+ Item,
+ on_delete=models.CASCADE,
+ related_name='speakers')
"""
ForeinKey to the agenda item to which the user want to speak.
"""
diff --git a/openslides/agenda/urls.py b/openslides/agenda/urls.py
index 0167c21a9..954255738 100644
--- a/openslides/agenda/urls.py
+++ b/openslides/agenda/urls.py
@@ -1,10 +1,9 @@
-from django.conf.urls import patterns, url
+from django.conf.urls import url
from . import views
-urlpatterns = patterns(
- '',
+urlpatterns = [
url(r'^print/$',
views.AgendaPDF.as_view(),
name='agenda_pdf'),
-)
+]
diff --git a/openslides/agenda/views.py b/openslides/agenda/views.py
index b71c5d44f..3eaed36a2 100644
--- a/openslides/agenda/views.py
+++ b/openslides/agenda/views.py
@@ -1,4 +1,4 @@
-from cgi import escape
+from html import escape
from django.contrib.auth import get_user_model
from django.db import transaction
diff --git a/openslides/assignments/models.py b/openslides/assignments/models.py
index 96d8f138b..2131124ea 100644
--- a/openslides/assignments/models.py
+++ b/openslides/assignments/models.py
@@ -1,7 +1,8 @@
+from collections import OrderedDict
+
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.db import models
-from django.utils.datastructures import SortedDict
from django.utils.translation import ugettext_lazy, ugettext_noop
from openslides.agenda.models import Item, Speaker
@@ -34,9 +35,11 @@ class AssignmentRelatedUser(RESTModelMixin, models.Model):
assignment = models.ForeignKey(
'Assignment',
- db_index=True,
+ on_delete=models.CASCADE,
related_name='assignment_related_users')
- user = models.ForeignKey(settings.AUTH_USER_MODEL, db_index=True)
+ user = models.ForeignKey(
+ settings.AUTH_USER_MODEL,
+ on_delete=models.CASCADE)
status = models.IntegerField(
choices=STATUSES,
default=STATUS_CANDIDATE)
@@ -272,7 +275,7 @@ class Assignment(RESTModelMixin, models.Model):
Returns a table represented as a list with all candidates from all
related polls and their vote results.
"""
- vote_results_dict = SortedDict()
+ vote_results_dict = OrderedDict()
polls = self.polls.all()
if only_published:
@@ -331,7 +334,10 @@ class Assignment(RESTModelMixin, models.Model):
class AssignmentVote(RESTModelMixin, BaseVote):
- option = models.ForeignKey('AssignmentOption', related_name='votes')
+ option = models.ForeignKey(
+ 'AssignmentOption',
+ on_delete=models.CASCADE,
+ related_name='votes')
class Meta:
default_permissions = ()
@@ -344,8 +350,13 @@ class AssignmentVote(RESTModelMixin, BaseVote):
class AssignmentOption(RESTModelMixin, BaseOption):
- poll = models.ForeignKey('AssignmentPoll', related_name='options')
- candidate = models.ForeignKey(settings.AUTH_USER_MODEL)
+ poll = models.ForeignKey(
+ 'AssignmentPoll',
+ on_delete=models.CASCADE,
+ related_name='options')
+ candidate = models.ForeignKey(
+ settings.AUTH_USER_MODEL,
+ on_delete=models.CASCADE)
vote_class = AssignmentVote
class Meta:
@@ -366,7 +377,10 @@ class AssignmentPoll(RESTModelMixin, CollectDefaultVotesMixin,
slide_callback_name = 'assignmentpoll'
option_class = AssignmentOption
- assignment = models.ForeignKey(Assignment, related_name='polls')
+ assignment = models.ForeignKey(
+ Assignment,
+ on_delete=models.CASCADE,
+ related_name='polls')
yesnoabstain = models.BooleanField(default=False)
description = models.CharField(
max_length=79,
diff --git a/openslides/assignments/urls.py b/openslides/assignments/urls.py
index ff5f8d511..1352510f5 100644
--- a/openslides/assignments/urls.py
+++ b/openslides/assignments/urls.py
@@ -1,9 +1,8 @@
-from django.conf.urls import patterns, url
+from django.conf.urls import url
from . import views
-urlpatterns = patterns(
- '',
+urlpatterns = [
url(r'^print/$',
views.AssignmentPDF.as_view(),
name='assignments_pdf'),
@@ -15,4 +14,4 @@ urlpatterns = patterns(
url(r'^poll/(?P\d+)/print/$',
views.AssignmentPollPDF.as_view(),
name='assignmentpoll_pdf'),
-)
+]
diff --git a/openslides/assignments/views.py b/openslides/assignments/views.py
index 3d7afe639..f0c45c325 100644
--- a/openslides/assignments/views.py
+++ b/openslides/assignments/views.py
@@ -1,4 +1,4 @@
-from cgi import escape
+from html import escape
from django.conf import settings
from django.contrib.auth import get_user_model
diff --git a/openslides/core/management/commands/runserver.py b/openslides/core/management/commands/runserver.py
index 6760426e7..6d21cab06 100644
--- a/openslides/core/management/commands/runserver.py
+++ b/openslides/core/management/commands/runserver.py
@@ -1,12 +1,13 @@
import errno
+import os
import socket
import sys
from datetime import datetime
-from django.core.exceptions import ImproperlyConfigured
+from django.conf import settings
from django.core.management.commands.runserver import Command as _Command
-from django.utils import translation
-from django.utils.encoding import force_text
+from django.utils import six
+from django.utils.encoding import force_text, get_system_encoding
from openslides.utils.autoupdate import run_tornado
@@ -17,40 +18,40 @@ class Command(_Command):
Only the line to run tornado has changed from the django default
implementation.
+
+ The Code is from django 1.9
"""
# TODO: do not start tornado when the settings says so
def inner_run(self, *args, **options):
- from django.conf import settings
- # From the base class:
- self.stdout.write("Performing system checks...\n\n")
- self.validate(display_num_errors=True)
-
- try:
- self.check_migrations()
- except ImproperlyConfigured:
- pass
-
- now = datetime.now().strftime('%B %d, %Y - %X')
+ # If an exception was silenced in ManagementUtility.execute in order
+ # to be raised in the child process, raise it now.
+ # OPENSLIDES: We do not use the django autoreload command
+ # autoreload.raise_last_exception()
+ # OPENSLIDES: This line is not needed by tornado
+ # threading = options.get('use_threading')
shutdown_message = options.get('shutdown_message', '')
quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C'
+ self.stdout.write("Performing system checks...\n\n")
+ self.check(display_num_errors=True)
+ self.check_migrations()
+ now = datetime.now().strftime('%B %d, %Y - %X')
+ if six.PY2:
+ now = now.decode(get_system_encoding())
+ self.stdout.write(now)
self.stdout.write((
- "%(started_at)s\n"
"Django version %(version)s, using settings %(settings)r\n"
"Starting development server at http://%(addr)s:%(port)s/\n"
"Quit the server with %(quit_command)s.\n"
- ) % {
- "started_at": now,
+ ) % {
"version": self.get_version(),
"settings": settings.SETTINGS_MODULE,
"addr": '[%s]' % self.addr if self._raw_ipv6 else self.addr,
"port": self.port,
"quit_command": quit_command,
- })
-
- translation.activate(settings.LANGUAGE_CODE)
+ })
try:
handler = self.get_handler(*args, **options)
@@ -64,15 +65,16 @@ class Command(_Command):
ERRORS = {
errno.EACCES: "You don't have permission to access that port.",
errno.EADDRINUSE: "That port is already in use.",
- errno.EADDRNOTAVAIL: "That IP address can't be assigned-to.",
+ errno.EADDRNOTAVAIL: "That IP address can't be assigned to.",
}
try:
error_text = ERRORS[e.errno]
except KeyError:
error_text = force_text(e)
- self.stderr.write("Error: %s" % error_text)
- sys.exit(0)
- except KeyboardInterrupt:
- if shutdown_message:
- self.stdout.write(shutdown_message)
- sys.exit(0)
+ self.stderr.write("Error: %s" % error_text)
+ # Need to use an OS exit because sys.exit doesn't work in a thread
+ os._exit(1)
+ except KeyboardInterrupt:
+ if shutdown_message:
+ self.stdout.write(shutdown_message)
+ sys.exit(0)
diff --git a/openslides/core/models.py b/openslides/core/models.py
index a3577cd64..55683df37 100644
--- a/openslides/core/models.py
+++ b/openslides/core/models.py
@@ -217,6 +217,7 @@ class ChatMessage(RESTModelMixin, models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
+ on_delete=models.CASCADE,
verbose_name=ugettext_lazy('User'))
class Meta:
diff --git a/openslides/global_settings.py b/openslides/global_settings.py
index f79a3a546..f5004597e 100644
--- a/openslides/global_settings.py
+++ b/openslides/global_settings.py
@@ -54,12 +54,6 @@ STATICFILES_FINDERS = (
STATICFILES_DIRS = [
os.path.join(SITE_ROOT, 'static')]
-# List of callables that know how to import templates from various sources.
-TEMPLATE_LOADERS = (
- 'django.template.loaders.filesystem.Loader',
- 'django.template.loaders.app_directories.Loader',
-)
-
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
diff --git a/openslides/mediafiles/migrations/0005_auto_20160109_1145.py b/openslides/mediafiles/migrations/0005_auto_20160109_1145.py
new file mode 100644
index 000000000..cfe476ace
--- /dev/null
+++ b/openslides/mediafiles/migrations/0005_auto_20160109_1145.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.1 on 2016-01-09 11:45
+from __future__ import unicode_literals
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('mediafiles', '0004_auto_20151210_0016'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='mediafile',
+ name='uploader',
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ to=settings.AUTH_USER_MODEL,
+ verbose_name='Uploaded by'),
+ ),
+ ]
diff --git a/openslides/mediafiles/models.py b/openslides/mediafiles/models.py
index 3e518e0d5..f7d479759 100644
--- a/openslides/mediafiles/models.py
+++ b/openslides/mediafiles/models.py
@@ -21,7 +21,12 @@ class Mediafile(RESTModelMixin, models.Model):
title = models.CharField(max_length=255, unique=True, blank=True, verbose_name=ugettext_lazy('Title'))
"""A string representing the title of the file."""
- uploader = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, verbose_name=ugettext_lazy('Uploaded by'))
+ uploader = models.ForeignKey(
+ settings.AUTH_USER_MODEL,
+ on_delete=models.SET_NULL,
+ null=True,
+ blank=True,
+ verbose_name=ugettext_lazy('Uploaded by'))
"""A user – the uploader of a file."""
timestamp = models.DateTimeField(auto_now_add=True)
diff --git a/openslides/mediafiles/templates/search/indexes/mediafiles/mediafile_text.txt b/openslides/mediafiles/templates/search/indexes/mediafiles/mediafile_text.txt
deleted file mode 100644
index 1cebe9df6..000000000
--- a/openslides/mediafiles/templates/search/indexes/mediafiles/mediafile_text.txt
+++ /dev/null
@@ -1 +0,0 @@
-{{ object.title }}
diff --git a/openslides/mediafiles/templates/search/mediafile-results.html b/openslides/mediafiles/templates/search/mediafile-results.html
deleted file mode 100644
index 2871e1e01..000000000
--- a/openslides/mediafiles/templates/search/mediafile-results.html
+++ /dev/null
@@ -1,10 +0,0 @@
-{% load i18n %}
-{% load highlight %}
-
-{% if perms.mediafiles.can_see %}
-
- {{ result.object }}
- {% trans "File" %}
- {% highlight result.text with request.GET.q %}
-
-{% endif %}
diff --git a/openslides/motions/migrations/0006_auto_20160109_1145.py b/openslides/motions/migrations/0006_auto_20160109_1145.py
new file mode 100644
index 000000000..49363b465
--- /dev/null
+++ b/openslides/motions/migrations/0006_auto_20160109_1145.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.1 on 2016-01-09 11:45
+from __future__ import unicode_literals
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('motions', '0005_auto_20151210_0019'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='motion',
+ name='category',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='motions.Category'),
+ ),
+ migrations.AlterField(
+ model_name='motion',
+ name='parent',
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name='amendments',
+ to='motions.Motion'),
+ ),
+ migrations.AlterField(
+ model_name='motion',
+ name='state',
+ field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='motions.State'),
+ ),
+ migrations.AlterField(
+ model_name='motionlog',
+ name='person',
+ field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
+ ),
+ migrations.AlterField(
+ model_name='workflow',
+ name='first_state',
+ field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='motions.State'),
+ ),
+ ]
diff --git a/openslides/motions/models.py b/openslides/motions/models.py
index 831dfb1ae..76fc8d261 100644
--- a/openslides/motions/models.py
+++ b/openslides/motions/models.py
@@ -35,9 +35,11 @@ class Motion(RESTModelMixin, models.Model):
Name of the callback for the slide-system.
"""
- active_version = models.ForeignKey('MotionVersion', null=True,
- related_name="active_version",
- on_delete=models.SET_NULL)
+ active_version = models.ForeignKey(
+ 'MotionVersion',
+ on_delete=models.SET_NULL,
+ null=True,
+ related_name="active_version")
"""
Points to a specific version.
@@ -46,7 +48,10 @@ class Motion(RESTModelMixin, models.Model):
version. Like the sighted versions on Wikipedia.
"""
- state = models.ForeignKey('State', null=True) # TODO: Check whether null=True is necessary.
+ state = models.ForeignKey(
+ 'State',
+ on_delete=models.SET_NULL,
+ null=True) # TODO: Check whether null=True is necessary.
"""
The related state object.
@@ -66,7 +71,11 @@ class Motion(RESTModelMixin, models.Model):
Needed to find the next free motion identifier.
"""
- category = models.ForeignKey('Category', null=True, blank=True)
+ category = models.ForeignKey(
+ 'Category',
+ on_delete=models.SET_NULL,
+ null=True,
+ blank=True)
"""
ForeignKey to one category of motions.
"""
@@ -76,7 +85,12 @@ class Motion(RESTModelMixin, models.Model):
Many to many relation to mediafile objects.
"""
- parent = models.ForeignKey('self', null=True, blank=True, related_name='amendments')
+ parent = models.ForeignKey(
+ 'self',
+ on_delete=models.SET_NULL,
+ null=True,
+ blank=True,
+ related_name='amendments')
"""
Field for amendments to reference to the motion that should be altered.
@@ -557,7 +571,10 @@ class MotionVersion(RESTModelMixin, models.Model):
A MotionVersion object saves some date of the motion.
"""
- motion = models.ForeignKey(Motion, related_name='versions')
+ motion = models.ForeignKey(
+ Motion,
+ on_delete=models.CASCADE,
+ related_name='versions')
"""The motion to which the version belongs."""
version_number = models.PositiveIntegerField(default=1)
@@ -623,7 +640,10 @@ class Category(RESTModelMixin, models.Model):
class MotionLog(RESTModelMixin, models.Model):
"""Save a logmessage for a motion."""
- motion = models.ForeignKey(Motion, related_name='log_messages')
+ motion = models.ForeignKey(
+ Motion,
+ on_delete=models.CASCADE,
+ related_name='log_messages')
"""The motion to witch the object belongs."""
message_list = JSONField()
@@ -631,7 +651,10 @@ class MotionLog(RESTModelMixin, models.Model):
The log message. It should be a list of strings in English.
"""
- person = models.ForeignKey(settings.AUTH_USER_MODEL, null=True)
+ person = models.ForeignKey(
+ settings.AUTH_USER_MODEL,
+ on_delete=models.SET_NULL,
+ null=True)
"""A user object, who created the log message. Optional."""
time = models.DateTimeField(auto_now=True)
@@ -665,7 +688,9 @@ class MotionVote(RESTModelMixin, BaseVote):
There should allways be three MotionVote objects for each poll,
one for 'yes', 'no', and 'abstain'."""
- option = models.ForeignKey('MotionOption')
+ option = models.ForeignKey(
+ 'MotionOption',
+ on_delete=models.CASCADE)
"""The option object, to witch the vote belongs."""
class Meta:
@@ -683,7 +708,9 @@ class MotionOption(RESTModelMixin, BaseOption):
There should be one MotionOption object for each poll."""
- poll = models.ForeignKey('MotionPoll')
+ poll = models.ForeignKey(
+ 'MotionPoll',
+ on_delete=models.CASCADE)
"""The poll object, to witch the object belongs."""
vote_class = MotionVote
@@ -705,7 +732,10 @@ class MotionPoll(RESTModelMixin, CollectDefaultVotesMixin, BasePoll):
slide_callback_name = 'motionpoll'
"""Name of the callback for the slide-system."""
- motion = models.ForeignKey(Motion, related_name='polls')
+ motion = models.ForeignKey(
+ Motion,
+ on_delete=models.CASCADE,
+ related_name='polls')
"""The motion to witch the object belongs."""
option_class = MotionOption
@@ -759,7 +789,10 @@ class State(RESTModelMixin, models.Model):
action_word = models.CharField(max_length=255)
"""An alternative string to be used for a button to switch to this state."""
- workflow = models.ForeignKey('Workflow', related_name='states')
+ workflow = models.ForeignKey(
+ 'Workflow',
+ on_delete=models.CASCADE,
+ related_name='states')
"""A many-to-one relation to a workflow."""
next_states = models.ManyToManyField('self', symmetrical=False)
@@ -850,7 +883,11 @@ class Workflow(RESTModelMixin, models.Model):
name = models.CharField(max_length=255)
"""A string representing the workflow."""
- first_state = models.OneToOneField(State, related_name='+', null=True)
+ first_state = models.OneToOneField(
+ State,
+ on_delete=models.SET_NULL,
+ related_name='+',
+ null=True)
"""A one-to-one relation to a state, the starting point for the workflow."""
class Meta:
diff --git a/openslides/motions/pdf.py b/openslides/motions/pdf.py
index 524ccb12d..173f81621 100644
--- a/openslides/motions/pdf.py
+++ b/openslides/motions/pdf.py
@@ -1,5 +1,5 @@
import random
-from cgi import escape
+from html import escape
from operator import attrgetter
from bs4 import BeautifulSoup
diff --git a/openslides/motions/urls.py b/openslides/motions/urls.py
index 1fbd5a01c..c707d67c2 100644
--- a/openslides/motions/urls.py
+++ b/openslides/motions/urls.py
@@ -1,9 +1,8 @@
-from django.conf.urls import patterns, url
+from django.conf.urls import url
from . import views
-urlpatterns = patterns(
- '',
+urlpatterns = [
url(r'^pdf/$',
views.MotionPDFView.as_view(print_all_motions=True),
name='motions_pdf'),
@@ -11,4 +10,4 @@ urlpatterns = patterns(
url(r'^(?P\d+)/pdf/$',
views.MotionPDFView.as_view(print_all_motions=False),
name='motions_single_pdf'),
-)
+]
diff --git a/openslides/urls.py b/openslides/urls.py
index 2f7f24404..0c48c4e2d 100644
--- a/openslides/urls.py
+++ b/openslides/urls.py
@@ -1,4 +1,4 @@
-from django.conf.urls import include, patterns, url
+from django.conf.urls import include, url
from django.views.generic import RedirectView
from openslides.utils.plugins import get_all_plugin_urlpatterns
@@ -6,8 +6,7 @@ from openslides.utils.rest_api import router
urlpatterns = get_all_plugin_urlpatterns()
-urlpatterns += patterns(
- '',
+urlpatterns += [
url(r'^(?P.*[^/])$', RedirectView.as_view(url='/%(url)s/', permanent=True)),
url(r'^rest/', include(router.urls)),
url(r'^agenda/', include('openslides.agenda.urls')),
@@ -18,4 +17,4 @@ urlpatterns += patterns(
# The urls.py of the core app has to be the last entry. It contains the
# main entry points for OpenSlides' browser clients.
url(r'^', include('openslides.core.urls')),
-)
+]
diff --git a/openslides/users/urls.py b/openslides/users/urls.py
index 1e3742b83..a50683ef0 100644
--- a/openslides/users/urls.py
+++ b/openslides/users/urls.py
@@ -1,10 +1,8 @@
-from django.conf.urls import patterns, url
+from django.conf.urls import url
from . import views
-urlpatterns = patterns(
- '',
-
+urlpatterns = [
# Auth
url(r'^login/$',
views.UserLoginView.as_view(),
@@ -30,4 +28,4 @@ urlpatterns = patterns(
url(r'^passwords/print/$',
views.UsersPasswordsPDF.as_view(),
name='user_passwordspdf'),
-)
+]
diff --git a/openslides/utils/plugins.py b/openslides/utils/plugins.py
index 2d1ae47fe..f2ce9c3c9 100644
--- a/openslides/utils/plugins.py
+++ b/openslides/utils/plugins.py
@@ -1,9 +1,9 @@
import os
import pkgutil
import sys
+from importlib import import_module
from django.conf import settings
-from django.utils.importlib import import_module
from pkg_resources import iter_entry_points
from openslides.utils.main import (
diff --git a/requirements.txt b/requirements.txt
index 86a1d06c0..ea61ad4ad 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,6 +2,6 @@
-r requirements_production.txt
# Requirements for development and tests in alphabetical order
-coverage==4.0a5
+coverage
flake8
isort
diff --git a/requirements_production.txt b/requirements_production.txt
index 24f296921..65abb73fe 100644
--- a/requirements_production.txt
+++ b/requirements_production.txt
@@ -1,12 +1,12 @@
# Requirements for OpenSlides in production in alphabetical order
-Django>=1.7.1,<1.9
-beautifulsoup4>=4.1,<4.5
-djangorestframework>=3.2.0,<3.3.0
+Django>=1.8,<1.10
+beautifulsoup4>=4.4,<4.5
+djangorestframework>=3.2.0,<3.4.0
html5lib>=0.9,<1.0
jsonfield>=0.9.19,<1.1
natsort>=3.2,<4.1
reportlab>=3.0,<3.3
roman>=2.0,<2.1
-setuptools>=2.2,<19.0
+setuptools>=2.2,<20.0
sockjs-tornado>=1.0,<1.1
Whoosh>=2.7.0,<2.8
diff --git a/tests/old/config/test_config.py b/tests/old/config/test_config.py
index 1ca93863b..2ba3b33c8 100644
--- a/tests/old/config/test_config.py
+++ b/tests/old/config/test_config.py
@@ -20,16 +20,23 @@ class HandleConfigTest(TestCase):
self.assertEqual(config['integer_var'], 3)
self.assertEqual(config['choices_var'], '1')
self.assertEqual(config['none_config_var'], None)
- self.assertRaisesMessage(expected_exception=ConfigNotFound,
- expected_message='The config variable unknown_config_var was not found.',
- callable_obj=self.get_config_var, key='unknown_config_var')
+ with self.assertRaisesMessage(
+ ConfigNotFound,
+ 'The config variable unknown_config_var was not found.'):
+ self.get_config_var('unknown_config_var')
def test_get_multiple_config_var_error(self):
- config_signal.connect(set_simple_config_view_multiple_vars, dispatch_uid='set_simple_config_view_multiple_vars_for_testing')
- self.assertRaisesMessage(expected_exception=ConfigError,
- expected_message='Too many values for config variable multiple_config_var found.',
- callable_obj=config.setup_cache)
- config_signal.disconnect(set_simple_config_view_multiple_vars, dispatch_uid='set_simple_config_view_multiple_vars_for_testing')
+ config_signal.connect(
+ set_simple_config_view_multiple_vars,
+ dispatch_uid='set_simple_config_view_multiple_vars_for_testing')
+
+ with self.assertRaisesMessage(
+ ConfigError,
+ 'Too many values for config variable multiple_config_var found.'):
+ config.setup_cache()
+ config_signal.disconnect(
+ set_simple_config_view_multiple_vars,
+ dispatch_uid='set_simple_config_view_multiple_vars_for_testing')
def test_database_queries(self):
"""
@@ -67,13 +74,16 @@ class HandleConfigTest(TestCase):
message.
"""
# TODO: use right exception
- self.assertRaisesMessage(
- Exception,
- 'Change callback dhcnfg34dlg06kdg successfully called.',
- self.set_config_var,
- key='var_with_callback_ghvnfjd5768gdfkwg0hm2',
- value='new_string_kbmbnfhdgibkdjshg452bc')
- self.assertEqual(config['var_with_callback_ghvnfjd5768gdfkwg0hm2'], 'new_string_kbmbnfhdgibkdjshg452bc')
+ with self.assertRaisesMessage(
+ Exception,
+ 'Change callback dhcnfg34dlg06kdg successfully called.'):
+ self.set_config_var(
+ key='var_with_callback_ghvnfjd5768gdfkwg0hm2',
+ value='new_string_kbmbnfhdgibkdjshg452bc')
+
+ self.assertEqual(
+ config['var_with_callback_ghvnfjd5768gdfkwg0hm2'],
+ 'new_string_kbmbnfhdgibkdjshg452bc')
@receiver(config_signal, dispatch_uid='set_grouped_config_view_for_testing')
diff --git a/tests/old/settings.py b/tests/old/settings.py
index b26e2b13d..be58c6922 100644
--- a/tests/old/settings.py
+++ b/tests/old/settings.py
@@ -40,10 +40,6 @@ TIME_ZONE = 'Europe/Berlin'
MEDIA_ROOT = os.path.join(OPENSLIDES_USER_DATA_PATH, '')
-TEMPLATE_DIRS = (
- os.path.join(OPENSLIDES_USER_DATA_PATH, 'templates'),
-)
-
STATICFILES_DIRS.insert(0, os.path.join(OPENSLIDES_USER_DATA_PATH, 'static'))
SEARCH_INDEX = 'ram'
diff --git a/tests/settings.py b/tests/settings.py
index b26e2b13d..be58c6922 100644
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -40,10 +40,6 @@ TIME_ZONE = 'Europe/Berlin'
MEDIA_ROOT = os.path.join(OPENSLIDES_USER_DATA_PATH, '')
-TEMPLATE_DIRS = (
- os.path.join(OPENSLIDES_USER_DATA_PATH, 'templates'),
-)
-
STATICFILES_DIRS.insert(0, os.path.join(OPENSLIDES_USER_DATA_PATH, 'static'))
SEARCH_INDEX = 'ram'