Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add djangorestframework-stubs for better typing #1090

Merged
merged 1 commit into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ ignore_errors: True
# Turn off mypy for unit tests
[mypy-*.tests.*]
ignore_errors: True

plugins =
mypy_drf_plugin.main
suricactus marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ repos:
rev: v1.13.0
hooks:
- id: mypy
additional_dependencies: [types-pytz, types-Deprecated, types-PyYAML, types-requests, types-tabulate, types-jsonschema, django-stubs, django-stubs-ext]
additional_dependencies: [types-pytz, types-Deprecated, types-PyYAML, types-requests, types-tabulate, types-jsonschema, django-stubs, django-stubs-ext, djangorestframework-stubs]
pass_filenames: false
entry: bash -c 'mypy -p docker-app -p docker-qgis "$@"' --
17 changes: 9 additions & 8 deletions docker-app/qfieldcloud/core/drf_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.db.models import QuerySet
from django.http import HttpRequest
from rest_framework import filters, viewsets
from rest_framework import filters, views
from rest_framework.request import Request
from typing import Iterable


class QfcOrderingFilter(filters.OrderingFilter):
Expand All @@ -15,7 +16,7 @@ class QfcOrderingFilter(filters.OrderingFilter):
TOKENS_LIST_SEPARATOR = ","
TOKENS_VALUE_SEPARATOR = "="

def _get_query_field(self, fields: list[str], term: str) -> str | None:
def _get_query_field(self, fields: Iterable[str], term: str) -> str | None:
"""Searches a term in a query field list.

The field list elements may start with "-".
Expand Down Expand Up @@ -74,9 +75,9 @@ def _parse_definition(self, definition: str) -> tuple[str, dict[str, str]]:
def remove_invalid_fields(
self,
queryset: QuerySet,
fields: list[str],
view: viewsets.ModelViewSet,
request: HttpRequest,
fields: Iterable[str],
tdrivas marked this conversation as resolved.
Show resolved Hide resolved
view: views.APIView,
request: Request,
) -> list[str]:
"""Process ordering fields by parsing custom field expression.

Expand All @@ -86,8 +87,8 @@ def remove_invalid_fields(

Args:
queryset (QuerySet): Django's ORM queryset of the same model as the one used in view of the `ModelViewSet`
fields (list[str]): ordering fields passed to the HTTP querystring
view (ModelViewSet): DRF view instance
fields (Iterable[str]): ordering fields passed to the HTTP querystring
view (APIView): DRF view instance
request (HttpRequest): DRF request instance
Returns :
list[str]: parsed ordering fields where aliases have been replaced
Expand Down
2 changes: 1 addition & 1 deletion docker-app/qfieldcloud/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class QFieldCloudException(Exception):

code = "unknown_error"
message = "QFieldcloud Unknown Error"
status_code = None
status_code: int | None = None
log_as_error = True

def __init__(self, detail="", status_code=None):
Expand Down
13 changes: 9 additions & 4 deletions docker-app/qfieldcloud/core/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,15 @@ def get_headers(self) -> dict[str, Any]:
Set new header fields to carry pagination controls.
"""
headers = {
"X-Total-Count": self.count,
"X-Total-Count": str(self.count),
}

next_link = self.get_next_link()
next_link: str | None = self.get_next_link()

if next_link:
headers["X-Next-Page"] = next_link

previous_link = self.get_previous_link()
previous_link: str | None = self.get_previous_link()
if previous_link:
headers["X-Previous-Page"] = previous_link

Expand All @@ -49,7 +50,11 @@ def get_paginated_response(self, data) -> response.Response:
"""
Paginate results injecting pagination controls and counter into response headers.
"""
if self.request.GET.get("offset") and not self.request.GET.get("limit"):
if (
self.request is not None
and self.request.GET.get("offset")
and not self.request.GET.get("limit")
):
# slice serialized data to enforce the application wide limit
data = islice(data, settings.QFIELDCLOUD_API_DEFAULT_PAGE_LIMIT)

Expand Down
12 changes: 6 additions & 6 deletions docker-app/qfieldcloud/core/views/teams_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
TeamSerializer,
)

from rest_framework import generics, permissions
from rest_framework import generics, permissions, exceptions
from rest_framework.request import Request
from rest_framework.views import View
from rest_framework.views import APIView

from django.shortcuts import get_object_or_404


class TeamMemberDeleteViewPermissions(permissions.BasePermission):
def has_permission(self, request: Request, view: View) -> bool:
def has_permission(self, request: Request, view: APIView) -> bool:
user = request.user
organization_name = permissions_utils.get_param_from_request(
request, "organization"
Expand All @@ -44,7 +44,7 @@ class TeamMemberPermission(permissions.BasePermission):
Permission class to handle CRUD operations for team members.
"""

def has_permission(self, request: Request, view: View) -> bool:
def has_permission(self, request: Request, view: APIView) -> bool:
organization_name = view.kwargs.get("organization_name")
team_name = view.kwargs.get("team_name")
team_username = Team.format_team_name(organization_name, team_name)
Expand Down Expand Up @@ -78,7 +78,7 @@ class TeamPermission(permissions.BasePermission):
Permission class to handle CRUD operations for teams.
"""

def has_permission(self, request: Request, view: View) -> bool:
def has_permission(self, request: Request, view: APIView) -> bool:
organization_name = view.kwargs.get("organization_name")

try:
Expand Down Expand Up @@ -138,7 +138,7 @@ def perform_update(self, serializer: TeamSerializer) -> None:
team_organization=serializer.instance.team_organization,
username=full_team_name,
).exists():
raise permissions.ValidationError(
raise exceptions.ValidationError(
{"error": "A team with this name already exists."}
)

Expand Down
Loading