parent
c4fe50b38d
commit
9d1ebac86e
3
.gitignore
vendored
3
.gitignore
vendored
@ -31,3 +31,6 @@ tests/file/*
|
|||||||
|
|
||||||
# Plugin development
|
# Plugin development
|
||||||
openslides_*
|
openslides_*
|
||||||
|
|
||||||
|
# Mypy cache for typechecking
|
||||||
|
.mypy_cache
|
||||||
|
@ -21,7 +21,8 @@ install:
|
|||||||
- node_modules/.bin/gulp --production
|
- node_modules/.bin/gulp --production
|
||||||
script:
|
script:
|
||||||
- flake8 openslides tests
|
- flake8 openslides tests
|
||||||
- isort --check-only --recursive openslides tests
|
- if [ "`python --version`" \> "Python 3.5.0" ]; then isort --check-only --recursive openslides tests; fi
|
||||||
|
- python -m mypy openslides/
|
||||||
- node_modules/.bin/gulp jshint
|
- node_modules/.bin/gulp jshint
|
||||||
- node_modules/.bin/karma start --browsers PhantomJS tests/karma/karma.conf.js
|
- node_modules/.bin/karma start --browsers PhantomJS tests/karma/karma.conf.js
|
||||||
|
|
||||||
|
@ -399,7 +399,9 @@ class AssignmentOption(RESTModelMixin, BaseOption):
|
|||||||
return self.poll.assignment
|
return self.poll.assignment
|
||||||
|
|
||||||
|
|
||||||
class AssignmentPoll(RESTModelMixin, CollectDefaultVotesMixin,
|
# TODO: remove the type-ignoring in the next line, after this is solved:
|
||||||
|
# https://github.com/python/mypy/issues/3855
|
||||||
|
class AssignmentPoll(RESTModelMixin, CollectDefaultVotesMixin, # type: ignore
|
||||||
PublishPollMixin, BasePoll):
|
PublishPollMixin, BasePoll):
|
||||||
option_class = AssignmentOption
|
option_class = AssignmentOption
|
||||||
|
|
||||||
|
@ -994,7 +994,9 @@ class MotionOption(RESTModelMixin, BaseOption):
|
|||||||
return self.poll.motion
|
return self.poll.motion
|
||||||
|
|
||||||
|
|
||||||
class MotionPoll(RESTModelMixin, CollectDefaultVotesMixin, BasePoll):
|
# TODO: remove the type-ignoring in the next line, after this is solved:
|
||||||
|
# https://github.com/python/mypy/issues/3855
|
||||||
|
class MotionPoll(RESTModelMixin, CollectDefaultVotesMixin, BasePoll): # type: ignore
|
||||||
"""The Class to saves the vote result for a motion poll."""
|
"""The Class to saves the vote result for a motion poll."""
|
||||||
|
|
||||||
motion = models.ForeignKey(
|
motion = models.ForeignKey(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import locale
|
import locale
|
||||||
|
from typing import Type # noqa
|
||||||
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db import models
|
from django.db import models
|
||||||
@ -16,7 +17,7 @@ class BaseOption(models.Model):
|
|||||||
which has to be a subclass of BaseVote. Otherwise you have to override the
|
which has to be a subclass of BaseVote. Otherwise you have to override the
|
||||||
get_vote_class method.
|
get_vote_class method.
|
||||||
"""
|
"""
|
||||||
vote_class = None
|
vote_class = None # type: Type[BaseVote]
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
@ -2,10 +2,10 @@ from random import choice
|
|||||||
|
|
||||||
from django.contrib.auth.hashers import make_password
|
from django.contrib.auth.hashers import make_password
|
||||||
from django.contrib.auth.models import Group as DjangoGroup
|
from django.contrib.auth.models import Group as DjangoGroup
|
||||||
|
from django.contrib.auth.models import GroupManager as _GroupManager
|
||||||
from django.contrib.auth.models import (
|
from django.contrib.auth.models import (
|
||||||
AbstractBaseUser,
|
AbstractBaseUser,
|
||||||
BaseUserManager,
|
BaseUserManager,
|
||||||
GroupManager,
|
|
||||||
Permission,
|
Permission,
|
||||||
PermissionsMixin,
|
PermissionsMixin,
|
||||||
)
|
)
|
||||||
@ -229,7 +229,7 @@ class User(RESTModelMixin, PermissionsMixin, AbstractBaseUser):
|
|||||||
raise RuntimeError('Do not use user.has_perm() but use openslides.utils.auth.has_perm')
|
raise RuntimeError('Do not use user.has_perm() but use openslides.utils.auth.has_perm')
|
||||||
|
|
||||||
|
|
||||||
class GroupManager(GroupManager):
|
class GroupManager(_GroupManager):
|
||||||
"""
|
"""
|
||||||
Customized manager that supports our get_full_queryset method.
|
Customized manager that supports our get_full_queryset method.
|
||||||
"""
|
"""
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
|
from typing import Optional, Union
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
|
from django.db.models import Model
|
||||||
|
|
||||||
from .collection import CollectionElement
|
from .collection import CollectionElement
|
||||||
|
|
||||||
|
|
||||||
def has_perm(user, perm):
|
def has_perm(user: Optional[CollectionElement], perm: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Checks that user has a specific permission.
|
Checks that user has a specific permission.
|
||||||
|
|
||||||
@ -34,7 +37,7 @@ def has_perm(user, perm):
|
|||||||
return has_perm
|
return has_perm
|
||||||
|
|
||||||
|
|
||||||
def anonymous_is_enabled():
|
def anonymous_is_enabled() -> bool:
|
||||||
"""
|
"""
|
||||||
Returns True if the anonymous user is enabled in the settings.
|
Returns True if the anonymous user is enabled in the settings.
|
||||||
"""
|
"""
|
||||||
@ -42,7 +45,10 @@ def anonymous_is_enabled():
|
|||||||
.get_full_data()['value'])
|
.get_full_data()['value'])
|
||||||
|
|
||||||
|
|
||||||
def user_to_collection_user(user):
|
AnyUser = Union[Model, CollectionElement, int, AnonymousUser, None]
|
||||||
|
|
||||||
|
|
||||||
|
def user_to_collection_user(user: AnyUser) -> Optional[CollectionElement]:
|
||||||
"""
|
"""
|
||||||
Takes an object, that represents a user and converts it to a CollectionElement
|
Takes an object, that represents a user and converts it to a CollectionElement
|
||||||
or to None, if it is an anonymous user.
|
or to None, if it is an anonymous user.
|
||||||
|
@ -261,6 +261,6 @@ def get_redis_connection():
|
|||||||
|
|
||||||
|
|
||||||
if use_redis_cache():
|
if use_redis_cache():
|
||||||
websocket_user_cache = RedisWebsocketUserCache()
|
websocket_user_cache = RedisWebsocketUserCache() # type: BaseWebsocketUserCache
|
||||||
else:
|
else:
|
||||||
websocket_user_cache = DjangoCacheWebsocketUserCache()
|
websocket_user_cache = DjangoCacheWebsocketUserCache()
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from typing import Mapping # noqa
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|
||||||
@ -507,7 +509,7 @@ class Collection:
|
|||||||
cache.set(self.get_cache_key(), ids)
|
cache.set(self.get_cache_key(), ids)
|
||||||
|
|
||||||
|
|
||||||
_models_to_collection_string = {}
|
_models_to_collection_string = {} # type: Mapping[str, object]
|
||||||
|
|
||||||
|
|
||||||
def get_model_from_collection_string(collection_string):
|
def get_model_from_collection_string(collection_string):
|
||||||
|
@ -71,7 +71,7 @@ class SignalConnectMetaClass(type):
|
|||||||
return new_class
|
return new_class
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod # type: ignore
|
||||||
def get_all(cls, request=None):
|
def get_all(cls, request=None):
|
||||||
"""
|
"""
|
||||||
Collects all objects of the class created by the SignalConnectMetaClass
|
Collects all objects of the class created by the SignalConnectMetaClass
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
from .access_permissions import BaseAccessPermissions # noqa
|
||||||
from .utils import convert_camel_case_to_pseudo_snake_case
|
from .utils import convert_camel_case_to_pseudo_snake_case
|
||||||
|
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ class RESTModelMixin:
|
|||||||
Mixin for Django models which are used in our REST API.
|
Mixin for Django models which are used in our REST API.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
access_permissions = None
|
access_permissions = None # type: BaseAccessPermissions
|
||||||
|
|
||||||
def get_root_rest_element(self):
|
def get_root_rest_element(self):
|
||||||
"""
|
"""
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from typing import Optional # noqa
|
||||||
|
|
||||||
from django.dispatch import Signal
|
from django.dispatch import Signal
|
||||||
|
|
||||||
from .collection import CollectionElement
|
from .collection import CollectionElement
|
||||||
@ -14,7 +16,7 @@ class ProjectorElement(object, metaclass=SignalConnectMetaClass):
|
|||||||
magic.
|
magic.
|
||||||
"""
|
"""
|
||||||
signal = Signal()
|
signal = Signal()
|
||||||
name = None
|
name = None # type: Optional[str]
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
from typing import Optional # noqa
|
||||||
|
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from rest_framework import status # noqa
|
from rest_framework import status # noqa
|
||||||
@ -30,6 +31,7 @@ from rest_framework.viewsets import GenericViewSet as _GenericViewSet # noqa
|
|||||||
from rest_framework.viewsets import ModelViewSet as _ModelViewSet # noqa
|
from rest_framework.viewsets import ModelViewSet as _ModelViewSet # noqa
|
||||||
from rest_framework.viewsets import ViewSet as _ViewSet # noqa
|
from rest_framework.viewsets import ViewSet as _ViewSet # noqa
|
||||||
|
|
||||||
|
from .access_permissions import BaseAccessPermissions # noqa
|
||||||
from .auth import user_to_collection_user
|
from .auth import user_to_collection_user
|
||||||
from .collection import Collection, CollectionElement
|
from .collection import Collection, CollectionElement
|
||||||
|
|
||||||
@ -102,7 +104,7 @@ class PermissionMixin:
|
|||||||
Also connects container to handle access permissions for model and
|
Also connects container to handle access permissions for model and
|
||||||
viewset.
|
viewset.
|
||||||
"""
|
"""
|
||||||
access_permissions = None
|
access_permissions = None # type: Optional[BaseAccessPermissions]
|
||||||
|
|
||||||
def get_permissions(self):
|
def get_permissions(self):
|
||||||
"""
|
"""
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from typing import List # noqa
|
||||||
|
|
||||||
from django.views import generic as django_views
|
from django.views import generic as django_views
|
||||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
@ -22,7 +24,7 @@ class APIView(_APIView):
|
|||||||
The Django Rest framework APIView with improvements for OpenSlides.
|
The Django Rest framework APIView with improvements for OpenSlides.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
http_method_names = []
|
http_method_names = [] # type: List[str]
|
||||||
"""
|
"""
|
||||||
The allowed actions have to be explicitly defined.
|
The allowed actions have to be explicitly defined.
|
||||||
|
|
||||||
|
@ -5,3 +5,4 @@
|
|||||||
coverage
|
coverage
|
||||||
flake8
|
flake8
|
||||||
isort==4.2.5
|
isort==4.2.5
|
||||||
|
mypy
|
||||||
|
@ -13,3 +13,10 @@ max_line_length = 150
|
|||||||
[isort]
|
[isort]
|
||||||
include_trailing_comma = true
|
include_trailing_comma = true
|
||||||
multi_line_output = 3
|
multi_line_output = 3
|
||||||
|
|
||||||
|
[mypy]
|
||||||
|
ignore_missing_imports = true
|
||||||
|
strict_optional = true
|
||||||
|
|
||||||
|
[mypy-openslides.utils.auth]
|
||||||
|
disallow_any = unannotated
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from openslides.core.config import ConfigVariable, config
|
from openslides.core.config import ConfigVariable
|
||||||
from openslides.core.exceptions import ConfigNotFound
|
|
||||||
|
|
||||||
|
|
||||||
class TestConfigVariable(TestCase):
|
class TestConfigVariable(TestCase):
|
||||||
@ -23,11 +22,3 @@ class TestConfigVariable(TestCase):
|
|||||||
'test_default_value',
|
'test_default_value',
|
||||||
"The value of config_variable.data['default_value'] should be the same "
|
"The value of config_variable.data['default_value'] should be the same "
|
||||||
"as set as second argument of ConfigVariable()")
|
"as set as second argument of ConfigVariable()")
|
||||||
|
|
||||||
|
|
||||||
class TestConfigHandler(TestCase):
|
|
||||||
def test_get_not_found(self):
|
|
||||||
self.assertRaises(
|
|
||||||
ConfigNotFound,
|
|
||||||
config.__getitem__,
|
|
||||||
'key_leehah4Sho4ee7aCohbn')
|
|
||||||
|
Loading…
Reference in New Issue
Block a user