Coverage for src/prisma/http_abstract.py: 97%
62 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-08-27 18:25 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2024-08-27 18:25 +0000
1from abc import ABC, abstractmethod
2from typing import (
3 Any,
4 Dict,
5 Type,
6 Union,
7 Generic,
8 TypeVar,
9 Optional,
10 Coroutine,
11 cast,
12)
13from typing_extensions import override
15from httpx import Limits, Headers, Timeout
17from .utils import _NoneType
18from ._types import Method
19from .errors import HTTPClientClosedError
21Session = TypeVar('Session')
22Response = TypeVar('Response')
23ReturnType = TypeVar('ReturnType')
24MaybeCoroutine = Union[Coroutine[Any, Any, ReturnType], ReturnType]
26DEFAULT_CONFIG: Dict[str, Any] = {
27 'limits': Limits(max_connections=1000),
28 'timeout': Timeout(30),
29}
32class AbstractHTTP(ABC, Generic[Session, Response]):
33 session_kwargs: Dict[str, Any]
35 __slots__ = (
36 '_session',
37 'session_kwargs',
38 )
40 # NOTE: ParamSpec wouldn't be valid here:
41 # https://github.com/microsoft/pyright/issues/2667
42 def __init__(self, **kwargs: Any) -> None:
43 # NoneType = not used yet
44 # None = closed
45 # Session = open
46 self._session: Optional[Union[Session, Type[_NoneType]]] = _NoneType
47 self.session_kwargs = {
48 **DEFAULT_CONFIG,
49 **kwargs,
50 }
52 @abstractmethod
53 def download(self, url: str, dest: str) -> MaybeCoroutine[None]: ...
55 @abstractmethod
56 def request(self, method: Method, url: str, **kwargs: Any) -> MaybeCoroutine['AbstractResponse[Response]']: ...
58 @abstractmethod
59 def open(self) -> None: ...
61 @abstractmethod
62 def close(self) -> MaybeCoroutine[None]: ...
64 @property
65 def closed(self) -> bool:
66 return self._session is None
68 @property
69 def session(self) -> Session:
70 session = self._session
71 if session is _NoneType:
72 self.open()
73 return cast(Session, self._session)
75 # TODO: make this not strict, just open a new session
76 if session is None:
77 raise HTTPClientClosedError()
79 return cast(Session, session)
81 @session.setter
82 def session(self, value: Optional[Session]) -> None: # pyright: ignore[reportPropertyTypeMismatch]
83 self._session = value
85 def should_close(self) -> bool:
86 return self._session is not _NoneType and not self.closed
88 @override
89 def __repr__(self) -> str:
90 return str(self)
92 @override
93 def __str__(self) -> str:
94 return f'<HTTP closed={self.closed}>'
97class AbstractResponse(ABC, Generic[Response]):
98 original: Response
100 __slots__ = ('original',)
102 def __init__(self, original: Response) -> None:
103 self.original = original
105 @property
106 @abstractmethod
107 def status(self) -> int: ...
109 @property
110 @abstractmethod
111 def headers(self) -> Headers: ...
113 @abstractmethod
114 def json(self) -> MaybeCoroutine[Any]: ...
116 @abstractmethod
117 def text(self) -> MaybeCoroutine[str]: ...
119 @override
120 def __repr__(self) -> str:
121 return str(self)
123 @override
124 def __str__(self) -> str:
125 return f'<Response wrapped={self.original} >'