ayaka.driver.ayakabot_driver.model
1import json 2import dataclasses 3from enum import Enum 4from http.cookiejar import Cookie, CookieJar 5from typing import ( 6 IO, 7 Any, 8 Dict, 9 List, 10 Tuple, 11 Union, 12 Mapping, 13 Callable, 14 Iterator, 15 Optional, 16 MutableMapping, 17) 18 19from yarl import URL 20from multidict import CIMultiDict 21 22RawURL = Tuple[bytes, bytes, Optional[int], bytes] 23 24SimpleQuery = Union[str, int, float] 25QueryVariable = Union[SimpleQuery, List[SimpleQuery]] 26QueryTypes = Union[ 27 None, str, Mapping[str, QueryVariable], List[Tuple[str, QueryVariable]] 28] 29 30HeaderTypes = Union[ 31 None, 32 CIMultiDict[str], 33 Dict[str, str], 34 List[Tuple[str, str]], 35] 36 37CookieTypes = Union[None, "Cookies", CookieJar, Dict[str, str], List[Tuple[str, str]]] 38 39ContentTypes = Union[str, bytes, None] 40DataTypes = Union[dict, None] 41FileContent = Union[IO[bytes], bytes] 42FileType = Tuple[Optional[str], FileContent, Optional[str]] 43FileTypes = Union[ 44 # file (or bytes) 45 FileContent, 46 # (filename, file (or bytes)) 47 Tuple[Optional[str], FileContent], 48 # (filename, file (or bytes), content_type) 49 FileType, 50] 51FilesTypes = Union[Dict[str, FileTypes], List[Tuple[str, FileTypes]], None] 52 53 54class HTTPVersion(Enum): 55 H10 = "1.0" 56 H11 = "1.1" 57 H2 = "2" 58 59 60class Request: 61 def __init__( 62 self, 63 method: Union[str, bytes], 64 url: Union["URL", str, RawURL], 65 *, 66 params: QueryTypes = None, 67 headers: HeaderTypes = None, 68 cookies: CookieTypes = None, 69 content: ContentTypes = None, 70 data: DataTypes = None, 71 json: Any = None, 72 files: FilesTypes = None, 73 version: Union[str, HTTPVersion] = HTTPVersion.H11, 74 timeout: Optional[float] = None, 75 proxy: Optional[str] = None, 76 ): 77 # method 78 self.method: str = ( 79 method.decode("ascii").upper() 80 if isinstance(method, bytes) 81 else method.upper() 82 ) 83 # http version 84 self.version: HTTPVersion = HTTPVersion(version) 85 # timeout 86 self.timeout: Optional[float] = timeout 87 # proxy 88 self.proxy: Optional[str] = proxy 89 90 # url 91 if isinstance(url, tuple): 92 scheme, host, port, path = url 93 url = URL.build( 94 scheme=scheme.decode("ascii"), 95 host=host.decode("ascii"), 96 port=port, 97 path=path.decode("ascii"), 98 ) 99 else: 100 url = URL(url) 101 102 if params is not None: 103 url = url.update_query(params) 104 self.url: URL = url 105 106 # headers 107 self.headers: CIMultiDict[str] 108 if headers is not None: 109 self.headers = CIMultiDict(headers) 110 else: 111 self.headers = CIMultiDict() 112 113 # cookies 114 self.cookies = Cookies(cookies) 115 116 # body 117 self.content: ContentTypes = content 118 self.data: DataTypes = data 119 self.json: Any = json 120 self.files: Optional[List[Tuple[str, FileType]]] = None 121 if files: 122 self.files = [] 123 files_ = files.items() if isinstance(files, dict) else files 124 for name, file_info in files_: 125 if not isinstance(file_info, tuple): 126 self.files.append((name, (None, file_info, None))) 127 elif len(file_info) == 2: 128 self.files.append((name, (file_info[0], file_info[1], None))) 129 else: 130 self.files.append((name, file_info)) # type: ignore 131 132 def __repr__(self) -> str: 133 class_name = self.__class__.__name__ 134 url = str(self.url) 135 return f"<{class_name}({self.method!r}, {url!r})>" 136 137 138class Cookies(MutableMapping): 139 def __init__(self, cookies: CookieTypes = None) -> None: 140 self.jar: CookieJar = cookies if isinstance(cookies, CookieJar) else CookieJar() 141 if cookies is not None and not isinstance(cookies, CookieJar): 142 if isinstance(cookies, dict): 143 for key, value in cookies.items(): 144 self.set(key, value) 145 elif isinstance(cookies, list): 146 for key, value in cookies: 147 self.set(key, value) 148 elif isinstance(cookies, Cookies): 149 for cookie in cookies.jar: 150 self.jar.set_cookie(cookie) 151 else: 152 raise TypeError(f"Cookies must be dict or list, not {type(cookies)}") 153 154 def set(self, name: str, value: str, domain: str = "", path: str = "/") -> None: 155 cookie = Cookie( 156 version=0, 157 name=name, 158 value=value, 159 port=None, 160 port_specified=False, 161 domain=domain, 162 domain_specified=bool(domain), 163 domain_initial_dot=domain.startswith("."), 164 path=path, 165 path_specified=bool(path), 166 secure=False, 167 expires=None, 168 discard=True, 169 comment=None, 170 comment_url=None, 171 rest={}, 172 rfc2109=False, 173 ) 174 self.jar.set_cookie(cookie) 175 176 def get( 177 self, 178 name: str, 179 default: Optional[str] = None, 180 domain: str = None, 181 path: str = None, 182 ) -> Optional[str]: 183 value: Optional[str] = None 184 for cookie in self.jar: 185 if ( 186 cookie.name == name 187 and (domain is None or cookie.domain == domain) 188 and (path is None or cookie.path == path) 189 ): 190 if value is not None: 191 message = f"Multiple cookies exist with name={name}" 192 raise ValueError(message) 193 value = cookie.value 194 195 return default if value is None else value 196 197 def delete( 198 self, name: str, domain: Optional[str] = None, path: Optional[str] = None 199 ) -> None: 200 if domain is not None and path is not None: 201 return self.jar.clear(domain, path, name) 202 203 remove = [ 204 cookie 205 for cookie in self.jar 206 if cookie.name == name 207 and (domain is None or cookie.domain == domain) 208 and (path is None or cookie.path == path) 209 ] 210 211 for cookie in remove: 212 self.jar.clear(cookie.domain, cookie.path, cookie.name) 213 214 def clear(self, domain: Optional[str] = None, path: Optional[str] = None) -> None: 215 self.jar.clear(domain, path) 216 217 def update(self, cookies: CookieTypes = None) -> None: 218 cookies = Cookies(cookies) 219 for cookie in cookies.jar: 220 self.jar.set_cookie(cookie) 221 222 def __setitem__(self, name: str, value: str) -> None: 223 return self.set(name, value) 224 225 def __getitem__(self, name: str) -> str: 226 value = self.get(name) 227 if value is None: 228 raise KeyError(name) 229 return value 230 231 def __delitem__(self, name: str) -> None: 232 return self.delete(name) 233 234 def __len__(self) -> int: 235 return len(self.jar) 236 237 def __iter__(self) -> Iterator[Cookie]: 238 return (cookie for cookie in self.jar) 239 240 def __repr__(self) -> str: 241 cookies_repr = ", ".join( 242 [ 243 f"<Cookie {cookie.name}={cookie.value} for {cookie.domain} />" 244 for cookie in self.jar 245 ] 246 ) 247 248 return f"<Cookies [{cookies_repr}]>" 249 250 251@dataclasses.dataclass 252class WebSocketServerSetup: 253 """WebSocket 服务器路由配置。""" 254 255 path: URL # path should not be absolute, check it by URL.is_absolute() == False 256 name: str 257 handle_func: Callable 258 259class DataclassEncoder(json.JSONEncoder): 260 """在JSON序列化 `Message` (List[Dataclass]) 时使用的 `JSONEncoder`""" 261 262 def default(self, o): 263 if dataclasses.is_dataclass(o): 264 return dataclasses.asdict(o) 265 return super().default(o)
An enumeration.
Inherited Members
- enum.Enum
- name
- value
61class Request: 62 def __init__( 63 self, 64 method: Union[str, bytes], 65 url: Union["URL", str, RawURL], 66 *, 67 params: QueryTypes = None, 68 headers: HeaderTypes = None, 69 cookies: CookieTypes = None, 70 content: ContentTypes = None, 71 data: DataTypes = None, 72 json: Any = None, 73 files: FilesTypes = None, 74 version: Union[str, HTTPVersion] = HTTPVersion.H11, 75 timeout: Optional[float] = None, 76 proxy: Optional[str] = None, 77 ): 78 # method 79 self.method: str = ( 80 method.decode("ascii").upper() 81 if isinstance(method, bytes) 82 else method.upper() 83 ) 84 # http version 85 self.version: HTTPVersion = HTTPVersion(version) 86 # timeout 87 self.timeout: Optional[float] = timeout 88 # proxy 89 self.proxy: Optional[str] = proxy 90 91 # url 92 if isinstance(url, tuple): 93 scheme, host, port, path = url 94 url = URL.build( 95 scheme=scheme.decode("ascii"), 96 host=host.decode("ascii"), 97 port=port, 98 path=path.decode("ascii"), 99 ) 100 else: 101 url = URL(url) 102 103 if params is not None: 104 url = url.update_query(params) 105 self.url: URL = url 106 107 # headers 108 self.headers: CIMultiDict[str] 109 if headers is not None: 110 self.headers = CIMultiDict(headers) 111 else: 112 self.headers = CIMultiDict() 113 114 # cookies 115 self.cookies = Cookies(cookies) 116 117 # body 118 self.content: ContentTypes = content 119 self.data: DataTypes = data 120 self.json: Any = json 121 self.files: Optional[List[Tuple[str, FileType]]] = None 122 if files: 123 self.files = [] 124 files_ = files.items() if isinstance(files, dict) else files 125 for name, file_info in files_: 126 if not isinstance(file_info, tuple): 127 self.files.append((name, (None, file_info, None))) 128 elif len(file_info) == 2: 129 self.files.append((name, (file_info[0], file_info[1], None))) 130 else: 131 self.files.append((name, file_info)) # type: ignore 132 133 def __repr__(self) -> str: 134 class_name = self.__class__.__name__ 135 url = str(self.url) 136 return f"<{class_name}({self.method!r}, {url!r})>"
62 def __init__( 63 self, 64 method: Union[str, bytes], 65 url: Union["URL", str, RawURL], 66 *, 67 params: QueryTypes = None, 68 headers: HeaderTypes = None, 69 cookies: CookieTypes = None, 70 content: ContentTypes = None, 71 data: DataTypes = None, 72 json: Any = None, 73 files: FilesTypes = None, 74 version: Union[str, HTTPVersion] = HTTPVersion.H11, 75 timeout: Optional[float] = None, 76 proxy: Optional[str] = None, 77 ): 78 # method 79 self.method: str = ( 80 method.decode("ascii").upper() 81 if isinstance(method, bytes) 82 else method.upper() 83 ) 84 # http version 85 self.version: HTTPVersion = HTTPVersion(version) 86 # timeout 87 self.timeout: Optional[float] = timeout 88 # proxy 89 self.proxy: Optional[str] = proxy 90 91 # url 92 if isinstance(url, tuple): 93 scheme, host, port, path = url 94 url = URL.build( 95 scheme=scheme.decode("ascii"), 96 host=host.decode("ascii"), 97 port=port, 98 path=path.decode("ascii"), 99 ) 100 else: 101 url = URL(url) 102 103 if params is not None: 104 url = url.update_query(params) 105 self.url: URL = url 106 107 # headers 108 self.headers: CIMultiDict[str] 109 if headers is not None: 110 self.headers = CIMultiDict(headers) 111 else: 112 self.headers = CIMultiDict() 113 114 # cookies 115 self.cookies = Cookies(cookies) 116 117 # body 118 self.content: ContentTypes = content 119 self.data: DataTypes = data 120 self.json: Any = json 121 self.files: Optional[List[Tuple[str, FileType]]] = None 122 if files: 123 self.files = [] 124 files_ = files.items() if isinstance(files, dict) else files 125 for name, file_info in files_: 126 if not isinstance(file_info, tuple): 127 self.files.append((name, (None, file_info, None))) 128 elif len(file_info) == 2: 129 self.files.append((name, (file_info[0], file_info[1], None))) 130 else: 131 self.files.append((name, file_info)) # type: ignore
139class Cookies(MutableMapping): 140 def __init__(self, cookies: CookieTypes = None) -> None: 141 self.jar: CookieJar = cookies if isinstance(cookies, CookieJar) else CookieJar() 142 if cookies is not None and not isinstance(cookies, CookieJar): 143 if isinstance(cookies, dict): 144 for key, value in cookies.items(): 145 self.set(key, value) 146 elif isinstance(cookies, list): 147 for key, value in cookies: 148 self.set(key, value) 149 elif isinstance(cookies, Cookies): 150 for cookie in cookies.jar: 151 self.jar.set_cookie(cookie) 152 else: 153 raise TypeError(f"Cookies must be dict or list, not {type(cookies)}") 154 155 def set(self, name: str, value: str, domain: str = "", path: str = "/") -> None: 156 cookie = Cookie( 157 version=0, 158 name=name, 159 value=value, 160 port=None, 161 port_specified=False, 162 domain=domain, 163 domain_specified=bool(domain), 164 domain_initial_dot=domain.startswith("."), 165 path=path, 166 path_specified=bool(path), 167 secure=False, 168 expires=None, 169 discard=True, 170 comment=None, 171 comment_url=None, 172 rest={}, 173 rfc2109=False, 174 ) 175 self.jar.set_cookie(cookie) 176 177 def get( 178 self, 179 name: str, 180 default: Optional[str] = None, 181 domain: str = None, 182 path: str = None, 183 ) -> Optional[str]: 184 value: Optional[str] = None 185 for cookie in self.jar: 186 if ( 187 cookie.name == name 188 and (domain is None or cookie.domain == domain) 189 and (path is None or cookie.path == path) 190 ): 191 if value is not None: 192 message = f"Multiple cookies exist with name={name}" 193 raise ValueError(message) 194 value = cookie.value 195 196 return default if value is None else value 197 198 def delete( 199 self, name: str, domain: Optional[str] = None, path: Optional[str] = None 200 ) -> None: 201 if domain is not None and path is not None: 202 return self.jar.clear(domain, path, name) 203 204 remove = [ 205 cookie 206 for cookie in self.jar 207 if cookie.name == name 208 and (domain is None or cookie.domain == domain) 209 and (path is None or cookie.path == path) 210 ] 211 212 for cookie in remove: 213 self.jar.clear(cookie.domain, cookie.path, cookie.name) 214 215 def clear(self, domain: Optional[str] = None, path: Optional[str] = None) -> None: 216 self.jar.clear(domain, path) 217 218 def update(self, cookies: CookieTypes = None) -> None: 219 cookies = Cookies(cookies) 220 for cookie in cookies.jar: 221 self.jar.set_cookie(cookie) 222 223 def __setitem__(self, name: str, value: str) -> None: 224 return self.set(name, value) 225 226 def __getitem__(self, name: str) -> str: 227 value = self.get(name) 228 if value is None: 229 raise KeyError(name) 230 return value 231 232 def __delitem__(self, name: str) -> None: 233 return self.delete(name) 234 235 def __len__(self) -> int: 236 return len(self.jar) 237 238 def __iter__(self) -> Iterator[Cookie]: 239 return (cookie for cookie in self.jar) 240 241 def __repr__(self) -> str: 242 cookies_repr = ", ".join( 243 [ 244 f"<Cookie {cookie.name}={cookie.value} for {cookie.domain} />" 245 for cookie in self.jar 246 ] 247 ) 248 249 return f"<Cookies [{cookies_repr}]>"
Abstract base class for generic types.
A generic type is typically declared by inheriting from this class parameterized with one or more type variables. For example, a generic mapping type might be defined as::
class Mapping(Generic[KT, VT]): def __getitem__(self, key: KT) -> VT: ... # Etc.
This class can then be used as follows::
def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT: try: return mapping[key] except KeyError: return default
140 def __init__(self, cookies: CookieTypes = None) -> None: 141 self.jar: CookieJar = cookies if isinstance(cookies, CookieJar) else CookieJar() 142 if cookies is not None and not isinstance(cookies, CookieJar): 143 if isinstance(cookies, dict): 144 for key, value in cookies.items(): 145 self.set(key, value) 146 elif isinstance(cookies, list): 147 for key, value in cookies: 148 self.set(key, value) 149 elif isinstance(cookies, Cookies): 150 for cookie in cookies.jar: 151 self.jar.set_cookie(cookie) 152 else: 153 raise TypeError(f"Cookies must be dict or list, not {type(cookies)}")
155 def set(self, name: str, value: str, domain: str = "", path: str = "/") -> None: 156 cookie = Cookie( 157 version=0, 158 name=name, 159 value=value, 160 port=None, 161 port_specified=False, 162 domain=domain, 163 domain_specified=bool(domain), 164 domain_initial_dot=domain.startswith("."), 165 path=path, 166 path_specified=bool(path), 167 secure=False, 168 expires=None, 169 discard=True, 170 comment=None, 171 comment_url=None, 172 rest={}, 173 rfc2109=False, 174 ) 175 self.jar.set_cookie(cookie)
177 def get( 178 self, 179 name: str, 180 default: Optional[str] = None, 181 domain: str = None, 182 path: str = None, 183 ) -> Optional[str]: 184 value: Optional[str] = None 185 for cookie in self.jar: 186 if ( 187 cookie.name == name 188 and (domain is None or cookie.domain == domain) 189 and (path is None or cookie.path == path) 190 ): 191 if value is not None: 192 message = f"Multiple cookies exist with name={name}" 193 raise ValueError(message) 194 value = cookie.value 195 196 return default if value is None else value
D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.
198 def delete( 199 self, name: str, domain: Optional[str] = None, path: Optional[str] = None 200 ) -> None: 201 if domain is not None and path is not None: 202 return self.jar.clear(domain, path, name) 203 204 remove = [ 205 cookie 206 for cookie in self.jar 207 if cookie.name == name 208 and (domain is None or cookie.domain == domain) 209 and (path is None or cookie.path == path) 210 ] 211 212 for cookie in remove: 213 self.jar.clear(cookie.domain, cookie.path, cookie.name)
215 def clear(self, domain: Optional[str] = None, path: Optional[str] = None) -> None: 216 self.jar.clear(domain, path)
D.clear() -> None. Remove all items from D.
218 def update(self, cookies: CookieTypes = None) -> None: 219 cookies = Cookies(cookies) 220 for cookie in cookies.jar: 221 self.jar.set_cookie(cookie)
D.update([E, ]**F) -> None. Update D from mapping/iterable E and F. If E present and has a .keys() method, does: for k in E: D[k] = E[k] If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v In either case, this is followed by: for k, v in F.items(): D[k] = v
Inherited Members
- collections.abc.MutableMapping
- pop
- popitem
- setdefault
- collections.abc.Mapping
- keys
- items
- values
253class WebSocketServerSetup: 254 """WebSocket 服务器路由配置。""" 255 256 path: URL # path should not be absolute, check it by URL.is_absolute() == False 257 name: str 258 handle_func: Callable
WebSocket 服务器路由配置。
260class DataclassEncoder(json.JSONEncoder): 261 """在JSON序列化 `Message` (List[Dataclass]) 时使用的 `JSONEncoder`""" 262 263 def default(self, o): 264 if dataclasses.is_dataclass(o): 265 return dataclasses.asdict(o) 266 return super().default(o)
在JSON序列化 Message
(List[Dataclass]) 时使用的 JSONEncoder
263 def default(self, o): 264 if dataclasses.is_dataclass(o): 265 return dataclasses.asdict(o) 266 return super().default(o)
Implement this method in a subclass such that it returns
a serializable object for o
, or calls the base implementation
(to raise a TypeError
).
For example, to support arbitrary iterators, you could implement default like this::
def default(self, o):
try:
iterable = iter(o)
except TypeError:
pass
else:
return list(iterable)
# Let the base class default method raise the TypeError
return JSONEncoder.default(self, o)
Inherited Members
- json.encoder.JSONEncoder
- JSONEncoder
- encode
- iterencode