Skip to content

Commit

Permalink
Add typing annotations to utils submodule
Browse files Browse the repository at this point in the history
  • Loading branch information
apragacz committed Apr 9, 2021
1 parent edd6b75 commit 0ea5f43
Show file tree
Hide file tree
Showing 16 changed files with 234 additions and 100 deletions.
19 changes: 13 additions & 6 deletions rest_registration/api/views/login.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
from typing import TYPE_CHECKING, Any, Dict

from django.contrib import auth
from django.utils.translation import gettext as _
from rest_framework import serializers
from rest_framework.authentication import SessionAuthentication, TokenAuthentication
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.settings import api_settings

from rest_registration.decorators import (
Expand All @@ -14,12 +18,15 @@
from rest_registration.settings import registration_settings
from rest_registration.utils.responses import get_ok_response

if TYPE_CHECKING:
from django.contrib.auth.base_user import AbstractBaseUser


@api_view_serializer_class_getter(
lambda: registration_settings.LOGIN_SERIALIZER_CLASS)
@api_view(['POST'])
@permission_classes(registration_settings.NOT_AUTHENTICATED_PERMISSION_CLASSES)
def login(request):
def login(request: Request) -> Response:
'''
Logs in the user via given login and password.
'''
Expand All @@ -44,7 +51,7 @@ class LogoutSerializer(serializers.Serializer): # pylint: disable=abstract-meth
@api_view_serializer_class(LogoutSerializer)
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def logout(request):
def logout(request: Request) -> Response:
'''
Logs out the user. returns an error if the user is not
authenticated.
Expand All @@ -67,25 +74,25 @@ def logout(request):
return get_ok_response(_("Logout successful"))


def should_authenticate_session():
def should_authenticate_session() -> bool:
result = registration_settings.LOGIN_AUTHENTICATE_SESSION
if result is None:
result = rest_auth_has_class(SessionAuthentication)
return result


def should_retrieve_token():
def should_retrieve_token() -> bool:
result = registration_settings.LOGIN_RETRIEVE_TOKEN
if result is None:
result = rest_auth_has_class(TokenAuthentication)
return result


def rest_auth_has_class(cls):
def rest_auth_has_class(cls: type) -> bool:
return cls in api_settings.DEFAULT_AUTHENTICATION_CLASSES


def perform_login(request, user):
def perform_login(request: Request, user: 'AbstractBaseUser') -> Dict[str, Any]:
if should_authenticate_session():
auth.login(request, user)

Expand Down
3 changes: 2 additions & 1 deletion rest_registration/api/views/profile.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response

from rest_registration.decorators import api_view_serializer_class_getter
Expand All @@ -10,7 +11,7 @@
lambda: registration_settings.PROFILE_SERIALIZER_CLASS)
@api_view(['GET', 'POST', 'PUT', 'PATCH'])
@permission_classes([IsAuthenticated])
def profile(request):
def profile(request: Request) -> Response:
'''
Get or set user profile.
'''
Expand Down
12 changes: 9 additions & 3 deletions rest_registration/api/views/register_email.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from typing import Any, Dict, Optional

from django.http import Http404
from django.utils.translation import gettext as _
from rest_framework import serializers
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response

from rest_registration import signals
from rest_registration.decorators import (
Expand Down Expand Up @@ -40,7 +44,7 @@ def get_valid_period(self):
lambda: registration_settings.REGISTER_EMAIL_SERIALIZER_CLASS)
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def register_email(request):
def register_email(request: Request) -> Response:
'''
Register new email.
'''
Expand Down Expand Up @@ -101,15 +105,17 @@ class VerifyEmailSerializer(serializers.Serializer): # noqa: E501 pylint: disab
@api_view_serializer_class(VerifyEmailSerializer)
@api_view(['POST'])
@permission_classes(registration_settings.NOT_AUTHENTICATED_PERMISSION_CLASSES)
def verify_email(request):
def verify_email(request: Request) -> Response:
'''
Verify email via signature.
'''
process_verify_email_data(request.data, serializer_context={'request': request})
return get_ok_response(_("Email verified successfully"))


def process_verify_email_data(input_data, serializer_context=None):
def process_verify_email_data(
input_data: Dict[str, Any],
serializer_context: Optional[Dict[str, Any]] = None) -> None:
if serializer_context is None:
serializer_context = {}
if not registration_settings.REGISTER_EMAIL_VERIFICATION_ENABLED:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
root_setting_name='REST_REGISTRATION_VERIFICATION_REDIRECTS')


def settings_changed_handler(*args, **kwargs):
def settings_changed_handler(*args, **kwargs) -> None:
verification_redirects_settings.reset_user_settings()
verification_redirects_settings.reset_attr_cache()

Expand Down
17 changes: 9 additions & 8 deletions rest_registration/contrib/verification_redirects/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,36 @@
from rest_registration.api.views.register import process_verify_registration_data
from rest_registration.api.views.register_email import process_verify_email_data
from rest_registration.api.views.reset_password import process_reset_password_data
from rest_registration.contrib.verification_redirects.settings import \
verification_redirects_settings as vr_settings
from rest_registration.contrib.verification_redirects.settings import (
verification_redirects_settings
)


@require_http_methods(['GET'])
def verify_registration(request):
return _generic_redirect_view(
request, process_verify_registration_data,
['user_id', 'signature', 'timestamp'],
vr_settings.VERIFY_REGISTRATION_SUCCESS_URL,
vr_settings.VERIFY_REGISTRATION_FAILURE_URL)
verification_redirects_settings.VERIFY_REGISTRATION_SUCCESS_URL,
verification_redirects_settings.VERIFY_REGISTRATION_FAILURE_URL)


@require_http_methods(['GET'])
def verify_email(request):
return _generic_redirect_view(
request, process_verify_email_data,
['user_id', 'email', 'signature', 'timestamp'],
vr_settings.VERIFY_EMAIL_SUCCESS_URL,
vr_settings.VERIFY_EMAIL_FAILURE_URL)
verification_redirects_settings.VERIFY_EMAIL_SUCCESS_URL,
verification_redirects_settings.VERIFY_EMAIL_FAILURE_URL)


@require_http_methods(['POST'])
def reset_password(request):
return _generic_redirect_view(
request, process_reset_password_data,
['user_id', 'signature', 'timestamp', 'password'],
vr_settings.RESET_PASSWORD_SUCCESS_URL,
vr_settings.RESET_PASSWORD_FAILURE_URL,
verification_redirects_settings.RESET_PASSWORD_SUCCESS_URL,
verification_redirects_settings.RESET_PASSWORD_FAILURE_URL,
use_post_method=True)


Expand Down
11 changes: 9 additions & 2 deletions rest_registration/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
from typing import Dict, List, Optional, Union

from django.utils.translation import gettext_lazy as _
from rest_framework.exceptions import APIException as _APIException
from rest_framework.settings import api_settings

from rest_registration.settings import registration_settings

DetailType = Union[str, List[str], Dict[str, List[str]]]


class APIException(_APIException):

def __init__(self, detail=None, code=None):
def __init__(
self,
detail: Optional[DetailType] = None,
code: Optional[str] = None) -> None:
if detail is None:
detail = self.default_detail
if code is None:
Expand Down Expand Up @@ -80,7 +87,7 @@ class SignatureInvalid(SignatureError):
default_code = 'signature-invalid'


def _wrap_detail_in_dict(detail):
def _wrap_detail_in_dict(detail: DetailType) -> Dict[str, List[str]]:
if isinstance(detail, list):
return {api_settings.NON_FIELD_ERRORS_KEY: detail}
if isinstance(detail, dict):
Expand Down
30 changes: 20 additions & 10 deletions rest_registration/notifications/email.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
from collections import namedtuple
from typing import TYPE_CHECKING, Any, Dict

from django.core.exceptions import ImproperlyConfigured
from django.core.mail.message import EmailMultiAlternatives
from django.template.exceptions import TemplateDoesNotExist
from django.template.loader import get_template, render_to_string
from django.utils.translation import gettext as _

from rest_registration.notifications.enums import NotificationMethod
from rest_registration.notifications.enums import NotificationMethod, NotificationType
from rest_registration.settings import registration_settings
from rest_registration.utils.common import identity
from rest_registration.utils.users import get_user_email_field_name

if TYPE_CHECKING:
from django.contrib.auth.base_user import AbstractBaseUser

EmailTemplateConfig = namedtuple('EmailTemplateConfig', (
'subject_template_name',
'text_body_template_name',
Expand All @@ -20,8 +24,11 @@


def send_verification_notification(
notification_type, user, data, template_config_data,
custom_user_address=None):
notification_type: NotificationType,
user: 'AbstractBaseUser',
data: Dict[str, Any],
template_config_data: Dict[str, Any],
custom_user_address: Any = None) -> None:
if custom_user_address is None:
user_address = get_user_address(user)
else:
Expand All @@ -32,8 +39,11 @@ def send_verification_notification(


def create_verification_notification(
notification_type, user, user_address, data,
template_config_data):
notification_type: NotificationType,
user: 'AbstractBaseUser',
user_address: Any,
data: Dict[str, Any],
template_config_data: Dict[str, Any]) -> EmailMultiAlternatives:
from_email = registration_settings.VERIFICATION_FROM_EMAIL
reply_to_email = (registration_settings.VERIFICATION_REPLY_TO_EMAIL or
from_email)
Expand Down Expand Up @@ -62,17 +72,17 @@ def create_verification_notification(
return email_msg


def send_notification(notification):
def send_notification(notification: EmailMultiAlternatives) -> None:
notification.send()


def get_user_address(user):
def get_user_address(user: 'AbstractBaseUser') -> str:
email_field_name = get_user_email_field_name()
email = getattr(user, email_field_name)
email = getattr(user, email_field_name) # type: str
return email


def parse_template_config(template_config_data):
def parse_template_config(template_config_data: Dict[str, Any]) -> EmailTemplateConfig:
"""
>>> from tests import doctest_utils
>>> convert_html_to_text = registration_settings.VERIFICATION_EMAIL_HTML_TO_TEXT_CONVERTER # noqa: E501
Expand Down Expand Up @@ -211,7 +221,7 @@ def parse_template_config(template_config_data):
return config


def _validate_template_name_existence(template_name):
def _validate_template_name_existence(template_name: str) -> None:
try:
get_template(template_name)
except TemplateDoesNotExist:
Expand Down
8 changes: 8 additions & 0 deletions rest_registration/utils/common.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
from typing import Callable, Iterable, Optional, Set, TypeVar, Union


class RaiseExceptionType:
pass


_T = TypeVar('_T')
LazyBool = Callable[[], bool]
MaybeLazyBool = Union[bool, LazyBool]


RAISE_EXCEPTION = RaiseExceptionType()


def identity(value: _T) -> _T:
"""
>>> identity(None)
Expand Down
Loading

0 comments on commit 0ea5f43

Please sign in to comment.