Skip to content

Commit

Permalink
Merge pull request #65 from praw-dev/abstract_classes
Browse files Browse the repository at this point in the history
Abstract classes
  • Loading branch information
LilSpazJoekp authored Nov 26, 2023
2 parents 75ff067 + ddd3cb6 commit 02335cd
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[report]
exclude_lines =
@abstract
if TYPE_CHECKING:
pragma: no cover
11 changes: 8 additions & 3 deletions asyncprawcore/auth.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Provides Authentication and Authorization classes."""
import inspect
import time
from abc import ABC, abstractmethod
from typing import (
TYPE_CHECKING,
Awaitable,
Expand All @@ -21,11 +22,11 @@
from .codes import codes
from .exceptions import InvalidInvocation, OAuthException, ResponseException

if TYPE_CHECKING: # pragma: no cover
if TYPE_CHECKING:
from asyncprawcore.requestor import Requestor


class BaseAuthenticator(object):
class BaseAuthenticator(ABC):
"""Provide the base authenticator object that stores OAuth2 credentials."""

def __init__(
Expand All @@ -46,6 +47,10 @@ def __init__(
self.client_id = client_id
self.redirect_uri = redirect_uri

@abstractmethod
def _auth(self):
pass

async def _post(
self, url: str, success_status: int = codes["ok"], **data
) -> ClientResponse:
Expand Down Expand Up @@ -164,7 +169,7 @@ def _auth(self) -> BasicAuth:
return BasicAuth(self.client_id, "")


class BaseAuthorizer(object):
class BaseAuthorizer(ABC):
"""Superclass for OAuth2 authorization tokens and scopes."""

AUTHENTICATOR_CLASS: Union[Tuple, Type] = BaseAuthenticator
Expand Down
2 changes: 1 addition & 1 deletion asyncprawcore/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
from urllib.parse import urlparse

if TYPE_CHECKING: # pragma: no cover
if TYPE_CHECKING:
from aiohttp import ClientResponse


Expand Down
2 changes: 1 addition & 1 deletion asyncprawcore/rate_limit.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import time
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Mapping, Optional

if TYPE_CHECKING: # pragma: no cover
if TYPE_CHECKING:
from aiohttp import ClientResponse

log = logging.getLogger(__package__)
Expand Down
2 changes: 1 addition & 1 deletion asyncprawcore/requestor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from .const import TIMEOUT, __version__
from .exceptions import InvalidInvocation, RequestException

if TYPE_CHECKING: # pragma: no cover
if TYPE_CHECKING:
from asyncio import AbstractEventLoop

from .sessions import Session
Expand Down
13 changes: 10 additions & 3 deletions asyncprawcore/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import asyncio
import logging
import random
from abc import ABC, abstractmethod
from copy import deepcopy
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
from urllib.parse import urljoin
Expand Down Expand Up @@ -29,7 +30,7 @@
from .rate_limit import RateLimiter
from .util import authorization_error_class

if TYPE_CHECKING: # pragma: no cover
if TYPE_CHECKING:
from io import BufferedReader

from aiofiles.threadpool.binary import AsyncBufferedReader
Expand All @@ -41,7 +42,7 @@
log = logging.getLogger(__package__)


class RetryStrategy(object):
class RetryStrategy(ABC):
"""An abstract class for scheduling request retries.
The strategy controls both the number and frequency of retry attempts.
Expand All @@ -50,6 +51,10 @@ class RetryStrategy(object):
"""

@abstractmethod
def _sleep_seconds(self) -> Optional[float]:
pass

async def sleep(self) -> None:
"""Sleep until we are ready to attempt the request."""
sleep_seconds = self._sleep_seconds()
Expand Down Expand Up @@ -114,7 +119,9 @@ class Session(object):
codes["service_unavailable"]: ServerError,
codes["too_many_requests"]: TooManyRequests,
codes["unauthorized"]: authorization_error_class,
codes["unavailable_for_legal_reasons"]: UnavailableForLegalReasons,
codes[
"unavailable_for_legal_reasons"
]: UnavailableForLegalReasons, # Cloudflare's status (not named in requests)
520: ServerError,
522: ServerError,
}
Expand Down
9 changes: 8 additions & 1 deletion asyncprawcore/util.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
"""Provide utility for the asyncprawcore package."""
from typing import TYPE_CHECKING, Union

from .exceptions import Forbidden, InsufficientScope, InvalidToken

if TYPE_CHECKING:
from aiohttp import ClientResponse

_auth_error_mapping = {
403: Forbidden,
"insufficient_scope": InsufficientScope,
"invalid_token": InvalidToken,
}


def authorization_error_class(response):
def authorization_error_class(
response: "ClientResponse",
) -> Union[InvalidToken, Forbidden, InsufficientScope]:
"""Return an exception instance that maps to the OAuth Error.
:param response: The HTTP response containing a www-authenticate error.
Expand Down

0 comments on commit 02335cd

Please sign in to comment.