# -*- coding: utf -*- """Decorators that are used in Nucleus API""" __all__ = ['basic_auth_required', 'token_auth_required'] import functools import typing import requests from .exceptions import LoginRequiredException if typing.TYPE_CHECKING: from .api import _NucleusAPI NucleusFunc = typing.TypeVar('NucleusFunc', bound=typing.Callable[..., typing.Any]) def basic_auth_required(func: NucleusFunc) -> NucleusFunc: """ Decorator that catches 401 and 403 requests.HTTPError and raises LoginRequiredException. :returns: Wrapped function. :raises LoginRequiredException: Exception that has to be handled and trigger basic authorization process. """ @functools.wraps(func) def check_auth(self: '_NucleusAPI', *args: typing.Any, **kwargs: typing.Any) -> typing.Any: try: return func(self, *args, **kwargs) except requests.HTTPError as err: response = err.response if response is None or response.status_code in (401, 403): raise LoginRequiredException( 'Client Error: Required basic auth using username/password.', response=response, ) from err raise return typing.cast(NucleusFunc, check_auth) def token_auth_required(func: NucleusFunc) -> NucleusFunc: """ Decorator that catches 401 and 403 requests.HTTPError and raises LoginRequiredException. :returns: Wrapped function. :raises requests.HTTPError: Raise any requests.HTTPError if status_code not in [401, 403]. """ @functools.wraps(func) def check_auth(self: '_NucleusAPI', *args: typing.Any, **kwargs: typing.Any) -> typing.Any: self.refresh_token_if_required() try: return func(self, *args, **kwargs) except requests.HTTPError as err: response: requests.Response = err.response if response.status_code in (401, 403): self.refresh_token() return func(self, *args, **kwargs) raise return typing.cast(NucleusFunc, check_auth)