# Path: src/bananas/drf/utils.py
# class HeaderError(ValueError):
#     code = "invalid_header"
# 
#     def as_api_error(self) -> BadRequest:
#         return BadRequest(detail=str(self), code=self.code)
# 
# def parse_header_datetime(request: Request, header: str) -> datetime.datetime:
#     try:
#         value = request.headers[header]
#     except KeyError:
#         raise MissingHeader(header)
#     try:
#         return datetime.datetime.fromtimestamp(
#             parse_http_date(value), tz=datetime.timezone.utc
#         )
#     except ValueError as e:
#         raise InvalidHeader(header) from e
# 
# def parse_header_etags(request: Request, header: str) -> FrozenSet[str]:
#     try:
#         parts = request.headers[header].split(",")
#     except KeyError:
#         raise MissingHeader(header)
#     tags = frozenset(clean_tags(parts))
#     if not tags:
#         raise InvalidHeader(header)
#     return tags


import abc
import datetime
import operator
from functools import wraps
from typing import (
    Any,
    Callable,
    FrozenSet,
    Generic,
    List,
    NoReturn,
    Optional,
    TypeVar,
    cast,
)
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db.models import Model, QuerySet
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework.mixins import UpdateModelMixin
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import BaseSerializer, ModelSerializer
from rest_framework.viewsets import GenericViewSet
from typing_extensions import Final, Protocol, final
from bananas.admin.api.schemas.yasg import BananasSwaggerSchema
from bananas.models import TimeStampedModel
from . import errors
from .utils import HeaderError, parse_header_datetime, parse_header_etags
        ...

    # django-restframework uses an "advanced self-type" on self in
    # perform_update() which subtly breaks subclassing. We try to remedy this by
    # implementing get_queryset() so that we fulfill the self-type in the
    # overridden method.
    # See https://github.com/typeddjango/djangorestframework-stubs/issues/132
    def get_queryset(self: UsesQuerySet[_MT_co]) -> "QuerySet[_MT_co]":
        return cast(UsesQuerySet[_MT_co], super()).get_queryset()

    def perform_update(self, serializer: BaseSerializer) -> None:
        # mypy's advanced self types don't work with super calls so we use an assertion
        # here instead.
        assert isinstance(self, GenericViewSet)
        assert isinstance(serializer, ModelSerializer)
        self.fence.validate(self.request, serializer.instance)
        super().perform_update(serializer)

    @swagger_auto_schema(auto_schema=FenceAwareSwaggerAutoSchema)
    def update(self, request: Request, *args: Any, **kwargs: Any) -> Response:
        return super().update(request, *args, **kwargs)

    @swagger_auto_schema(auto_schema=FenceAwareSwaggerAutoSchema)
    def partial_update(self, request: Request, *args: Any, **kwargs: Any) -> Response:
        return super().partial_update(request, *args, **kwargs)


def header_date_parser(header: str) -> Callable[[Request], datetime.datetime]:
    def parse(request: Request) -> datetime.datetime:
        try:

# Path: src/bananas/drf/utils.py
# class HeaderError(ValueError):
#     code = "invalid_header"
# 
#     def as_api_error(self) -> BadRequest:
#         return BadRequest(detail=str(self), code=self.code)
# 
# def parse_header_datetime(request: Request, header: str) -> datetime.datetime:
#     try:
#         value = request.headers[header]
#     except KeyError:
#         raise MissingHeader(header)
#     try:
#         return datetime.datetime.fromtimestamp(
#             parse_http_date(value), tz=datetime.timezone.utc
#         )
#     except ValueError as e:
#         raise InvalidHeader(header) from e
# 
# def parse_header_etags(request: Request, header: str) -> FrozenSet[str]:
#     try:
#         parts = request.headers[header].split(",")
#     except KeyError:
#         raise MissingHeader(header)
#     tags = frozenset(clean_tags(parts))
#     if not tags:
#         raise InvalidHeader(header)
#     return tags


# Path: src/bananas/drf/fencing.py
import abc
import datetime
import operator
from functools import wraps
from typing import (
    Any,
    Callable,
    FrozenSet,
    Generic,
    List,
    NoReturn,
    Optional,
    TypeVar,
    cast,
)
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db.models import Model, QuerySet
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework.mixins import UpdateModelMixin
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import BaseSerializer, ModelSerializer
from rest_framework.viewsets import GenericViewSet
from typing_extensions import Final, Protocol, final
from bananas.admin.api.schemas.yasg import BananasSwaggerSchema
from bananas.models import TimeStampedModel
from . import errors
from .utils import HeaderError, parse_header_datetime, parse_header_etags

        ...

    # django-restframework uses an "advanced self-type" on self in
    # perform_update() which subtly breaks subclassing. We try to remedy this by
    # implementing get_queryset() so that we fulfill the self-type in the
    # overridden method.
    # See https://github.com/typeddjango/djangorestframework-stubs/issues/132
    def get_queryset(self: UsesQuerySet[_MT_co]) -> "QuerySet[_MT_co]":
        return cast(UsesQuerySet[_MT_co], super()).get_queryset()

    def perform_update(self, serializer: BaseSerializer) -> None:
        # mypy's advanced self types don't work with super calls so we use an assertion
        # here instead.
        assert isinstance(self, GenericViewSet)
        assert isinstance(serializer, ModelSerializer)
        self.fence.validate(self.request, serializer.instance)
        super().perform_update(serializer)

    @swagger_auto_schema(auto_schema=FenceAwareSwaggerAutoSchema)
    def update(self, request: Request, *args: Any, **kwargs: Any) -> Response:
        return super().update(request, *args, **kwargs)

    @swagger_auto_schema(auto_schema=FenceAwareSwaggerAutoSchema)
    def partial_update(self, request: Request, *args: Any, **kwargs: Any) -> Response:
        return super().partial_update(request, *args, **kwargs)


def header_date_parser(header: str) -> Callable[[Request], datetime.datetime]:
    def parse(request: Request) -> datetime.datetime:
        try:

            return parse_header_datetime(request, header)