Skip to content

Commit

Permalink
added mypy
Browse files Browse the repository at this point in the history
  • Loading branch information
jhnnsrs committed Dec 10, 2023
1 parent eb7b7af commit 24a137c
Show file tree
Hide file tree
Showing 31 changed files with 423 additions and 190 deletions.
40 changes: 36 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,17 @@ pytest-cov = "^4.0.0"
ruff = "^0.0.282"
cryptography = "^41.0.3"
pyjwt = "^2.8.0"
fakts = "^0.3.48"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.mypy]
exclude = ["venv/", "tests/"]
ignore_missing_imports = true


[[tool.pydoc-markdown.loaders]]
type = "python"
search_path = ["rath"]
Expand Down
9 changes: 5 additions & 4 deletions rath/contrib/fakts/links/aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from fakts.fakt import Fakt
from fakts.fakts import Fakts
from rath.links.aiohttp import AIOHttpLink

from rath.operation import Operation

class AioHttpConfig(Fakt):
"""AioHttpConfig
Expand All @@ -24,20 +24,21 @@ class FaktsAIOHttpLink(AIOHttpLink):
"""

fakts: Fakts
endpoint_url: Optional[str]
endpoint_url: Optional[str] # type: ignore

fakts_group: str
""" The fakts group within the fakts context to use for configuration """

_old_fakt: Dict[str, Any] = None
_old_fakt: Optional[Dict[str, Any]] = None

def configure(self, fakt: AioHttpConfig) -> None:
"""Configure the link with the given fakt"""
self.endpoint_url = fakt.endpoint_url

async def aconnect(self, operation):
async def aconnect(self, operation: Operation):
if self.fakts.has_changed(self._old_fakt, self.fakts_group):
self._old_fakt = await self.fakts.aget(self.fakts_group)
assert self._old_fakt is not None, "Fakt should not be None"
self.configure(AioHttpConfig(**self._old_fakt))

return await super().aconnect(operation)
3 changes: 2 additions & 1 deletion rath/contrib/fakts/links/graphql_ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Config:

class FaktsGraphQLWSLink(GraphQLWSLink):
fakts: Fakts
ws_endpoint_url: Optional[str]
ws_endpoint_url: Optional[str] # type: ignore
fakts_group: str = "websocket"

_old_fakt: Dict[str, Any] = {}
Expand All @@ -25,6 +25,7 @@ def configure(self, fakt: WebsocketHttpConfig) -> None:
async def aconnect(self, operation: Any):
if self.fakts.has_changed(self._old_fakt, self.fakts_group):
self._old_fakt = await self.fakts.aget(self.fakts_group)
assert self._old_fakt is not None, "Fakt should not be None"
self.configure(WebsocketHttpConfig(**self._old_fakt))

return await super().aconnect(operation)
4 changes: 2 additions & 2 deletions rath/contrib/fakts/links/httpx.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ class Config:


class FaktsHttpXLink(HttpxLink):
endpoint_url: Optional[str]
endpoint_url: Optional[str] # type: ignore
fakts_group: str
fakt: Optional[FaltsHttpXConfig]
fakts: Fakts

_old_fakt: Dict[str, Any] = None
_old_fakt: Optional[Dict[str, Any]] = None

def configure(self, fakt: FaltsHttpXConfig) -> None:
self.endpoint_url = fakt.endpoint_url
Expand Down
4 changes: 2 additions & 2 deletions rath/contrib/fakts/links/subscription_transport_ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ class Config:

class FaktsWebsocketLink(SubscriptionTransportWsLink):
fakts: Fakts
ws_endpoint_url: Optional[str]
ws_endpoint_url: Optional[str] # type: ignore
fakts_group: str = "websocket"

_old_fakt: Dict[str, Any] = {}
_old_fakt: Optional[Dict[str, Any]] = None

def configure(self, fakt: WebsocketHttpConfig) -> None:
self.ws_endpoint_url = fakt.ws_endpoint_url
Expand Down
7 changes: 7 additions & 0 deletions rath/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,10 @@ class NotEnteredError(RathException):
to protected methods is attempted."""

pass


class NotComposedError(RathException):
"""NotComposedError is raised when the Rath link chain is not composed and
the next link is accessed."""

pass
8 changes: 4 additions & 4 deletions rath/links/aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
from http import HTTPStatus
import json
from ssl import SSLContext
from typing import Any, Dict, List, Type

from typing import Any, Dict, List, Type, AsyncIterator
from rath.links.types import Payload
import aiohttp
from graphql import OperationType
from pydantic import Field
Expand Down Expand Up @@ -66,11 +66,11 @@ async def aconnect(self, operation: Operation):
async def __aexit__(self, *args, **kwargs) -> None:
pass

async def aexecute(self, operation: Operation) -> GraphQLResult:
async def aexecute(self, operation: Operation) -> AsyncIterator[GraphQLResult]:
if not self._connected:
await self.aconnect(operation)

payload = {"query": operation.document}
payload: Payload = {"query": operation.document}

if operation.node.operation == OperationType.SUBSCRIPTION:
raise NotImplementedError(
Expand Down
4 changes: 4 additions & 0 deletions rath/links/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from rath.links.base import ContinuationLink
from rath.operation import GraphQLResult, Operation
from rath.links.errors import AuthenticationError
from rath.errors import NotComposedError


async def fake_loader():
Expand Down Expand Up @@ -36,6 +37,9 @@ async def arefresh_token(self, operation: Operation):
async def aexecute(
self, operation: Operation, retry=0, **kwargs
) -> AsyncIterator[GraphQLResult]:
if not self.next:
raise NotComposedError("No next link set")

token = await self.aload_token(operation)
operation.context.headers["Authorization"] = f"Bearer {token}"
operation.context.initial_payload["token"] = token
Expand Down
15 changes: 9 additions & 6 deletions rath/links/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import AsyncIterator, Optional
from koil.composition import KoiledModel
from rath.operation import GraphQLResult, Operation

from rath.errors import NotComposedError

class Link(KoiledModel):
"""A Link is a class that can be used to send operations to a GraphQL API.
Expand All @@ -14,7 +14,7 @@ class Link(KoiledModel):
"""

async def aconnect(self):
async def aconnect(self, operation: Operation):
"""A coroutine that is called when the link is connected."""
pass

Expand All @@ -28,7 +28,7 @@ async def __aenter__(self) -> None:
async def __aexit__(self, *args, **kwargs) -> None:
pass

def aexecute(self, operation: Operation, **kwargs) -> AsyncIterator[GraphQLResult]:
def aexecute(self, operation: Operation) -> AsyncIterator[GraphQLResult]:
"""A coroutine that takes an operation and returns an AsyncIterator
of GraphQLResults. This method should be implemented by subclasses."""
raise NotImplementedError(
Expand Down Expand Up @@ -56,7 +56,7 @@ class AsyncTerminatingLink(TerminatingLink):
TerminatingLink (_type_): _description_
"""

async def aexecute(self, operation: Operation) -> AsyncIterator[GraphQLResult]:
def aexecute(self, operation: Operation) -> AsyncIterator[GraphQLResult]:
raise NotImplementedError("Your Async Transport needs to overwrite this method")


Expand All @@ -71,6 +71,9 @@ class ContinuationLink(Link):
def set_next(self, next: Link):
self.next = next

async def aexecute(self, operation: Operation, **kwargs) -> GraphQLResult:
async for x in self.next.aexecute(operation, **kwargs):
async def aexecute(self, operation: Operation) -> AsyncIterator[GraphQLResult]:
if not self.next:
raise NotComposedError("No next link set")

async for x in self.next.aexecute(operation):
yield x
10 changes: 7 additions & 3 deletions rath/links/compose.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from typing import List
from typing import List, Optional

from pydantic import validator
from rath.links.base import ContinuationLink, Link, TerminatingLink
from rath.operation import Operation

from rath.errors import NotComposedError

class ComposedLink(TerminatingLink):
"""A composed link is a link that is composed of multiple links. The links
Expand Down Expand Up @@ -69,7 +69,7 @@ class TypedComposedLink(TerminatingLink):
automatically composed together.
"""

_firstlink: Link = None
_firstlink: Optional[Link] = None

async def __aenter__(self):
current_link = None
Expand All @@ -93,6 +93,10 @@ async def __aexit__(self, *args, **kwargs):
await link.__aexit__(*args, **kwargs)

async def aexecute(self, operation: Operation, **kwargs):
if not self._firstlink:
raise NotComposedError("Links need to be composed before they can be executed. (Through __aenter__)")


async for result in self._firstlink.aexecute(operation):
yield result

Expand Down
16 changes: 15 additions & 1 deletion rath/links/dictinglink.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ def parse_variables(
variables: Dict,
by_alias: bool = True,
) -> Dict:
"""Parse Variables
Parse vaiables converts any pydantic models in the variables dict to dicts
by calling their .json() method with by_alias=True
Args:
variables (Dict): variables to parse
by_alias (bool, optional): whether to use the alias names. Defaults to True.
Returns:
Dict: the parsed variables
"""


def recurse_extract(obj):
"""
recursively traverse obj, doing a deepcopy, but
Expand Down Expand Up @@ -43,7 +57,7 @@ class DictingLink(ParsingLink):
It traversed the variables dict, and converts any (nested) pydantic models to dicts
by callind their .json() method."""

by_alias = True
by_alias: bool = True
"""Converts pydantic models to dicts by calling their .json() method with by_alias=True"""

async def aparse(self, operation: Operation) -> Operation:
Expand Down
8 changes: 7 additions & 1 deletion rath/links/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,18 @@ def __init__(self, message) -> None:


class TerminatingLinkError(LinkError):
"""Raised when a terminating link is called."""
"""Raised when a terminating link is called.
This is a base class for all terminating link errors."""


class ContinuationLinkError(LinkError):
"""Raised when a continuation link is called an errors.
THis is a base class for all continuation link errors."""
pass


class AuthenticationError(TerminatingLinkError):
"""Signals that the authentication failed."""
pass
Loading

0 comments on commit 24a137c

Please sign in to comment.