diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8177a91..01e25c1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: python:3.9-alpine +image: python:3.10-alpine variables: PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" diff --git a/LICENSE b/LICENSE index f1d5400..8bd7101 100644 --- a/LICENSE +++ b/LICENSE @@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Litecord - Copyright (C) 2018 Luna Mendes + Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -651,7 +651,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - litecord Copyright (C) 2018 Luna Mendes + litecord Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff --git a/README.md b/README.md index f3296f7..cbdf65e 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ are not implemented, for example: - Threads - Channel Categories -- API v9 (Right now, Litecord, in generla, assumes v9 is +- API v9 (Right now, Litecord, in general, assumes v9 is just v6 to make clients work, new payload structure support is scattered throughout the codebase) diff --git a/__init__.py b/__init__.py index 62dfb89..3878d03 100644 --- a/__init__.py +++ b/__init__.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,4 +16,3 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ - diff --git a/config.ci.py b/config.ci.py index 911085a..83290d3 100644 --- a/config.ci.py +++ b/config.ci.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/config.example.py b/config.example.py index 999add7..56d701b 100644 --- a/config.example.py +++ b/config.example.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -48,6 +48,11 @@ class Config: # e.g 'gateway.example.com' for reverse proxies. WEBSOCKET_URL = "localhost:5001" + # Set these to file paths if you want to enable raw TLS support on + # the websocket (without NGINX) + WEBSOCKET_TLS_CERT_PATH = None + WEBSOCKET_TLS_KEY_PATH = None + #: Where to host the websocket? # (a local address the server will bind to) WS_HOST = "0.0.0.0" @@ -60,6 +65,9 @@ class Config: #: Postgres credentials POSTGRES = {} + + #: Shared secret for LVSP + LVSP_SECRET = "" class Development(Config): diff --git a/docs/lvsp.md b/docs/lvsp.md index bbd31ba..2913769 100644 --- a/docs/lvsp.md +++ b/docs/lvsp.md @@ -8,7 +8,9 @@ LVSP runs over a *long-lived* websocket with TLS. The encoding is JSON. ## OP code table -"client" is litecord. "server" is the voice server. +"client" is litecord. "server" is the voice server. + +note: only the opcode is sent in a message, so the names are determined by the implementation of LVSP. | opcode | name | sent by | | --: | :-- | :-- | @@ -119,15 +121,17 @@ are laid on. ### InfoType Enum +note: this enum is only ever identified by its opcode, so the `name` field can differ from the values in this enum without error. + | value | name | description | | --: | :-- | :-- | | 0 | CHANNEL\_REQ | channel assignment request | | 1 | CHANNEL\_ASSIGN | channel assignment reply | | 2 | CHANNEL\_DESTROY | channel destroy | -| 3 | VST\_CREATE | voice state create request | -| 4 | VST\_DONE | voice state created | -| 5 | VST\_UPDATE | voice state update | -| 6 | VST\_LEAVE | voice state leave | +| 3 | VOICE\_STATE\_CREATE | voice state create request | +| 4 | VOICE\_STATE\_DONE | voice state created | +| 5 | VOICE\_STATE\_DESTROY | voice state destroy | +| 6 | VOICE\_STATE\_UPDATE | voice state update | ### CHANNEL\_REQ @@ -158,7 +162,7 @@ a channel being deleted, or all members in it leaving. Same data as CHANNEL\_ASSIGN, but without `token`. -### VST\_CREATE +### VOICE\_STATE\_CREATE Sent by the client to create a voice state. @@ -168,21 +172,25 @@ Sent by the client to create a voice state. | channel\_id | snowflake | channel id | | guild\_id | Optional[snowflake] | guild id. not provided if dm / group dm | -### VST\_DONE +### VOICE\_STATE\_DONE -Sent by the server to indicate the success of a VST\_CREATE. +Sent by the server to indicate the success of a VOICE\_STATE\_CREATE. -Has the same fields as VST\_CREATE, but with extras: +Has the same fields as VOICE\_STATE\_CREATE, but with extras: | field | type | description | | --: | :-- | :-- | | session\_id | string | session id for the voice state | -### VST\_DESTROY +### VOICE\_STATE\_DESTROY Sent by the client when a user is leaving a channel OR moving between channels in a guild. More on state transitions later on. +### VOICE\_STATE\_UPDATE + +Sent to update an existing voice state. Potentially unused. + | field | type | description | | --: | :-- | :-- | | session\_id | string | session id for the voice state | @@ -195,11 +203,11 @@ Since the channel is unitialized, both logic on initialization AND user join is here. - Client will send a CHANNEL\_REQ. - - Client MAY send a VST\_CREATE right after as well. + - Client MAY send a VOICE\_STATE\_CREATE right after as well. - The Server MUST process CHANNEL\_REQ first, so the Server can keep a lock on channel operations while it is initialized. - Reply with CHANNEL\_ASSIGN once initialization is done. - - Process VST\_CREATE + - Process VOICE\_STATE\_CREATE ### Updating a voice channel @@ -214,15 +222,15 @@ user join is here. ### User joining an (initialized) voice channel - - Client sends VST\_CREATE - - Server sends VST\_DONE + - Client sends VOICE\_STATE\_CREATE + - Server sends VOICE\_STATE\_DONE ### User leaves a channel - - Client sends VST\_DESTROY with the old fields + - Client sends VOICE\_STATE\_DESTROY with the old fields ### User moves a channel - - Client sends VST\_DESTROY with the old fields - - Client sends VST\_CREATE with the new fields - - Server sends VST\_DONE + - Client sends VOICE\_STATE\_DESTROY with the old fields + - Client sends VOICE\_STATE\_CREATE with the new fields + - Server sends VOICE\_STATE\_DONE diff --git a/litecord/__init__.py b/litecord/__init__.py index d21f555..3878d03 100644 --- a/litecord/__init__.py +++ b/litecord/__init__.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/admin_schemas.py b/litecord/admin_schemas.py index 900f734..39cc244 100644 --- a/litecord/admin_schemas.py +++ b/litecord/admin_schemas.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/auth.py b/litecord/auth.py index 849a45a..841c49d 100644 --- a/litecord/auth.py +++ b/litecord/auth.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/__init__.py b/litecord/blueprints/__init__.py index e02db5b..0d8ad80 100644 --- a/litecord/blueprints/__init__.py +++ b/litecord/blueprints/__init__.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/admin_api/__init__.py b/litecord/blueprints/admin_api/__init__.py index ab0e1e8..633221b 100644 --- a/litecord/blueprints/admin_api/__init__.py +++ b/litecord/blueprints/admin_api/__init__.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/admin_api/features.py b/litecord/blueprints/admin_api/features.py index 2d9d655..6e4aeb6 100644 --- a/litecord/blueprints/admin_api/features.py +++ b/litecord/blueprints/admin_api/features.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/admin_api/guilds.py b/litecord/blueprints/admin_api/guilds.py index 153bdff..e1d98d3 100644 --- a/litecord/blueprints/admin_api/guilds.py +++ b/litecord/blueprints/admin_api/guilds.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/admin_api/instance_invites.py b/litecord/blueprints/admin_api/instance_invites.py index 2a9540d..d053dc9 100644 --- a/litecord/blueprints/admin_api/instance_invites.py +++ b/litecord/blueprints/admin_api/instance_invites.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/admin_api/users.py b/litecord/blueprints/admin_api/users.py index d18cb76..4c04fc7 100644 --- a/litecord/blueprints/admin_api/users.py +++ b/litecord/blueprints/admin_api/users.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/admin_api/voice.py b/litecord/blueprints/admin_api/voice.py index 6326003..83a33ba 100644 --- a/litecord/blueprints/admin_api/voice.py +++ b/litecord/blueprints/admin_api/voice.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/applications.py b/litecord/blueprints/applications.py index 5b789c2..67b39a7 100644 --- a/litecord/blueprints/applications.py +++ b/litecord/blueprints/applications.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/attachments.py b/litecord/blueprints/attachments.py index 49da21a..9c60082 100644 --- a/litecord/blueprints/attachments.py +++ b/litecord/blueprints/attachments.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/auth.py b/litecord/blueprints/auth.py index dda3e4f..c801bde 100644 --- a/litecord/blueprints/auth.py +++ b/litecord/blueprints/auth.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/channel/__init__.py b/litecord/blueprints/channel/__init__.py index fc08dd2..081f072 100644 --- a/litecord/blueprints/channel/__init__.py +++ b/litecord/blueprints/channel/__init__.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/channel/messages.py b/litecord/blueprints/channel/messages.py index 98f7e3b..c1a621b 100644 --- a/litecord/blueprints/channel/messages.py +++ b/litecord/blueprints/channel/messages.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,7 +29,8 @@ from litecord.errors import MessageNotFound, Forbidden from litecord.enums import MessageType, ChannelType, GUILD_CHANS from litecord.schemas import validate, MESSAGE_CREATE -from litecord.utils import pg_set_json, query_tuple_from_args, extract_limit +from litecord.utils import query_tuple_from_args, extract_limit +from litecord.json import pg_set_json from litecord.permissions import get_permissions from litecord.embed.sanitizer import fill_embed diff --git a/litecord/blueprints/channel/pins.py b/litecord/blueprints/channel/pins.py index 477d543..56db54e 100644 --- a/litecord/blueprints/channel/pins.py +++ b/litecord/blueprints/channel/pins.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/channel/reactions.py b/litecord/blueprints/channel/reactions.py index 3fa18a6..b42c47f 100644 --- a/litecord/blueprints/channel/reactions.py +++ b/litecord/blueprints/channel/reactions.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/channels.py b/litecord/blueprints/channels.py index d1caf94..21dcb55 100644 --- a/litecord/blueprints/channels.py +++ b/litecord/blueprints/channels.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/checks.py b/litecord/blueprints/checks.py index aa126b8..ddd345d 100644 --- a/litecord/blueprints/checks.py +++ b/litecord/blueprints/checks.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/dm_channels.py b/litecord/blueprints/dm_channels.py index 041c288..a126928 100644 --- a/litecord/blueprints/dm_channels.py +++ b/litecord/blueprints/dm_channels.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/dms.py b/litecord/blueprints/dms.py index 5c7ad31..de0d10d 100644 --- a/litecord/blueprints/dms.py +++ b/litecord/blueprints/dms.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/gateway.py b/litecord/blueprints/gateway.py index 5a4601b..e6e0d2f 100644 --- a/litecord/blueprints/gateway.py +++ b/litecord/blueprints/gateway.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/guild/__init__.py b/litecord/blueprints/guild/__init__.py index 31c2640..37be2f8 100644 --- a/litecord/blueprints/guild/__init__.py +++ b/litecord/blueprints/guild/__init__.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/guild/channels.py b/litecord/blueprints/guild/channels.py index 56a1d21..6cce8d0 100644 --- a/litecord/blueprints/guild/channels.py +++ b/litecord/blueprints/guild/channels.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/guild/emoji.py b/litecord/blueprints/guild/emoji.py index 1716af2..aa8d7e5 100644 --- a/litecord/blueprints/guild/emoji.py +++ b/litecord/blueprints/guild/emoji.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/guild/members.py b/litecord/blueprints/guild/members.py index 0f77dc8..e6aae5c 100644 --- a/litecord/blueprints/guild/members.py +++ b/litecord/blueprints/guild/members.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/guild/mod.py b/litecord/blueprints/guild/mod.py index 8084e72..913c3cc 100644 --- a/litecord/blueprints/guild/mod.py +++ b/litecord/blueprints/guild/mod.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/guild/roles.py b/litecord/blueprints/guild/roles.py index 265ccf8..dc7a122 100644 --- a/litecord/blueprints/guild/roles.py +++ b/litecord/blueprints/guild/roles.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/guilds.py b/litecord/blueprints/guilds.py index 4ada15f..0e064cd 100644 --- a/litecord/blueprints/guilds.py +++ b/litecord/blueprints/guilds.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/icons.py b/litecord/blueprints/icons.py index fc6eec3..2d455d9 100644 --- a/litecord/blueprints/icons.py +++ b/litecord/blueprints/icons.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/invites.py b/litecord/blueprints/invites.py index c31820a..c53b739 100644 --- a/litecord/blueprints/invites.py +++ b/litecord/blueprints/invites.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/nodeinfo.py b/litecord/blueprints/nodeinfo.py index 7afefb2..a15e84b 100644 --- a/litecord/blueprints/nodeinfo.py +++ b/litecord/blueprints/nodeinfo.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/read_states.py b/litecord/blueprints/read_states.py index 04053b5..827698a 100644 --- a/litecord/blueprints/read_states.py +++ b/litecord/blueprints/read_states.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/relationships.py b/litecord/blueprints/relationships.py index 7e88af2..50b7310 100644 --- a/litecord/blueprints/relationships.py +++ b/litecord/blueprints/relationships.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/science.py b/litecord/blueprints/science.py index 7a5273c..ba995b0 100644 --- a/litecord/blueprints/science.py +++ b/litecord/blueprints/science.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/static.py b/litecord/blueprints/static.py index 61f2148..c3416f4 100644 --- a/litecord/blueprints/static.py +++ b/litecord/blueprints/static.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ along with this program. If not, see . """ -from quart import Blueprint, current_app as app, render_template_string +from quart import Blueprint, current_app as app, render_template_string, send_file from pathlib import Path bp = Blueprint("static", __name__) @@ -30,7 +30,10 @@ async def static_pages(path): return "no", 404 static_path = Path.cwd() / Path("static") / path - return await app.send_static_file(str(static_path)) + if static_path.exists(): + return await send_file(static_path) + else: + return "not found", 404 @bp.route("/") diff --git a/litecord/blueprints/stickers.py b/litecord/blueprints/stickers.py index afd8297..824f74a 100644 --- a/litecord/blueprints/stickers.py +++ b/litecord/blueprints/stickers.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/store.py b/litecord/blueprints/store.py index 27a22a7..46efc4a 100644 --- a/litecord/blueprints/store.py +++ b/litecord/blueprints/store.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/user/__init__.py b/litecord/blueprints/user/__init__.py index bd27fa4..a383443 100644 --- a/litecord/blueprints/user/__init__.py +++ b/litecord/blueprints/user/__init__.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/user/billing.py b/litecord/blueprints/user/billing.py index 30e27e3..8d159fa 100644 --- a/litecord/blueprints/user/billing.py +++ b/litecord/blueprints/user/billing.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/user/billing_job.py b/litecord/blueprints/user/billing_job.py index 0824f82..3676ef7 100644 --- a/litecord/blueprints/user/billing_job.py +++ b/litecord/blueprints/user/billing_job.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/user/fake_store.py b/litecord/blueprints/user/fake_store.py index 7f4fc3c..eaeef0e 100644 --- a/litecord/blueprints/user/fake_store.py +++ b/litecord/blueprints/user/fake_store.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/user/settings.py b/litecord/blueprints/user/settings.py index ae05b59..cc8c018 100644 --- a/litecord/blueprints/user/settings.py +++ b/litecord/blueprints/user/settings.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/users.py b/litecord/blueprints/users.py index af4e028..f50e583 100644 --- a/litecord/blueprints/users.py +++ b/litecord/blueprints/users.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/voice.py b/litecord/blueprints/voice.py index dd3cad5..cde0db8 100644 --- a/litecord/blueprints/voice.py +++ b/litecord/blueprints/voice.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/blueprints/webhooks.py b/litecord/blueprints/webhooks.py index fb5e7b7..cc5d4ab 100644 --- a/litecord/blueprints/webhooks.py +++ b/litecord/blueprints/webhooks.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -52,7 +52,7 @@ from litecord.common.messages import ( from litecord.embed.sanitizer import fill_embed, fetch_mediaproxy_img from litecord.embed.messages import process_url_embed, is_media_url from litecord.embed.schemas import EmbedURL -from litecord.utils import pg_set_json +from litecord.json import pg_set_json from litecord.enums import MessageType from litecord.images import STATIC_IMAGE_MIMES diff --git a/litecord/common/channels.py b/litecord/common/channels.py index 08ff7f0..7245e20 100644 --- a/litecord/common/channels.py +++ b/litecord/common/channels.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/common/guilds.py b/litecord/common/guilds.py index 44ec3f4..476d9a1 100644 --- a/litecord/common/guilds.py +++ b/litecord/common/guilds.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/common/users.py b/litecord/common/users.py index 550218b..04428cc 100644 --- a/litecord/common/users.py +++ b/litecord/common/users.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/dispatcher.py b/litecord/dispatcher.py index 21e3dfe..67c27d5 100644 --- a/litecord/dispatcher.py +++ b/litecord/dispatcher.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/embed/__init__.py b/litecord/embed/__init__.py index c813d99..35a696e 100644 --- a/litecord/embed/__init__.py +++ b/litecord/embed/__init__.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/embed/messages.py b/litecord/embed/messages.py index 69b1576..72be730 100644 --- a/litecord/embed/messages.py +++ b/litecord/embed/messages.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/embed/sanitizer.py b/litecord/embed/sanitizer.py index 992522b..79416d9 100644 --- a/litecord/embed/sanitizer.py +++ b/litecord/embed/sanitizer.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/embed/schemas.py b/litecord/embed/schemas.py index 7df073c..b3521c2 100644 --- a/litecord/embed/schemas.py +++ b/litecord/embed/schemas.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/enums.py b/litecord/enums.py index 284204c..235b865 100644 --- a/litecord/enums.py +++ b/litecord/enums.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -189,6 +189,8 @@ class StatusType(EasyEnum): IDLE = "idle" INVISIBLE = "invisible" OFFLINE = "offline" + STREAMING = "streaming" + UNKNOWN = "unknown" class ExplicitFilter(EasyEnum): diff --git a/litecord/errors.py b/litecord/errors.py index 89463be..23ffea4 100644 --- a/litecord/errors.py +++ b/litecord/errors.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/gateway/encoding.py b/litecord/gateway/encoding.py index 788d2b7..dc187b3 100644 --- a/litecord/gateway/encoding.py +++ b/litecord/gateway/encoding.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ along with this program. If not, see . import json import earl -from litecord.utils import LitecordJSONEncoder +from litecord.json import LitecordJSONEncoder def encode_json(payload) -> str: diff --git a/litecord/gateway/errors.py b/litecord/gateway/errors.py index 569bc88..0b89dc2 100644 --- a/litecord/gateway/errors.py +++ b/litecord/gateway/errors.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/gateway/gateway.py b/litecord/gateway/gateway.py index c7f0cf1..50c231a 100644 --- a/litecord/gateway/gateway.py +++ b/litecord/gateway/gateway.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/gateway/opcodes.py b/litecord/gateway/opcodes.py index 626d109..67c7463 100644 --- a/litecord/gateway/opcodes.py +++ b/litecord/gateway/opcodes.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/gateway/schemas.py b/litecord/gateway/schemas.py index 8335a37..af8d469 100644 --- a/litecord/gateway/schemas.py +++ b/litecord/gateway/schemas.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -120,8 +120,12 @@ IDENTIFY_SCHEMA = { "type": "number", "required": False, }, + "user_settings_version": {"type": "number", "required": False}, }, }, + "guild_subscriptions": {"type": "boolean", "required": False}, + # this is just to make bot libraries happy + "v": {"type": "number", "required": False}, }, } }, diff --git a/litecord/gateway/state.py b/litecord/gateway/state.py index 3d97788..840af3e 100644 --- a/litecord/gateway/state.py +++ b/litecord/gateway/state.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/gateway/state_manager.py b/litecord/gateway/state_manager.py index bbfdc2c..c1b88bf 100644 --- a/litecord/gateway/state_manager.py +++ b/litecord/gateway/state_manager.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/gateway/utils.py b/litecord/gateway/utils.py index 8f158b3..81da248 100644 --- a/litecord/gateway/utils.py +++ b/litecord/gateway/utils.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/gateway/websocket.py b/litecord/gateway/websocket.py index c535c1a..3f12d06 100644 --- a/litecord/gateway/websocket.py +++ b/litecord/gateway/websocket.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -91,7 +91,8 @@ def _complete_users_list(user_id: str, base_ready, user_ready, ws_properties) -> for recipient in private_channel["recipients"]: users_to_send[recipient["id"]] = recipient - for relationship in user_ready["relationships"]: + user_relationships = user_ready.get("relationships", []) + for relationship in user_relationships: relationship_user = relationship["user"] users_to_send[relationship_user["id"]] = relationship_user @@ -101,7 +102,7 @@ def _complete_users_list(user_id: str, base_ready, user_ready, ws_properties) -> # relationship object structure changed in v9 if ws_properties.version == 9: ready["relationships"] = [] - for relationship in user_ready["relationships"]: + for relationship in user_relationships: ready["relationships"].append( { "user_id": relationship["user"]["id"], @@ -138,7 +139,9 @@ async def _compute_supplemental(app, base_ready, user_ready, users_to_send: dict "guilds": [], } - for relationship in user_ready["relationships"]: + user_relationships = user_ready.get("relationships", []) + + for relationship in user_relationships: if relationship["type"] != RelationshipType.FRIEND.value: continue @@ -265,16 +268,13 @@ class GatewayWebsocket: """Split data in chunk_size-big chunks and send them over the websocket.""" log.debug( - "zlib-stream: chunking {} bytes into {}-byte chunks", len(data), chunk_size + "zlib-stream: sending {} bytes into {}-byte chunks", len(data), chunk_size ) - total_chunks = 0 - for chunk in yield_chunks(data, chunk_size): - total_chunks += 1 - log.debug("zlib-stream: chunk {}", total_chunks) - await self.ws.send(chunk) - - log.debug("zlib-stream: sent {} chunks", total_chunks) + # we send the entire iterator as per websockets documentation + # to pretent setting FIN when we don't want to + # see https://gitlab.com/litecord/litecord/-/issues/139 + await self.ws.send(yield_chunks(data, chunk_size)) async def _zlib_stream_send(self, encoded): """Sending a single payload across multiple compressed @@ -283,39 +283,19 @@ class GatewayWebsocket: # compress and flush (for the rest of compressed data + ZLIB_SUFFIX) data1 = self.ws_properties.zctx.compress(encoded) data2 = self.ws_properties.zctx.flush(zlib.Z_FULL_FLUSH) + data = data1 + data2 log.debug( - "zlib-stream: length {} -> compressed ({} + {})", + "zlib-stream: length {} -> compressed ({})", len(encoded), - len(data1), - len(data2), + len(data), ) - if not data1: - # if data1 is nothing, that might cause problems - # to clients, since they'll receive an empty message - data1 = bytes([data2[0]]) - data2 = data2[1:] - - log.debug( - "zlib-stream: len(data1) == 0, remaking as ({} + {})", - len(data1), - len(data2), - ) - - # NOTE: the old approach was ws.send(data1 + data2). - # I changed this to a chunked send of data1 and data2 - # because that can bring some problems to the network - # since we can be potentially sending a really big packet - # as a single message. - - # clients should handle chunked sends (via detection - # of the ZLIB_SUFFIX suffix appended to data2), so - # this shouldn't being problems. + # since we always chunk the entire compressed message, we shouldn't + # worry about sending big frames to the clients # TODO: the chunks are 1024 bytes, 1KB, is this good enough? - await self._chunked_send(data1, 1024) - await self._chunked_send(data2, 1024) + await self._chunked_send(data, 1024) async def _zstd_stream_send(self, encoded): compressor = self.ws_properties.zsctx.stream_writer( @@ -730,7 +710,7 @@ class GatewayWebsocket: presence.game = game - if presence.status == "invisible": + if presence.status in ("invisible", "unknown"): presence.status = "offline" self.state.presence = presence @@ -915,6 +895,9 @@ class GatewayWebsocket: # they CAN NOT enter two channels in a single guild. # this state id format takes care of that. + # + # TODO voice_key should have a type as a 0th element to prevent + # code from having to call get_guild(id2). voice_key = (self.state.user_id, state_id2) voice_state = await self.app.voice.get_state(voice_key) @@ -932,6 +915,10 @@ class GatewayWebsocket: if same_guild and not same_channel: return await self.app.voice.move_state(voice_state, channel_id) + # TODO: this is an edge case. we're trying to move guilds in + # a single message, perhaps? + log.warning("vsu payload does not appear logical") + async def _handle_5(self, payload: Dict[str, Any]): """Handle OP 5 Voice Server Ping. diff --git a/litecord/guild_memory_store.py b/litecord/guild_memory_store.py index 223891c..b2541d0 100644 --- a/litecord/guild_memory_store.py +++ b/litecord/guild_memory_store.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/images.py b/litecord/images.py index d13f997..e14ab2d 100644 --- a/litecord/images.py +++ b/litecord/images.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/jobs.py b/litecord/jobs.py index 44342e1..46e3ad1 100644 --- a/litecord/jobs.py +++ b/litecord/jobs.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/json.py b/litecord/json.py new file mode 100644 index 0000000..e6fccbf --- /dev/null +++ b/litecord/json.py @@ -0,0 +1,69 @@ +""" + +Litecord +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +""" + +import json +from typing import Any +from decimal import Decimal +from uuid import UUID +from dataclasses import asdict, is_dataclass + +import quart.json.provider + + +class LitecordJSONEncoder(json.JSONEncoder): + """Custom JSON encoder for Litecord. Useful for json.dumps""" + + def default(self, value: Any): + if isinstance(value, (Decimal, UUID)): + return str(value) + + if is_dataclass(value): + return asdict(value) + + if hasattr(value, "to_json"): + return value.to_json + + return super().default(self, value) + + +class LitecordJSONProvider(quart.json.provider.DefaultJSONProvider): + """Custom JSON provider for Quart.""" + + def __init__(self, *args, **kwargs): + self.encoder = LitecordJSONEncoder(**kwargs) + + def default(self, value: Any): + self.encoder.default(value) + + +async def pg_set_json(con): + """Set JSON and JSONB codecs for an asyncpg connection.""" + await con.set_type_codec( + "json", + encoder=lambda v: json.dumps(v, cls=LitecordJSONEncoder), + decoder=json.loads, + schema="pg_catalog", + ) + + await con.set_type_codec( + "jsonb", + encoder=lambda v: json.dumps(v, cls=LitecordJSONEncoder), + decoder=json.loads, + schema="pg_catalog", + ) diff --git a/litecord/permissions.py b/litecord/permissions.py index 654e2be..3825fe3 100644 --- a/litecord/permissions.py +++ b/litecord/permissions.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/presence.py b/litecord/presence.py index 32600ae..398bbe0 100644 --- a/litecord/presence.py +++ b/litecord/presence.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/pubsub/__init__.py b/litecord/pubsub/__init__.py index a038822..b4e20f3 100644 --- a/litecord/pubsub/__init__.py +++ b/litecord/pubsub/__init__.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/pubsub/channel.py b/litecord/pubsub/channel.py index 4cdb9b2..67826d0 100644 --- a/litecord/pubsub/channel.py +++ b/litecord/pubsub/channel.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/pubsub/dispatcher.py b/litecord/pubsub/dispatcher.py index 50e3ead..b617dc0 100644 --- a/litecord/pubsub/dispatcher.py +++ b/litecord/pubsub/dispatcher.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/pubsub/friend.py b/litecord/pubsub/friend.py index c129ed3..aa9ba3d 100644 --- a/litecord/pubsub/friend.py +++ b/litecord/pubsub/friend.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/pubsub/guild.py b/litecord/pubsub/guild.py index 32a3e6d..ab9194a 100644 --- a/litecord/pubsub/guild.py +++ b/litecord/pubsub/guild.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/pubsub/lazy_guild.py b/litecord/pubsub/lazy_guild.py index 9b9dd0c..69f57a6 100644 --- a/litecord/pubsub/lazy_guild.py +++ b/litecord/pubsub/lazy_guild.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/pubsub/member.py b/litecord/pubsub/member.py index d026ef9..c7679da 100644 --- a/litecord/pubsub/member.py +++ b/litecord/pubsub/member.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/pubsub/user.py b/litecord/pubsub/user.py index 178d6b8..d3b4220 100644 --- a/litecord/pubsub/user.py +++ b/litecord/pubsub/user.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/pubsub/utils.py b/litecord/pubsub/utils.py index bb1981b..614553d 100644 --- a/litecord/pubsub/utils.py +++ b/litecord/pubsub/utils.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/ratelimits/bucket.py b/litecord/ratelimits/bucket.py index c79bca2..817ab24 100644 --- a/litecord/ratelimits/bucket.py +++ b/litecord/ratelimits/bucket.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/ratelimits/handler.py b/litecord/ratelimits/handler.py index 74b2270..708feb9 100644 --- a/litecord/ratelimits/handler.py +++ b/litecord/ratelimits/handler.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/ratelimits/main.py b/litecord/ratelimits/main.py index 88ec1a2..6ede010 100644 --- a/litecord/ratelimits/main.py +++ b/litecord/ratelimits/main.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/schemas.py b/litecord/schemas.py index 2d4fca1..eff44da 100644 --- a/litecord/schemas.py +++ b/litecord/schemas.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -450,8 +450,8 @@ MESSAGE_CREATE = { "required": False, "nullable": True, "schema": { - "parse": {"type": "list", "required": True}, - "replied_user": {"type": "boolean", "required": True}, + "parse": {"type": "list", "required": False}, + "replied_user": {"type": "boolean", "required": False}, }, }, } diff --git a/litecord/snowflake.py b/litecord/snowflake.py index 24a83c8..dbf47b1 100644 --- a/litecord/snowflake.py +++ b/litecord/snowflake.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/storage.py b/litecord/storage.py index eca2481..3f9b77d 100644 --- a/litecord/storage.py +++ b/litecord/storage.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -33,7 +33,7 @@ from litecord.blueprints.channel.reactions import ( from litecord.blueprints.user.billing import PLAN_ID_TO_TYPE from litecord.types import timestamp_ -from litecord.utils import pg_set_json +from litecord.json import pg_set_json log = Logger(__name__) diff --git a/litecord/system_messages.py b/litecord/system_messages.py index b32168d..e1f18e0 100644 --- a/litecord/system_messages.py +++ b/litecord/system_messages.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/types.py b/litecord/types.py index da8b157..81ac165 100644 --- a/litecord/types.py +++ b/litecord/types.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/user_storage.py b/litecord/user_storage.py index 02979fd..1dadd8a 100644 --- a/litecord/user_storage.py +++ b/litecord/user_storage.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/utils.py b/litecord/utils.py index 355bebf..f153d85 100644 --- a/litecord/utils.py +++ b/litecord/utils.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,14 +18,12 @@ along with this program. If not, see . """ import asyncio -import json import secrets import datetime import re from typing import Any, Iterable, Optional, Sequence, List, Dict, Union from logbook import Logger -from quart.json import JSONEncoder from quart import current_app as app from litecord.common.messages import message_view @@ -156,35 +154,6 @@ def mmh3(inp_str: str, seed: int = 0): return _u(h1) >> 0 -class LitecordJSONEncoder(JSONEncoder): - """Custom JSON encoder for Litecord.""" - - def default(self, value: Any): - """By default, this will try to get the to_json attribute of a given - value being JSON encoded.""" - try: - return value.to_json - except AttributeError: - return super().default(value) - - -async def pg_set_json(con): - """Set JSON and JSONB codecs for an asyncpg connection.""" - await con.set_type_codec( - "json", - encoder=lambda v: json.dumps(v, cls=LitecordJSONEncoder), - decoder=json.loads, - schema="pg_catalog", - ) - - await con.set_type_codec( - "jsonb", - encoder=lambda v: json.dumps(v, cls=LitecordJSONEncoder), - decoder=json.loads, - schema="pg_catalog", - ) - - def yield_chunks(input_list: Sequence[Any], chunk_size: int): """Yield successive n-sized chunks from l. diff --git a/litecord/voice/lvsp_conn.py b/litecord/voice/lvsp_conn.py index 30a39da..73be635 100644 --- a/litecord/voice/lvsp_conn.py +++ b/litecord/voice/lvsp_conn.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,6 +24,9 @@ from typing import Dict import websockets from logbook import Logger +import hmac +import hashlib + from litecord.voice.lvsp_opcodes import OPCodes as OP, InfoTable, InfoReverse log = Logger(__name__) @@ -59,7 +62,7 @@ class LVSPConnection: """Receive a payload.""" assert self.conn is not None msg = await self.conn.recv() - msg = json.dumps(msg) + msg = json.loads(msg) return msg async def send_op(self, opcode: int, data: dict): @@ -100,10 +103,15 @@ class LVSPConnection: """Handle HELLO message.""" data = msg["d"] - # nonce = data['nonce'] self._hb_interval = data["heartbeat_interval"] - # TODO: send identify + token = hmac.new( + self.app.config.get("LVSP_SECRET").encode(), + data["nonce"].encode(), + hashlib.sha256, + ).hexdigest() + + await self.send_op(OP.identify, {"token": token}) async def _update_health(self, new_health: float): """Update the health value of a given voice server.""" @@ -112,7 +120,7 @@ class LVSPConnection: await self.app.db.execute( """ UPDATE voice_servers - SET health = $1 + SET last_health = $1 WHERE hostname = $2 """, new_health, @@ -124,13 +132,17 @@ class LVSPConnection: We only start heartbeating after READY. """ - await self._update_health(msg["health"]) + data = msg["d"] + + await self._update_health(data["health"]) self._start_hb() async def _handle_5(self, msg): """Handle HEARTBEAT_ACK.""" self._stop_hb() - await self._update_health(msg["health"]) + data = msg["d"] + + await self._update_health(data["health"]) self._start_hb() async def _handle_6(self, msg): diff --git a/litecord/voice/lvsp_manager.py b/litecord/voice/lvsp_manager.py index 178ab41..f3e1265 100644 --- a/litecord/voice/lvsp_manager.py +++ b/litecord/voice/lvsp_manager.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/voice/lvsp_opcodes.py b/litecord/voice/lvsp_opcodes.py index b617fae..9f27cc1 100644 --- a/litecord/voice/lvsp_opcodes.py +++ b/litecord/voice/lvsp_opcodes.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/voice/manager.py b/litecord/voice/manager.py index 5499363..09d43bc 100644 --- a/litecord/voice/manager.py +++ b/litecord/voice/manager.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/litecord/voice/state.py b/litecord/voice/state.py index b3d8d31..b993be7 100644 --- a/litecord/voice/state.py +++ b/litecord/voice/state.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/manage.py b/manage.py index 454f304..5a2a2de 100755 --- a/manage.py +++ b/manage.py @@ -2,7 +2,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/manage/__init__.py b/manage/__init__.py index d21f555..3878d03 100644 --- a/manage/__init__.py +++ b/manage/__init__.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/manage/cmd/invites.py b/manage/cmd/invites.py index 05b3edc..7f354b0 100644 --- a/manage/cmd/invites.py +++ b/manage/cmd/invites.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/manage/cmd/migration/__init__.py b/manage/cmd/migration/__init__.py index 6ceffc6..5d1db64 100644 --- a/manage/cmd/migration/__init__.py +++ b/manage/cmd/migration/__init__.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/manage/cmd/migration/command.py b/manage/cmd/migration/command.py index 9151d51..87ebd0b 100644 --- a/manage/cmd/migration/command.py +++ b/manage/cmd/migration/command.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/manage/cmd/users.py b/manage/cmd/users.py index e54ee87..87d3fdd 100644 --- a/manage/cmd/users.py +++ b/manage/cmd/users.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -130,6 +130,23 @@ async def set_max_concurrency(ctx, args): print(f"OK: set max_concurrency={args.max_concurrency} for {args.user_id}") +async def addbot(ctx, args): + uid, _ = await create_user(args.username, args.email, args.password) + + await ctx.db.execute( + """ + UPDATE users + SET bot=True + WHERE id = $1 + """, + uid, + ) + + args.user_id = uid + + return await generate_bot_token(ctx, args) + + async def set_flag(ctx, args): """Setting a 'staff' flag gives the user access to the Admin API. Beware of that. @@ -174,7 +191,8 @@ async def generate_bot_token(ctx, args): ) if not password_hash: - return print("cannot find a bot with specified id") + print("cannot find a bot with specified id") + return 1 print(make_token(args.user_id, password_hash)) @@ -245,6 +263,14 @@ def setup(subparser): ) set_max_concurrency_parser.set_defaults(func=set_max_concurrency) + addbot_parser = subparser.add_parser("addbot", help="create a bot") + + addbot_parser.add_argument("username", help="username of the bot") + addbot_parser.add_argument("email", help="email of the bot") + addbot_parser.add_argument("password", help="password of the bot") + + addbot_parser.set_defaults(func=addbot) + setflag_parser = subparser.add_parser( "setflag", help="set a flag for a user", description=set_flag.__doc__ ) diff --git a/manage/main.py b/manage/main.py index 2008237..457673f 100644 --- a/manage/main.py +++ b/manage/main.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -93,7 +93,7 @@ def main(config): async def _ctx_wrapper(fake_app, args): app = fake_app.make_app() async with app.app_context(): - await args.func(fake_app, args) + return await args.func(fake_app, args) try: if len(argv) < 2: @@ -107,8 +107,9 @@ def main(config): init_app_managers(app, init_voice=False) args = parser.parse_args() - loop.run_until_complete(_ctx_wrapper(app, args)) + return loop.run_until_complete(_ctx_wrapper(app, args)) except Exception: log.exception("error while running command") + return 1 finally: loop.run_until_complete(app.db.close()) diff --git a/poetry.lock b/poetry.lock index dac5df5..aa343ef 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,6 +1,6 @@ [[package]] name = "aiofiles" -version = "0.7.0" +version = "0.8.0" description = "File support for asyncio." category = "main" optional = false @@ -8,61 +8,73 @@ python-versions = ">=3.6,<4.0" [[package]] name = "aiohttp" -version = "3.7.4.post0" +version = "3.8.1" description = "Async http client/server framework (asyncio)" category = "main" optional = false python-versions = ">=3.6" [package.dependencies] -async-timeout = ">=3.0,<4.0" +aiosignal = ">=1.1.2" +async-timeout = ">=4.0.0a3,<5.0" attrs = ">=17.3.0" -chardet = ">=2.0,<5.0" +charset-normalizer = ">=2.0,<3.0" +frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" -typing-extensions = ">=3.6.5" yarl = ">=1.0,<2.0" [package.extras] -speedups = ["aiodns", "brotlipy", "cchardet"] +speedups = ["cchardet", "brotli", "aiodns"] + +[[package]] +name = "aiosignal" +version = "1.2.0" +description = "aiosignal: a list of registered asynchronous callbacks" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +frozenlist = ">=1.1.0" [[package]] name = "async-timeout" -version = "3.0.1" +version = "4.0.2" description = "Timeout context manager for asyncio programs" category = "main" optional = false -python-versions = ">=3.5.3" +python-versions = ">=3.6" [[package]] name = "asyncpg" -version = "0.24.0" +version = "0.26.0" description = "An asyncio PostgreSQL driver" category = "main" optional = false python-versions = ">=3.6.0" [package.extras] -dev = ["Cython (>=0.29.24,<0.30.0)", "pytest (>=6.0)", "Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "pycodestyle (>=2.7.0,<2.8.0)", "flake8 (>=3.9.2,<3.10.0)", "uvloop (>=0.15.3)"] -docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)"] -test = ["pycodestyle (>=2.7.0,<2.8.0)", "flake8 (>=3.9.2,<3.10.0)", "uvloop (>=0.15.3)"] +test = ["uvloop (>=0.15.3)", "flake8 (>=3.9.2,<3.10.0)", "pycodestyle (>=2.7.0,<2.8.0)"] +docs = ["sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "Sphinx (>=4.1.2,<4.2.0)"] +dev = ["uvloop (>=0.15.3)", "flake8 (>=3.9.2,<3.10.0)", "pycodestyle (>=2.7.0,<2.8.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "Sphinx (>=4.1.2,<4.2.0)", "pytest (>=6.0)", "Cython (>=0.29.24,<0.30.0)"] [[package]] name = "attrs" -version = "21.2.0" +version = "22.1.0" description = "Classes Without Boilerplate" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.5" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] -docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] +tests_no_zope = ["cloudpickle", "pytest-mypy-plugins", "mypy (>=0.900,!=0.940)", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"] +tests = ["cloudpickle", "zope.interface", "pytest-mypy-plugins", "mypy (>=0.900,!=0.940)", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"] +docs = ["sphinx-notfound-page", "zope.interface", "sphinx", "furo"] +dev = ["cloudpickle", "pre-commit", "sphinx-notfound-page", "sphinx", "furo", "zope.interface", "pytest-mypy-plugins", "mypy (>=0.900,!=0.940)", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"] [[package]] name = "bcrypt" -version = "3.2.0" +version = "3.2.2" description = "Modern password hashing for your software and your servers" category = "main" optional = false @@ -70,7 +82,6 @@ python-versions = ">=3.6" [package.dependencies] cffi = ">=1.1" -six = ">=1.4.1" [package.extras] tests = ["pytest (>=3.2.1,!=3.3.0)"] @@ -78,11 +89,11 @@ typecheck = ["mypy"] [[package]] name = "blinker" -version = "1.4" +version = "1.5" description = "Fast, simple object-to-object and broadcast signaling" category = "main" optional = false -python-versions = "*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "cerberus" @@ -94,7 +105,7 @@ python-versions = ">=2.7" [[package]] name = "cffi" -version = "1.14.6" +version = "1.15.1" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false @@ -104,27 +115,30 @@ python-versions = "*" pycparser = "*" [[package]] -name = "chardet" -version = "4.0.0" -description = "Universal encoding detector for Python 2 and 3" +name = "charset-normalizer" +version = "2.1.0" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6.0" + +[package.extras] +unicode_backport = ["unicodedata2"] [[package]] name = "click" -version = "8.0.1" +version = "8.1.3" description = "Composable command line interface toolkit" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "colorama" -version = "0.4.4" +version = "0.4.5" description = "Cross-platform colored terminal text." category = "main" optional = false @@ -138,9 +152,17 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "frozenlist" +version = "1.3.1" +description = "A list-like structure which implements collections.abc.MutableSequence" +category = "main" +optional = false +python-versions = ">=3.7" + [[package]] name = "h11" -version = "0.12.0" +version = "0.13.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" category = "main" optional = false @@ -148,7 +170,7 @@ python-versions = ">=3.6" [[package]] name = "h2" -version = "4.0.0" +version = "4.1.0" description = "HTTP/2 State-Machine based protocol implementation" category = "main" optional = false @@ -168,8 +190,8 @@ python-versions = ">=3.6.1" [[package]] name = "hypercorn" -version = "0.11.2" -description = "A ASGI Server based on Hyper libraries and inspired by Gunicorn." +version = "0.13.2" +description = "A ASGI Server based on Hyper libraries and inspired by Gunicorn" category = "main" optional = false python-versions = ">=3.7" @@ -183,7 +205,6 @@ wsproto = ">=0.14.0" [package.extras] h3 = ["aioquic (>=0.9.0,<1.0)"] -tests = ["hypothesis", "mock", "pytest", "pytest-asyncio", "pytest-cov", "pytest-trio", "trio"] trio = ["trio (>=0.11.0)"] uvloop = ["uvloop"] @@ -197,27 +218,43 @@ python-versions = ">=3.6.1" [[package]] name = "idna" -version = "3.2" +version = "3.3" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false python-versions = ">=3.5" [[package]] -name = "itsdangerous" -version = "1.1.0" -description = "Various helpers to pass data to untrusted environments and back." +name = "importlib-metadata" +version = "4.12.0" +description = "Read metadata from Python packages" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.7" + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +testing = ["importlib-resources (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-black (>=0.3.7)", "pytest-perf (>=0.9.2)", "flufl.flake8", "pyfakefs", "packaging", "pytest-enabler (>=1.3)", "pytest-cov", "pytest-flake8", "pytest-checkdocs (>=2.4)", "pytest (>=6)"] +perf = ["ipython"] +docs = ["rst.linker (>=1.9)", "jaraco.packaging (>=9)", "sphinx"] + +[[package]] +name = "itsdangerous" +version = "2.1.2" +description = "Safely pass data to untrusted environments and back." +category = "main" +optional = false +python-versions = ">=3.7" [[package]] name = "jinja2" -version = "3.0.1" +version = "3.1.2" description = "A very fast and expressive template engine." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] MarkupSafe = ">=2.0" @@ -246,27 +283,31 @@ zmq = ["pyzmq"] [[package]] name = "markupsafe" -version = "2.0.1" +version = "2.1.1" description = "Safely add untrusted strings to HTML/XML markup." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "multidict" -version = "5.1.0" +version = "6.0.2" description = "multidict implementation" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "pillow" -version = "8.3.2" +version = "9.2.0" description = "Python Imaging Library (Fork)" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" + +[package.extras] +tests = ["pytest-timeout", "pytest-cov", "pytest", "pyroma", "packaging", "olefile", "markdown2", "defusedxml", "coverage", "check-manifest"] +docs = ["sphinxext-opengraph", "sphinx-removed-in", "sphinx-issues (>=3.0.1)", "sphinx-copybutton", "sphinx (>=2.4)", "olefile", "furo"] [[package]] name = "priority" @@ -278,7 +319,7 @@ python-versions = ">=3.6.1" [[package]] name = "pycparser" -version = "2.20" +version = "2.21" description = "C parser in Python" category = "main" optional = false @@ -286,32 +327,26 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "quart" -version = "0.15.1" +version = "0.18.0" description = "A Python ASGI web microframework with the same API as Flask" category = "main" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.7" [package.dependencies] aiofiles = "*" blinker = "*" click = "*" hypercorn = ">=0.11.2" +importlib_metadata = {version = "*", markers = "python_version < \"3.10\""} itsdangerous = "*" jinja2 = "*" -toml = "*" -werkzeug = ">=2.0.0" +markupsafe = "*" +werkzeug = ">=2.2.0" [package.extras] dotenv = ["python-dotenv"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +docs = ["pydata-sphinx-theme"] [[package]] name = "toml" @@ -321,17 +356,9 @@ category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -[[package]] -name = "typing-extensions" -version = "3.10.0.2" -description = "Backported and Experimental Type Hints for Python 3.5+" -category = "main" -optional = false -python-versions = "*" - [[package]] name = "websockets" -version = "10.0" +version = "10.3" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" category = "main" optional = false @@ -339,11 +366,14 @@ python-versions = ">=3.7" [[package]] name = "werkzeug" -version = "2.0.1" +version = "2.2.2" description = "The comprehensive WSGI web application library." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" + +[package.dependencies] +MarkupSafe = ">=2.1.1" [package.extras] watchdog = ["watchdog"] @@ -365,34 +395,46 @@ resolved_reference = "7390e1747d9c6a1d1bf571b7a2b419b09728a654" [[package]] name = "wsproto" -version = "1.0.0" +version = "1.1.0" description = "WebSockets state-machine based protocol implementation" category = "main" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.7.0" [package.dependencies] h11 = ">=0.9.0,<1" [[package]] name = "yarl" -version = "1.6.3" +version = "1.8.1" description = "Yet another URL library" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] idna = ">=2.0" multidict = ">=4.0" +[[package]] +name = "zipp" +version = "3.8.1" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +testing = ["pytest-mypy (>=0.9.1)", "pytest-black (>=0.3.7)", "func-timeout", "jaraco.itertools", "pytest-enabler (>=1.3)", "pytest-cov", "pytest-flake8", "pytest-checkdocs (>=2.4)", "pytest (>=6)"] +docs = ["jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "jaraco.packaging (>=9)", "sphinx"] + [[package]] name = "zstandard" -version = "0.15.2" +version = "0.18.0" description = "Zstandard bindings for Python" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [package.dependencies] cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\""} @@ -403,473 +445,128 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "e07bedf6968bdb2112e351624b975a2ea8ababdad1693ad6a40e664953f77c19" +content-hash = "2ad3557d85930df2e93df80ce9381b1bd4e055f9adcaf17b14a3e33a08978cf5" [metadata.files] aiofiles = [ - {file = "aiofiles-0.7.0-py3-none-any.whl", hash = "sha256:c67a6823b5f23fcab0a2595a289cec7d8c863ffcb4322fb8cd6b90400aedfdbc"}, - {file = "aiofiles-0.7.0.tar.gz", hash = "sha256:a1c4fc9b2ff81568c83e21392a82f344ea9d23da906e4f6a52662764545e19d4"}, -] -aiohttp = [ - {file = "aiohttp-3.7.4.post0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:3cf75f7cdc2397ed4442594b935a11ed5569961333d49b7539ea741be2cc79d5"}, - {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4b302b45040890cea949ad092479e01ba25911a15e648429c7c5aae9650c67a8"}, - {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95"}, - {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:393f389841e8f2dfc86f774ad22f00923fdee66d238af89b70ea314c4aefd290"}, - {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:c6e9dcb4cb338d91a73f178d866d051efe7c62a7166653a91e7d9fb18274058f"}, - {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:5df68496d19f849921f05f14f31bd6ef53ad4b00245da3195048c69934521809"}, - {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:0563c1b3826945eecd62186f3f5c7d31abb7391fedc893b7e2b26303b5a9f3fe"}, - {file = "aiohttp-3.7.4.post0-cp36-cp36m-win32.whl", hash = "sha256:3d78619672183be860b96ed96f533046ec97ca067fd46ac1f6a09cd9b7484287"}, - {file = "aiohttp-3.7.4.post0-cp36-cp36m-win_amd64.whl", hash = "sha256:f705e12750171c0ab4ef2a3c76b9a4024a62c4103e3a55dd6f99265b9bc6fcfc"}, - {file = "aiohttp-3.7.4.post0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:230a8f7e24298dea47659251abc0fd8b3c4e38a664c59d4b89cca7f6c09c9e87"}, - {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2e19413bf84934d651344783c9f5e22dee452e251cfd220ebadbed2d9931dbf0"}, - {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e4b2b334e68b18ac9817d828ba44d8fcb391f6acb398bcc5062b14b2cbeac970"}, - {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:d012ad7911653a906425d8473a1465caa9f8dea7fcf07b6d870397b774ea7c0f"}, - {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:40eced07f07a9e60e825554a31f923e8d3997cfc7fb31dbc1328c70826e04cde"}, - {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:209b4a8ee987eccc91e2bd3ac36adee0e53a5970b8ac52c273f7f8fd4872c94c"}, - {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:14762875b22d0055f05d12abc7f7d61d5fd4fe4642ce1a249abdf8c700bf1fd8"}, - {file = "aiohttp-3.7.4.post0-cp37-cp37m-win32.whl", hash = "sha256:7615dab56bb07bff74bc865307aeb89a8bfd9941d2ef9d817b9436da3a0ea54f"}, - {file = "aiohttp-3.7.4.post0-cp37-cp37m-win_amd64.whl", hash = "sha256:d9e13b33afd39ddeb377eff2c1c4f00544e191e1d1dee5b6c51ddee8ea6f0cf5"}, - {file = "aiohttp-3.7.4.post0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:547da6cacac20666422d4882cfcd51298d45f7ccb60a04ec27424d2f36ba3eaf"}, - {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:af9aa9ef5ba1fd5b8c948bb11f44891968ab30356d65fd0cc6707d989cd521df"}, - {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:64322071e046020e8797117b3658b9c2f80e3267daec409b350b6a7a05041213"}, - {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:bb437315738aa441251214dad17428cafda9cdc9729499f1d6001748e1d432f4"}, - {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:e54962802d4b8b18b6207d4a927032826af39395a3bd9196a5af43fc4e60b009"}, - {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:a00bb73540af068ca7390e636c01cbc4f644961896fa9363154ff43fd37af2f5"}, - {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:79ebfc238612123a713a457d92afb4096e2148be17df6c50fb9bf7a81c2f8013"}, - {file = "aiohttp-3.7.4.post0-cp38-cp38-win32.whl", hash = "sha256:515dfef7f869a0feb2afee66b957cc7bbe9ad0cdee45aec7fdc623f4ecd4fb16"}, - {file = "aiohttp-3.7.4.post0-cp38-cp38-win_amd64.whl", hash = "sha256:114b281e4d68302a324dd33abb04778e8557d88947875cbf4e842c2c01a030c5"}, - {file = "aiohttp-3.7.4.post0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:7b18b97cf8ee5452fa5f4e3af95d01d84d86d32c5e2bfa260cf041749d66360b"}, - {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:15492a6368d985b76a2a5fdd2166cddfea5d24e69eefed4630cbaae5c81d89bd"}, - {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bdb230b4943891321e06fc7def63c7aace16095be7d9cf3b1e01be2f10fba439"}, - {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:cffe3ab27871bc3ea47df5d8f7013945712c46a3cc5a95b6bee15887f1675c22"}, - {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a"}, - {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:a5ca29ee66f8343ed336816c553e82d6cade48a3ad702b9ffa6125d187e2dedb"}, - {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:17c073de315745a1510393a96e680d20af8e67e324f70b42accbd4cb3315c9fb"}, - {file = "aiohttp-3.7.4.post0-cp39-cp39-win32.whl", hash = "sha256:932bb1ea39a54e9ea27fc9232163059a0b8855256f4052e776357ad9add6f1c9"}, - {file = "aiohttp-3.7.4.post0-cp39-cp39-win_amd64.whl", hash = "sha256:02f46fc0e3c5ac58b80d4d56eb0a7c7d97fcef69ace9326289fb9f1955e65cfe"}, - {file = "aiohttp-3.7.4.post0.tar.gz", hash = "sha256:493d3299ebe5f5a7c66b9819eacdcfbbaaf1a8e84911ddffcdc48888497afecf"}, -] -async-timeout = [ - {file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"}, - {file = "async_timeout-3.0.1-py3-none-any.whl", hash = "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"}, -] -asyncpg = [ - {file = "asyncpg-0.24.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c4fc0205fe4ddd5aeb3dfdc0f7bafd43411181e1f5650189608e5971cceacff1"}, - {file = "asyncpg-0.24.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a7095890c96ba36f9f668eb552bb020dddb44f8e73e932f8573efc613ee83843"}, - {file = "asyncpg-0.24.0-cp310-cp310-win_amd64.whl", hash = "sha256:8ff5073d4b654e34bd5eaadc01dc4d68b8a9609084d835acd364cd934190a08d"}, - {file = "asyncpg-0.24.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e36c6806883786b19551bb70a4882561f31135dc8105a59662e0376cf5b2cbc5"}, - {file = "asyncpg-0.24.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ddffcb85227bf39cd1bedd4603e0082b243cf3b14ced64dce506a15b05232b83"}, - {file = "asyncpg-0.24.0-cp37-cp37m-win_amd64.whl", hash = "sha256:41704c561d354bef01353835a7846e5606faabbeb846214dfcf666cf53319f18"}, - {file = "asyncpg-0.24.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:29ef6ae0a617fc13cc2ac5dc8e9b367bb83cba220614b437af9b67766f4b6b20"}, - {file = "asyncpg-0.24.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eed43abc6ccf1dc02e0d0efc06ce46a411362f3358847c6b0ec9a43426f91ece"}, - {file = "asyncpg-0.24.0-cp38-cp38-win_amd64.whl", hash = "sha256:129d501f3d30616afd51eb8d3142ef51ba05374256bd5834cec3ef4956a9b317"}, - {file = "asyncpg-0.24.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a458fc69051fbb67d995fdda46d75a012b5d6200f91e17d23d4751482640ed4c"}, - {file = "asyncpg-0.24.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:556b0e92e2b75dc028b3c4bc9bd5162ddf0053b856437cf1f04c97f9c6837d03"}, - {file = "asyncpg-0.24.0-cp39-cp39-win_amd64.whl", hash = "sha256:a738f4807c853623d3f93f0fea11f61be6b0e5ca16ea8aeb42c2c7ee742aa853"}, - {file = "asyncpg-0.24.0.tar.gz", hash = "sha256:dd2fa063c3344823487d9ddccb40802f02622ddf8bf8a6cc53885ee7a2c1c0c6"}, -] -attrs = [ - {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, - {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, -] -bcrypt = [ - {file = "bcrypt-3.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6"}, - {file = "bcrypt-3.2.0-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:63d4e3ff96188e5898779b6057878fecf3f11cfe6ec3b313ea09955d587ec7a7"}, - {file = "bcrypt-3.2.0-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:cd1ea2ff3038509ea95f687256c46b79f5fc382ad0aa3664d200047546d511d1"}, - {file = "bcrypt-3.2.0-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:cdcdcb3972027f83fe24a48b1e90ea4b584d35f1cc279d76de6fc4b13376239d"}, - {file = "bcrypt-3.2.0-cp36-abi3-win32.whl", hash = "sha256:a67fb841b35c28a59cebed05fbd3e80eea26e6d75851f0574a9273c80f3e9b55"}, - {file = "bcrypt-3.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:81fec756feff5b6818ea7ab031205e1d323d8943d237303baca2c5f9c7846f34"}, - {file = "bcrypt-3.2.0.tar.gz", hash = "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29"}, -] -blinker = [ - {file = "blinker-1.4.tar.gz", hash = "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6"}, -] -cerberus = [ - {file = "Cerberus-1.3.4.tar.gz", hash = "sha256:d1b21b3954b2498d9a79edf16b3170a3ac1021df88d197dc2ce5928ba519237c"}, -] -cffi = [ - {file = "cffi-1.14.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:22b9c3c320171c108e903d61a3723b51e37aaa8c81255b5e7ce102775bd01e2c"}, - {file = "cffi-1.14.6-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f0c5d1acbfca6ebdd6b1e3eded8d261affb6ddcf2186205518f1428b8569bb99"}, - {file = "cffi-1.14.6-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99f27fefe34c37ba9875f224a8f36e31d744d8083e00f520f133cab79ad5e819"}, - {file = "cffi-1.14.6-cp27-cp27m-win32.whl", hash = "sha256:55af55e32ae468e9946f741a5d51f9896da6b9bf0bbdd326843fec05c730eb20"}, - {file = "cffi-1.14.6-cp27-cp27m-win_amd64.whl", hash = "sha256:7bcac9a2b4fdbed2c16fa5681356d7121ecabf041f18d97ed5b8e0dd38a80224"}, - {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ed38b924ce794e505647f7c331b22a693bee1538fdf46b0222c4717b42f744e7"}, - {file = "cffi-1.14.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e22dcb48709fc51a7b58a927391b23ab37eb3737a98ac4338e2448bef8559b33"}, - {file = "cffi-1.14.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e8c6a99be100371dbb046880e7a282152aa5d6127ae01783e37662ef73850d8f"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:19ca0dbdeda3b2615421d54bef8985f72af6e0c47082a8d26122adac81a95872"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d950695ae4381ecd856bcaf2b1e866720e4ab9a1498cba61c602e56630ca7195"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9dc245e3ac69c92ee4c167fbdd7428ec1956d4e754223124991ef29eb57a09d"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8661b2ce9694ca01c529bfa204dbb144b275a31685a075ce123f12331be790b"}, - {file = "cffi-1.14.6-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b315d709717a99f4b27b59b021e6207c64620790ca3e0bde636a6c7f14618abb"}, - {file = "cffi-1.14.6-cp36-cp36m-win32.whl", hash = "sha256:80b06212075346b5546b0417b9f2bf467fea3bfe7352f781ffc05a8ab24ba14a"}, - {file = "cffi-1.14.6-cp36-cp36m-win_amd64.whl", hash = "sha256:a9da7010cec5a12193d1af9872a00888f396aba3dc79186604a09ea3ee7c029e"}, - {file = "cffi-1.14.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4373612d59c404baeb7cbd788a18b2b2a8331abcc84c3ba40051fcd18b17a4d5"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f10afb1004f102c7868ebfe91c28f4a712227fe4cb24974350ace1f90e1febbf"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fd4305f86f53dfd8cd3522269ed7fc34856a8ee3709a5e28b2836b2db9d4cd69"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d6169cb3c6c2ad50db5b868db6491a790300ade1ed5d1da29289d73bbe40b56"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d4b68e216fc65e9fe4f524c177b54964af043dde734807586cf5435af84045c"}, - {file = "cffi-1.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33791e8a2dc2953f28b8d8d300dde42dd929ac28f974c4b4c6272cb2955cb762"}, - {file = "cffi-1.14.6-cp37-cp37m-win32.whl", hash = "sha256:0c0591bee64e438883b0c92a7bed78f6290d40bf02e54c5bf0978eaf36061771"}, - {file = "cffi-1.14.6-cp37-cp37m-win_amd64.whl", hash = "sha256:8eb687582ed7cd8c4bdbff3df6c0da443eb89c3c72e6e5dcdd9c81729712791a"}, - {file = "cffi-1.14.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba6f2b3f452e150945d58f4badd92310449876c4c954836cfb1803bdd7b422f0"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:64fda793737bc4037521d4899be780534b9aea552eb673b9833b01f945904c2e"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9f3e33c28cd39d1b655ed1ba7247133b6f7fc16fa16887b120c0c670e35ce346"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26bb2549b72708c833f5abe62b756176022a7b9a7f689b571e74c8478ead51dc"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb687a11f0a7a1839719edd80f41e459cc5366857ecbed383ff376c4e3cc6afd"}, - {file = "cffi-1.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ad4d668a5c0645d281dcd17aff2be3212bc109b33814bbb15c4939f44181cc"}, - {file = "cffi-1.14.6-cp38-cp38-win32.whl", hash = "sha256:487d63e1454627c8e47dd230025780e91869cfba4c753a74fda196a1f6ad6548"}, - {file = "cffi-1.14.6-cp38-cp38-win_amd64.whl", hash = "sha256:c33d18eb6e6bc36f09d793c0dc58b0211fccc6ae5149b808da4a62660678b156"}, - {file = "cffi-1.14.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:06c54a68935738d206570b20da5ef2b6b6d92b38ef3ec45c5422c0ebaf338d4d"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:f174135f5609428cc6e1b9090f9268f5c8935fddb1b25ccb8255a2d50de6789e"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f3ebe6e73c319340830a9b2825d32eb6d8475c1dac020b4f0aa774ee3b898d1c"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d896becff2fa653dc4438b54a5a25a971d1f4110b32bd3068db3722c80202"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4922cd707b25e623b902c86188aca466d3620892db76c0bdd7b99a3d5e61d35f"}, - {file = "cffi-1.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9e005e9bd57bc987764c32a1bee4364c44fdc11a3cc20a40b93b444984f2b87"}, - {file = "cffi-1.14.6-cp39-cp39-win32.whl", hash = "sha256:eb9e2a346c5238a30a746893f23a9535e700f8192a68c07c0258e7ece6ff3728"}, - {file = "cffi-1.14.6-cp39-cp39-win_amd64.whl", hash = "sha256:818014c754cd3dba7229c0f5884396264d51ffb87ec86e927ef0be140bfdb0d2"}, - {file = "cffi-1.14.6.tar.gz", hash = "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd"}, -] -chardet = [ - {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, - {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, + {file = "aiofiles-0.8.0-py3-none-any.whl", hash = "sha256:7a973fc22b29e9962d0897805ace5856e6a566ab1f0c8e5c91ff6c866519c937"}, + {file = "aiofiles-0.8.0.tar.gz", hash = "sha256:8334f23235248a3b2e83b2c3a78a22674f39969b96397126cc93664d9a901e59"}, ] +aiohttp = [] +aiosignal = [] +async-timeout = [] +asyncpg = [] +attrs = [] +bcrypt = [] +blinker = [] +cerberus = [] +cffi = [] +charset-normalizer = [] click = [ - {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, - {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, ] colorama = [ - {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, - {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, -] -earl-etf = [ - {file = "earl-etf-2.1.2.tar.gz", hash = "sha256:f43cffbcf754e45f6716d82bb885c5072f3f8b16c1f1e26b46cb63f27e838640"}, - {file = "earl_etf-2.1.2-cp34-cp34m-win32.whl", hash = "sha256:d6f3e3bdbe2b74571f57b2c23f68233b464785ddf0c41870c3d8ff88db06b40e"}, - {file = "earl_etf-2.1.2-cp34-cp34m-win_amd64.whl", hash = "sha256:870b40778ef6f644d6568a5afd481ce53bc87cb21fd92bfcf5b6072ede8e3078"}, - {file = "earl_etf-2.1.2-cp35-cp35m-win32.whl", hash = "sha256:f6a77049a21ed04095ef64f7e39ed26a2a88c17fffaf361119cd739683d25d55"}, - {file = "earl_etf-2.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:46bea44c3a3bf3914b01eb6a3bd42e3fb6dee6f45d68372b1237a153bf9fe4fc"}, - {file = "earl_etf-2.1.2-cp36-cp36m-win32.whl", hash = "sha256:6e3595ca9642d33cc5644c923826271f960c7df567fdaf62b5b439a0a6a9b619"}, - {file = "earl_etf-2.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:52155ec379ec96560938f295bfa1f055743dc8be275423bdfebef14b16acfdab"}, + {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, + {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, ] +earl-etf = [] +frozenlist = [] h11 = [ - {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, - {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, + {file = "h11-0.13.0-py3-none-any.whl", hash = "sha256:8ddd78563b633ca55346c8cd41ec0af27d3c79931828beffb46ce70a379e7442"}, + {file = "h11-0.13.0.tar.gz", hash = "sha256:70813c1135087a248a4d38cc0e1a0181ffab2188141a93eaf567940c3957ff06"}, ] h2 = [ - {file = "h2-4.0.0-py3-none-any.whl", hash = "sha256:ac9e293a1990b339d5d71b19c5fe630e3dd4d768c620d1730d355485323f1b25"}, - {file = "h2-4.0.0.tar.gz", hash = "sha256:bb7ac7099dd67a857ed52c815a6192b6b1f5ba6b516237fc24a085341340593d"}, + {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, + {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, ] hpack = [ {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, ] hypercorn = [ - {file = "Hypercorn-0.11.2-py3-none-any.whl", hash = "sha256:8007c10f81566920f8ae12c0e26e146f94ca70506da964b5a727ad610aa1d821"}, - {file = "Hypercorn-0.11.2.tar.gz", hash = "sha256:5ba1e719c521080abd698ff5781a2331e34ef50fc1c89a50960538115a896a9a"}, + {file = "Hypercorn-0.13.2-py3-none-any.whl", hash = "sha256:ca18f91ab3fa823cbe9e949738f9f2cc07027cd647c80d8f93e4b1a2a175f112"}, + {file = "Hypercorn-0.13.2.tar.gz", hash = "sha256:6307be5cbdf6ba411967d4661202dc4f79bd511b5d318bc4eed88b09418427f8"}, ] hyperframe = [ {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, ] idna = [ - {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, - {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, ] +importlib-metadata = [] itsdangerous = [ - {file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"}, - {file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"}, + {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, + {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, ] jinja2 = [ - {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"}, - {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"}, -] -logbook = [ - {file = "Logbook-1.5.3-cp27-cp27m-win32.whl", hash = "sha256:56ee54c11df3377314cedcd6507638f015b4b88c0238c2e01b5eb44fd3a6ad1b"}, - {file = "Logbook-1.5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:2dc85f1510533fddb481e97677bb7bca913560862734c0b3b289bfed04f78c92"}, - {file = "Logbook-1.5.3-cp35-cp35m-win32.whl", hash = "sha256:94e2e11ff3c2304b0d09a36c6208e5ae756eb948b210e5cbd63cd8d27f911542"}, - {file = "Logbook-1.5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:97fee1bd9605f76335b169430ed65e15e457a844b2121bd1d90a08cf7e30aba0"}, - {file = "Logbook-1.5.3-cp36-cp36m-win32.whl", hash = "sha256:7c533eb728b3d220b1b5414ba4635292d149d79f74f6973b4aa744c850ca944a"}, - {file = "Logbook-1.5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:e18f7422214b1cf0240c56f884fd9c9b4ff9d0da2eabca9abccba56df7222f66"}, - {file = "Logbook-1.5.3-cp37-cp37m-win32.whl", hash = "sha256:8f76a2e7b1f72595f753228732f81ce342caf03babc3fed6bbdcf366f2f20f18"}, - {file = "Logbook-1.5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0cf2cdbfb65a03b5987d19109dacad13417809dcf697f66e1a7084fb21744ea9"}, - {file = "Logbook-1.5.3.tar.gz", hash = "sha256:66f454ada0f56eae43066f604a222b09893f98c1adc18df169710761b8f32fe8"}, + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, ] +logbook = [] markupsafe = [ - {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, - {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, -] -multidict = [ - {file = "multidict-5.1.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:b7993704f1a4b204e71debe6095150d43b2ee6150fa4f44d6d966ec356a8d61f"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:9dd6e9b1a913d096ac95d0399bd737e00f2af1e1594a787e00f7975778c8b2bf"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab820665e67373de5802acae069a6a05567ae234ddb129f31d290fc3d1aa56d"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:9436dc58c123f07b230383083855593550c4d301d2532045a17ccf6eca505f6d"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:830f57206cc96ed0ccf68304141fec9481a096c4d2e2831f311bde1c404401da"}, - {file = "multidict-5.1.0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:2e68965192c4ea61fff1b81c14ff712fc7dc15d2bd120602e4a3494ea6584224"}, - {file = "multidict-5.1.0-cp36-cp36m-win32.whl", hash = "sha256:2f1a132f1c88724674271d636e6b7351477c27722f2ed789f719f9e3545a3d26"}, - {file = "multidict-5.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:3a4f32116f8f72ecf2a29dabfb27b23ab7cdc0ba807e8459e59a93a9be9506f6"}, - {file = "multidict-5.1.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:46c73e09ad374a6d876c599f2328161bcd95e280f84d2060cf57991dec5cfe76"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:018132dbd8688c7a69ad89c4a3f39ea2f9f33302ebe567a879da8f4ca73f0d0a"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:4b186eb7d6ae7c06eb4392411189469e6a820da81447f46c0072a41c748ab73f"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3a041b76d13706b7fff23b9fc83117c7b8fe8d5fe9e6be45eee72b9baa75f348"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:051012ccee979b2b06be928a6150d237aec75dd6bf2d1eeeb190baf2b05abc93"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:6a4d5ce640e37b0efcc8441caeea8f43a06addace2335bd11151bc02d2ee31f9"}, - {file = "multidict-5.1.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:5cf3443199b83ed9e955f511b5b241fd3ae004e3cb81c58ec10f4fe47c7dce37"}, - {file = "multidict-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:f200755768dc19c6f4e2b672421e0ebb3dd54c38d5a4f262b872d8cfcc9e93b5"}, - {file = "multidict-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:05c20b68e512166fddba59a918773ba002fdd77800cad9f55b59790030bab632"}, - {file = "multidict-5.1.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:54fd1e83a184e19c598d5e70ba508196fd0bbdd676ce159feb412a4a6664f952"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:0e3c84e6c67eba89c2dbcee08504ba8644ab4284863452450520dad8f1e89b79"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:dc862056f76443a0db4509116c5cd480fe1b6a2d45512a653f9a855cc0517456"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:0e929169f9c090dae0646a011c8b058e5e5fb391466016b39d21745b48817fd7"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:d81eddcb12d608cc08081fa88d046c78afb1bf8107e6feab5d43503fea74a635"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:585fd452dd7782130d112f7ddf3473ffdd521414674c33876187e101b588738a"}, - {file = "multidict-5.1.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:37e5438e1c78931df5d3c0c78ae049092877e5e9c02dd1ff5abb9cf27a5914ea"}, - {file = "multidict-5.1.0-cp38-cp38-win32.whl", hash = "sha256:07b42215124aedecc6083f1ce6b7e5ec5b50047afa701f3442054373a6deb656"}, - {file = "multidict-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:929006d3c2d923788ba153ad0de8ed2e5ed39fdbe8e7be21e2f22ed06c6783d3"}, - {file = "multidict-5.1.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b797515be8743b771aa868f83563f789bbd4b236659ba52243b735d80b29ed93"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d5c65bdf4484872c4af3150aeebe101ba560dcfb34488d9a8ff8dbcd21079647"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b47a43177a5e65b771b80db71e7be76c0ba23cc8aa73eeeb089ed5219cdbe27d"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:806068d4f86cb06af37cd65821554f98240a19ce646d3cd24e1c33587f313eb8"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:46dd362c2f045095c920162e9307de5ffd0a1bfbba0a6e990b344366f55a30c1"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:ace010325c787c378afd7f7c1ac66b26313b3344628652eacd149bdd23c68841"}, - {file = "multidict-5.1.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:ecc771ab628ea281517e24fd2c52e8f31c41e66652d07599ad8818abaad38cda"}, - {file = "multidict-5.1.0-cp39-cp39-win32.whl", hash = "sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80"}, - {file = "multidict-5.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7df80d07818b385f3129180369079bd6934cf70469f99daaebfac89dca288359"}, - {file = "multidict-5.1.0.tar.gz", hash = "sha256:25b4e5f22d3a37ddf3effc0710ba692cfc792c2b9edfb9c05aefe823256e84d5"}, -] -pillow = [ - {file = "Pillow-8.3.2-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:c691b26283c3a31594683217d746f1dad59a7ae1d4cfc24626d7a064a11197d4"}, - {file = "Pillow-8.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f514c2717012859ccb349c97862568fdc0479aad85b0270d6b5a6509dbc142e2"}, - {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be25cb93442c6d2f8702c599b51184bd3ccd83adebd08886b682173e09ef0c3f"}, - {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d675a876b295afa114ca8bf42d7f86b5fb1298e1b6bb9a24405a3f6c8338811c"}, - {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59697568a0455764a094585b2551fd76bfd6b959c9f92d4bdec9d0e14616303a"}, - {file = "Pillow-8.3.2-cp310-cp310-win32.whl", hash = "sha256:2d5e9dc0bf1b5d9048a94c48d0813b6c96fccfa4ccf276d9c36308840f40c228"}, - {file = "Pillow-8.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:11c27e74bab423eb3c9232d97553111cc0be81b74b47165f07ebfdd29d825875"}, - {file = "Pillow-8.3.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:11eb7f98165d56042545c9e6db3ce394ed8b45089a67124298f0473b29cb60b2"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f23b2d3079522fdf3c09de6517f625f7a964f916c956527bed805ac043799b8"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19ec4cfe4b961edc249b0e04b5618666c23a83bc35842dea2bfd5dfa0157f81b"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5a31c07cea5edbaeb4bdba6f2b87db7d3dc0f446f379d907e51cc70ea375629"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15ccb81a6ffc57ea0137f9f3ac2737ffa1d11f786244d719639df17476d399a7"}, - {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8f284dc1695caf71a74f24993b7c7473d77bc760be45f776a2c2f4e04c170550"}, - {file = "Pillow-8.3.2-cp36-cp36m-win32.whl", hash = "sha256:4abc247b31a98f29e5224f2d31ef15f86a71f79c7f4d2ac345a5d551d6393073"}, - {file = "Pillow-8.3.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a048dad5ed6ad1fad338c02c609b862dfaa921fcd065d747194a6805f91f2196"}, - {file = "Pillow-8.3.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:06d1adaa284696785375fa80a6a8eb309be722cf4ef8949518beb34487a3df71"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd24054aaf21e70a51e2a2a5ed1183560d3a69e6f9594a4bfe360a46f94eba83"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a330bf7014ee034046db43ccbb05c766aa9e70b8d6c5260bfc38d73103b0ba"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13654b521fb98abdecec105ea3fb5ba863d1548c9b58831dd5105bb3873569f1"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1bd983c565f92779be456ece2479840ec39d386007cd4ae83382646293d681b"}, - {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4326ea1e2722f3dc00ed77c36d3b5354b8fb7399fb59230249ea6d59cbed90da"}, - {file = "Pillow-8.3.2-cp37-cp37m-win32.whl", hash = "sha256:085a90a99404b859a4b6c3daa42afde17cb3ad3115e44a75f0d7b4a32f06a6c9"}, - {file = "Pillow-8.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:18a07a683805d32826c09acfce44a90bf474e6a66ce482b1c7fcd3757d588df3"}, - {file = "Pillow-8.3.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4e59e99fd680e2b8b11bbd463f3c9450ab799305d5f2bafb74fefba6ac058616"}, - {file = "Pillow-8.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4d89a2e9219a526401015153c0e9dd48319ea6ab9fe3b066a20aa9aee23d9fd3"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fd98c8294f57636084f4b076b75f86c57b2a63a8410c0cd172bc93695ee979"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b11c9d310a3522b0fd3c35667914271f570576a0e387701f370eb39d45f08a4"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0412516dcc9de9b0a1e0ae25a280015809de8270f134cc2c1e32c4eeb397cf30"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bcb04ff12e79b28be6c9988f275e7ab69f01cc2ba319fb3114f87817bb7c74b6"}, - {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0b9911ec70731711c3b6ebcde26caea620cbdd9dcb73c67b0730c8817f24711b"}, - {file = "Pillow-8.3.2-cp38-cp38-win32.whl", hash = "sha256:ce2e5e04bb86da6187f96d7bab3f93a7877830981b37f0287dd6479e27a10341"}, - {file = "Pillow-8.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:35d27687f027ad25a8d0ef45dd5208ef044c588003cdcedf05afb00dbc5c2deb"}, - {file = "Pillow-8.3.2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:04835e68ef12904bc3e1fd002b33eea0779320d4346082bd5b24bec12ad9c3e9"}, - {file = "Pillow-8.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10e00f7336780ca7d3653cf3ac26f068fa11b5a96894ea29a64d3dc4b810d630"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cde7a4d3687f21cffdf5bb171172070bb95e02af448c4c8b2f223d783214056"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c3ff00110835bdda2b1e2b07f4a2548a39744bb7de5946dc8e95517c4fb2ca6"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35d409030bf3bd05fa66fb5fdedc39c521b397f61ad04309c90444e893d05f7d"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bff50ba9891be0a004ef48828e012babaaf7da204d81ab9be37480b9020a82b"}, - {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7dbfbc0020aa1d9bc1b0b8bcf255a7d73f4ad0336f8fd2533fcc54a4ccfb9441"}, - {file = "Pillow-8.3.2-cp39-cp39-win32.whl", hash = "sha256:963ebdc5365d748185fdb06daf2ac758116deecb2277ec5ae98139f93844bc09"}, - {file = "Pillow-8.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:cc9d0dec711c914ed500f1d0d3822868760954dce98dfb0b7382a854aee55d19"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2c661542c6f71dfd9dc82d9d29a8386287e82813b0375b3a02983feac69ef864"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:548794f99ff52a73a156771a0402f5e1c35285bd981046a502d7e4793e8facaa"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8b68f565a4175e12e68ca900af8910e8fe48aaa48fd3ca853494f384e11c8bcd"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:838eb85de6d9307c19c655c726f8d13b8b646f144ca6b3771fa62b711ebf7624"}, - {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:feb5db446e96bfecfec078b943cc07744cc759893cef045aa8b8b6d6aaa8274e"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:fc0db32f7223b094964e71729c0361f93db43664dd1ec86d3df217853cedda87"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd4fd83aa912d7b89b4b4a1580d30e2a4242f3936882a3f433586e5ab97ed0d5"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d0c8ebbfd439c37624db98f3877d9ed12c137cadd99dde2d2eae0dab0bbfc355"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cb3dd7f23b044b0737317f892d399f9e2f0b3a02b22b2c692851fb8120d82c6"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a66566f8a22561fc1a88dc87606c69b84fa9ce724f99522cf922c801ec68f5c1"}, - {file = "Pillow-8.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ce651ca46d0202c302a535d3047c55a0131a720cf554a578fc1b8a2aff0e7d96"}, - {file = "Pillow-8.3.2.tar.gz", hash = "sha256:dde3f3ed8d00c72631bc19cbfff8ad3b6215062a5eed402381ad365f82f0c18c"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, + {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, ] +multidict = [] +pillow = [] priority = [ {file = "priority-2.0.0-py3-none-any.whl", hash = "sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa"}, {file = "priority-2.0.0.tar.gz", hash = "sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0"}, ] -pycparser = [ - {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, - {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, -] -quart = [ - {file = "Quart-0.15.1-py3-none-any.whl", hash = "sha256:f35134fb1d81af61624e6d89bca33cd611dcedce2dc4e291f527ab04395f4e1a"}, - {file = "Quart-0.15.1.tar.gz", hash = "sha256:f80c91d1e0588662483e22dd9c368a5778886b62e128c5399d2cc1b1898482cf"}, -] -six = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] +pycparser = [] +quart = [] toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] -typing-extensions = [ - {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, - {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, - {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, -] -websockets = [ - {file = "websockets-10.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cd8c6f2ec24aedace251017bc7a414525171d4e6578f914acab9349362def4da"}, - {file = "websockets-10.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1f6b814cff6aadc4288297cb3a248614829c6e4ff5556593c44a115e9dd49939"}, - {file = "websockets-10.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:01db0ecd1a0ca6702d02a5ed40413e18b7d22f94afb3bbe0d323bac86c42c1c8"}, - {file = "websockets-10.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:82b17524b1ce6ae7f7dd93e4d18e9b9474071e28b65dbf1dfe9b5767778db379"}, - {file = "websockets-10.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:8bbf8660c3f833ddc8b1afab90213f2e672a9ddac6eecb3cde968e6b2807c1c7"}, - {file = "websockets-10.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b8176deb6be540a46695960a765a77c28ac8b2e3ef2ec95d50a4f5df901edb1c"}, - {file = "websockets-10.0-cp37-cp37m-win32.whl", hash = "sha256:706e200fc7f03bed99ad0574cd1ea8b0951477dd18cc978ccb190683c69dba76"}, - {file = "websockets-10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5b2600e01c7ca6f840c42c747ffbe0254f319594ed108db847eb3d75f4aacb80"}, - {file = "websockets-10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:085bb8a6e780d30eaa1ba48ac7f3a6707f925edea787cfb761ce5a39e77ac09b"}, - {file = "websockets-10.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:9a4d889162bd48588e80950e07fa5e039eee9deb76a58092e8c3ece96d7ef537"}, - {file = "websockets-10.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b4ade7569b6fd17912452f9c3757d96f8e4044016b6d22b3b8391e641ca50456"}, - {file = "websockets-10.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:2a43072e434c041a99f2e1eb9b692df0232a38c37c61d00e9f24db79474329e4"}, - {file = "websockets-10.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:7f79f02c7f9a8320aff7d3321cd1c7e3a7dbc15d922ac996cca827301ee75238"}, - {file = "websockets-10.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:1ac35426fe3e7d3d0fac3d63c8965c76ed67a8fd713937be072bf0ce22808539"}, - {file = "websockets-10.0-cp38-cp38-win32.whl", hash = "sha256:ff59c6bdb87b31f7e2d596f09353d5a38c8c8ff571b0e2238e8ee2d55ad68465"}, - {file = "websockets-10.0-cp38-cp38-win_amd64.whl", hash = "sha256:d67646ddd17a86117ae21c27005d83c1895c0cef5d7be548b7549646372f868a"}, - {file = "websockets-10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:82bd921885231f4a30d9bc550552495b3fc36b1235add6d374e7c65c3babd805"}, - {file = "websockets-10.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:7d2e12e4f901f1bc062dfdf91831712c4106ed18a9a4cdb65e2e5f502124ca37"}, - {file = "websockets-10.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:71358c7816e2762f3e4af3adf0040f268e219f5a38cb3487a9d0fc2e554fef6a"}, - {file = "websockets-10.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:fe83b3ec9ef34063d86dfe1029160a85f24a5a94271036e5714a57acfdd089a1"}, - {file = "websockets-10.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:eb282127e9c136f860c6068a4fba5756eb25e755baffb5940b6f1eae071928b2"}, - {file = "websockets-10.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:62160772314920397f9d219147f958b33fa27a12c662d4455c9ccbba9a07e474"}, - {file = "websockets-10.0-cp39-cp39-win32.whl", hash = "sha256:e42a1f1e03437b017af341e9bbfdc09252cd48ef32a8c3c3ead769eab3b17368"}, - {file = "websockets-10.0-cp39-cp39-win_amd64.whl", hash = "sha256:c5880442f5fc268f1ef6d37b2c152c114deccca73f48e3a8c48004d2f16f4567"}, - {file = "websockets-10.0.tar.gz", hash = "sha256:c4fc9a1d242317892590abe5b61a9127f1a61740477bfb121743f290b8054002"}, -] -werkzeug = [ - {file = "Werkzeug-2.0.1-py3-none-any.whl", hash = "sha256:6c1ec500dcdba0baa27600f6a22f6333d8b662d22027ff9f6202e3367413caa8"}, - {file = "Werkzeug-2.0.1.tar.gz", hash = "sha256:1de1db30d010ff1af14a009224ec49ab2329ad2cde454c8a708130642d579c42"}, -] +websockets = [] +werkzeug = [] winter = [] wsproto = [ - {file = "wsproto-1.0.0-py3-none-any.whl", hash = "sha256:d8345d1808dd599b5ffb352c25a367adb6157e664e140dbecba3f9bc007edb9f"}, - {file = "wsproto-1.0.0.tar.gz", hash = "sha256:868776f8456997ad0d9720f7322b746bbe9193751b5b290b7f924659377c8c38"}, -] -yarl = [ - {file = "yarl-1.6.3-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:0355a701b3998dcd832d0dc47cc5dedf3874f966ac7f870e0f3a6788d802d434"}, - {file = "yarl-1.6.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:bafb450deef6861815ed579c7a6113a879a6ef58aed4c3a4be54400ae8871478"}, - {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:547f7665ad50fa8563150ed079f8e805e63dd85def6674c97efd78eed6c224a6"}, - {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:63f90b20ca654b3ecc7a8d62c03ffa46999595f0167d6450fa8383bab252987e"}, - {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:97b5bdc450d63c3ba30a127d018b866ea94e65655efaf889ebeabc20f7d12406"}, - {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:d8d07d102f17b68966e2de0e07bfd6e139c7c02ef06d3a0f8d2f0f055e13bb76"}, - {file = "yarl-1.6.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:15263c3b0b47968c1d90daa89f21fcc889bb4b1aac5555580d74565de6836366"}, - {file = "yarl-1.6.3-cp36-cp36m-win32.whl", hash = "sha256:b5dfc9a40c198334f4f3f55880ecf910adebdcb2a0b9a9c23c9345faa9185721"}, - {file = "yarl-1.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:b2e9a456c121e26d13c29251f8267541bd75e6a1ccf9e859179701c36a078643"}, - {file = "yarl-1.6.3-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:ce3beb46a72d9f2190f9e1027886bfc513702d748047b548b05dab7dfb584d2e"}, - {file = "yarl-1.6.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2ce4c621d21326a4a5500c25031e102af589edb50c09b321049e388b3934eec3"}, - {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:d26608cf178efb8faa5ff0f2d2e77c208f471c5a3709e577a7b3fd0445703ac8"}, - {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:4c5bcfc3ed226bf6419f7a33982fb4b8ec2e45785a0561eb99274ebbf09fdd6a"}, - {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:4736eaee5626db8d9cda9eb5282028cc834e2aeb194e0d8b50217d707e98bb5c"}, - {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:68dc568889b1c13f1e4745c96b931cc94fdd0defe92a72c2b8ce01091b22e35f"}, - {file = "yarl-1.6.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:7356644cbed76119d0b6bd32ffba704d30d747e0c217109d7979a7bc36c4d970"}, - {file = "yarl-1.6.3-cp37-cp37m-win32.whl", hash = "sha256:00d7ad91b6583602eb9c1d085a2cf281ada267e9a197e8b7cae487dadbfa293e"}, - {file = "yarl-1.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:69ee97c71fee1f63d04c945f56d5d726483c4762845400a6795a3b75d56b6c50"}, - {file = "yarl-1.6.3-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:e46fba844f4895b36f4c398c5af062a9808d1f26b2999c58909517384d5deda2"}, - {file = "yarl-1.6.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:31ede6e8c4329fb81c86706ba8f6bf661a924b53ba191b27aa5fcee5714d18ec"}, - {file = "yarl-1.6.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71"}, - {file = "yarl-1.6.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:72a660bdd24497e3e84f5519e57a9ee9220b6f3ac4d45056961bf22838ce20cc"}, - {file = "yarl-1.6.3-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:324ba3d3c6fee56e2e0b0d09bf5c73824b9f08234339d2b788af65e60040c959"}, - {file = "yarl-1.6.3-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:e6b5460dc5ad42ad2b36cca524491dfcaffbfd9c8df50508bddc354e787b8dc2"}, - {file = "yarl-1.6.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:6d6283d8e0631b617edf0fd726353cb76630b83a089a40933043894e7f6721e2"}, - {file = "yarl-1.6.3-cp38-cp38-win32.whl", hash = "sha256:9ede61b0854e267fd565e7527e2f2eb3ef8858b301319be0604177690e1a3896"}, - {file = "yarl-1.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a"}, - {file = "yarl-1.6.3-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:329412812ecfc94a57cd37c9d547579510a9e83c516bc069470db5f75684629e"}, - {file = "yarl-1.6.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c49ff66d479d38ab863c50f7bb27dee97c6627c5fe60697de15529da9c3de724"}, - {file = "yarl-1.6.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f040bcc6725c821a4c0665f3aa96a4d0805a7aaf2caf266d256b8ed71b9f041c"}, - {file = "yarl-1.6.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:d5c32c82990e4ac4d8150fd7652b972216b204de4e83a122546dce571c1bdf25"}, - {file = "yarl-1.6.3-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:d597767fcd2c3dc49d6eea360c458b65643d1e4dbed91361cf5e36e53c1f8c96"}, - {file = "yarl-1.6.3-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:8aa3decd5e0e852dc68335abf5478a518b41bf2ab2f330fe44916399efedfae0"}, - {file = "yarl-1.6.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:73494d5b71099ae8cb8754f1df131c11d433b387efab7b51849e7e1e851f07a4"}, - {file = "yarl-1.6.3-cp39-cp39-win32.whl", hash = "sha256:5b883e458058f8d6099e4420f0cc2567989032b5f34b271c0827de9f1079a424"}, - {file = "yarl-1.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:4953fb0b4fdb7e08b2f3b3be80a00d28c5c8a2056bb066169de00e6501b986b6"}, - {file = "yarl-1.6.3.tar.gz", hash = "sha256:8a9066529240171b68893d60dca86a763eae2139dd42f42106b03cf4b426bf10"}, -] -zstandard = [ - {file = "zstandard-0.15.2-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:7b16bd74ae7bfbaca407a127e11058b287a4267caad13bd41305a5e630472549"}, - {file = "zstandard-0.15.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8baf7991547441458325ca8fafeae79ef1501cb4354022724f3edd62279c5b2b"}, - {file = "zstandard-0.15.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:5752f44795b943c99be367fee5edf3122a1690b0d1ecd1bd5ec94c7fd2c39c94"}, - {file = "zstandard-0.15.2-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:3547ff4eee7175d944a865bbdf5529b0969c253e8a148c287f0668fe4eb9c935"}, - {file = "zstandard-0.15.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:ac43c1821ba81e9344d818c5feed574a17f51fca27976ff7d022645c378fbbf5"}, - {file = "zstandard-0.15.2-cp35-cp35m-manylinux2014_i686.whl", hash = "sha256:1fb23b1754ce834a3a1a1e148cc2faad76eeadf9d889efe5e8199d3fb839d3c6"}, - {file = "zstandard-0.15.2-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:1faefe33e3d6870a4dce637bcb41f7abb46a1872a595ecc7b034016081c37543"}, - {file = "zstandard-0.15.2-cp35-cp35m-win32.whl", hash = "sha256:b7d3a484ace91ed827aa2ef3b44895e2ec106031012f14d28bd11a55f24fa734"}, - {file = "zstandard-0.15.2-cp35-cp35m-win_amd64.whl", hash = "sha256:ff5b75f94101beaa373f1511319580a010f6e03458ee51b1a386d7de5331440a"}, - {file = "zstandard-0.15.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c9e2dcb7f851f020232b991c226c5678dc07090256e929e45a89538d82f71d2e"}, - {file = "zstandard-0.15.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4800ab8ec94cbf1ed09c2b4686288750cab0642cb4d6fba2a56db66b923aeb92"}, - {file = "zstandard-0.15.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ec58e84d625553d191a23d5988a19c3ebfed519fff2a8b844223e3f074152163"}, - {file = "zstandard-0.15.2-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bd3c478a4a574f412efc58ba7e09ab4cd83484c545746a01601636e87e3dbf23"}, - {file = "zstandard-0.15.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:6f5d0330bc992b1e267a1b69fbdbb5ebe8c3a6af107d67e14c7a5b1ede2c5945"}, - {file = "zstandard-0.15.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:b4963dad6cf28bfe0b61c3265d1c74a26a7605df3445bfcd3ba25de012330b2d"}, - {file = "zstandard-0.15.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:77d26452676f471223571efd73131fd4a626622c7960458aab2763e025836fc5"}, - {file = "zstandard-0.15.2-cp36-cp36m-win32.whl", hash = "sha256:6ffadd48e6fe85f27ca3ca10cfd3ef3d0f933bef7316870285ffeb58d791ca9c"}, - {file = "zstandard-0.15.2-cp36-cp36m-win_amd64.whl", hash = "sha256:92d49cc3b49372cfea2d42f43a2c16a98a32a6bc2f42abcde121132dbfc2f023"}, - {file = "zstandard-0.15.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:af5a011609206e390b44847da32463437505bf55fd8985e7a91c52d9da338d4b"}, - {file = "zstandard-0.15.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:31e35790434da54c106f05fa93ab4d0fab2798a6350e8a73928ec602e8505836"}, - {file = "zstandard-0.15.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a4f8af277bb527fa3d56b216bda4da931b36b2d3fe416b6fc1744072b2c1dbd9"}, - {file = "zstandard-0.15.2-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:72a011678c654df8323aa7b687e3147749034fdbe994d346f139ab9702b59cea"}, - {file = "zstandard-0.15.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:5d53f02aeb8fdd48b88bc80bece82542d084fb1a7ba03bf241fd53b63aee4f22"}, - {file = "zstandard-0.15.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:f8bb00ced04a8feff05989996db47906673ed45b11d86ad5ce892b5741e5f9dd"}, - {file = "zstandard-0.15.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:7a88cc773ffe55992ff7259a8df5fb3570168d7138c69aadba40142d0e5ce39a"}, - {file = "zstandard-0.15.2-cp37-cp37m-win32.whl", hash = "sha256:1c5ef399f81204fbd9f0df3debf80389fd8aa9660fe1746d37c80b0d45f809e9"}, - {file = "zstandard-0.15.2-cp37-cp37m-win_amd64.whl", hash = "sha256:22f127ff5da052ffba73af146d7d61db874f5edb468b36c9cb0b857316a21b3d"}, - {file = "zstandard-0.15.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9867206093d7283d7de01bd2bf60389eb4d19b67306a0a763d1a8a4dbe2fb7c3"}, - {file = "zstandard-0.15.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f98fc5750aac2d63d482909184aac72a979bfd123b112ec53fd365104ea15b1c"}, - {file = "zstandard-0.15.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3fe469a887f6142cc108e44c7f42c036e43620ebaf500747be2317c9f4615d4f"}, - {file = "zstandard-0.15.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:edde82ce3007a64e8434ccaf1b53271da4f255224d77b880b59e7d6d73df90c8"}, - {file = "zstandard-0.15.2-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:855d95ec78b6f0ff66e076d5461bf12d09d8e8f7e2b3fc9de7236d1464fd730e"}, - {file = "zstandard-0.15.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d25c8eeb4720da41e7afbc404891e3a945b8bb6d5230e4c53d23ac4f4f9fc52c"}, - {file = "zstandard-0.15.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:2353b61f249a5fc243aae3caa1207c80c7e6919a58b1f9992758fa496f61f839"}, - {file = "zstandard-0.15.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:6cc162b5b6e3c40b223163a9ea86cd332bd352ddadb5fd142fc0706e5e4eaaff"}, - {file = "zstandard-0.15.2-cp38-cp38-win32.whl", hash = "sha256:94d0de65e37f5677165725f1fc7fb1616b9542d42a9832a9a0bdcba0ed68b63b"}, - {file = "zstandard-0.15.2-cp38-cp38-win_amd64.whl", hash = "sha256:b0975748bb6ec55b6d0f6665313c2cf7af6f536221dccd5879b967d76f6e7899"}, - {file = "zstandard-0.15.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eda0719b29792f0fea04a853377cfff934660cb6cd72a0a0eeba7a1f0df4a16e"}, - {file = "zstandard-0.15.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8fb77dd152054c6685639d855693579a92f276b38b8003be5942de31d241ebfb"}, - {file = "zstandard-0.15.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:24cdcc6f297f7c978a40fb7706877ad33d8e28acc1786992a52199502d6da2a4"}, - {file = "zstandard-0.15.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:69b7a5720b8dfab9005a43c7ddb2e3ccacbb9a2442908ae4ed49dd51ab19698a"}, - {file = "zstandard-0.15.2-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:dc8c03d0c5c10c200441ffb4cce46d869d9e5c4ef007f55856751dc288a2dffd"}, - {file = "zstandard-0.15.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:3e1cd2db25117c5b7c7e86a17cde6104a93719a9df7cb099d7498e4c1d13ee5c"}, - {file = "zstandard-0.15.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:ab9f19460dfa4c5dd25431b75bee28b5f018bf43476858d64b1aa1046196a2a0"}, - {file = "zstandard-0.15.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:f36722144bc0a5068934e51dca5a38a5b4daac1be84f4423244277e4baf24e7a"}, - {file = "zstandard-0.15.2-cp39-cp39-win32.whl", hash = "sha256:378ac053c0cfc74d115cbb6ee181540f3e793c7cca8ed8cd3893e338af9e942c"}, - {file = "zstandard-0.15.2-cp39-cp39-win_amd64.whl", hash = "sha256:9ee3c992b93e26c2ae827404a626138588e30bdabaaf7aa3aa25082a4e718790"}, - {file = "zstandard-0.15.2.tar.gz", hash = "sha256:52de08355fd5cfb3ef4533891092bb96229d43c2069703d4aff04fdbedf9c92f"}, + {file = "wsproto-1.1.0-py3-none-any.whl", hash = "sha256:2218cb57952d90b9fca325c0dcfb08c3bda93e8fd8070b0a17f048e2e47a521b"}, + {file = "wsproto-1.1.0.tar.gz", hash = "sha256:a2e56bfd5c7cd83c1369d83b5feccd6d37798b74872866e62616e0ecf111bda8"}, ] +yarl = [] +zipp = [] +zstandard = [] diff --git a/pyproject.toml b/pyproject.toml index dd5ba59..4f996c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,18 +7,19 @@ license = "GPLv3-only" [tool.poetry.dependencies] python = "^3.9" -bcrypt = "^3.2.0" -itsdangerous = "^1.1.0" -asyncpg = "^0.24.0" -websockets = "^10.0" +bcrypt = "^3.2.2" +itsdangerous = "^2.1.2" +asyncpg = "^0.26.0" +websockets = "^10.3" Earl-ETF = "^2.1.2" logbook = "^1.5.3" Cerberus = "^1.3.4" -quart = "^0.15.1" -pillow = "^8.3.2" -aiohttp = "^3.7.4" -zstandard = "^0.15.2" +quart = "^0.18.0" +pillow = "^9.2.0" +aiohttp = "^3.8.1" +zstandard = "^0.18.0" winter = {git = "https://gitlab.com/elixire/winter"} +wsproto = "^1.1.0" diff --git a/run.py b/run.py index b85e894..a966b48 100644 --- a/run.py +++ b/run.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,6 +18,7 @@ along with this program. If not, see . """ import asyncio +import ssl import sys import asyncpg @@ -104,7 +105,13 @@ from litecord.pubsub.lazy_guild import LazyGuildManager from litecord.gateway.gateway import websocket_handler -from litecord.utils import LitecordJSONEncoder +from litecord.json import LitecordJSONProvider + +# == HACKY PATCH == +# this MUST be removed once Hypercorn gets py3.10 support. +from asyncio import start_server as _start_server + +asyncio.start_server = lambda *args, loop=None, **kwargs: _start_server(*args, **kwargs) # setup logbook handler = StreamHandler(sys.stdout, level=logbook.INFO) @@ -128,12 +135,12 @@ def make_app(): logging.getLogger("websockets").setLevel(logbook.INFO) # use our custom json encoder for custom data types - app.json_encoder = LitecordJSONEncoder + app.json_provider_class = LitecordJSONProvider return app -PREFIXES = ("/api/v6", "/api/v7", "/api/v8", "/api/v9") +PREFIXES = ("/api/v6", "/api/v7", "/api/v8", "/api/v9", "/api/v10") def set_blueprints(app_): @@ -367,7 +374,15 @@ def start_websocket(host, port, ws_handler) -> asyncio.Future: # so we can pass quart's app object. await ws_handler(app, ws, url) - return websockets.serve(_wrapper, host, port) + kwargs = {"ws_handler": _wrapper, "host": host, "port": port} + tls_cert_path = getattr(app.config, "WEBSOCKET_TLS_CERT_PATH", None) + tls_key_path = getattr(app.config, "WEBSOCKET_TLS_CERT_PATH", None) + if tls_cert_path: + context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + context.load_cert_chain(tls_cert_path, tls_key_path) + kwargs["ssl"] = context + + return websockets.serve(**kwargs) @app.before_serving diff --git a/setup.py b/setup.py index ee848cf..0b312ed 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/common.py b/tests/common.py index 1c25743..aed8d44 100644 --- a/tests/common.py +++ b/tests/common.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/conftest.py b/tests/conftest.py index e625dba..e73a1f0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -143,3 +143,25 @@ async def test_cli_staff(test_cli): yield client await client.cleanup() await _user_fixture_teardown(test_cli.app, test_user) + + +@pytest.fixture +async def test_cli_bot(test_cli): + """Yield a TestClient with a bot user.""" + # do not create a new test user to prevent race conditions caused + # by a test wanting both fixtures + app = test_cli.app + test_user = await _user_fixture_setup(app) + user_id = test_user["id"] + + assert await app.db.fetchval( + """ + UPDATE users SET bot = true WHERE id = $1 RETURNING bot + """, + user_id, + ) + + client = TestClient(test_cli, test_user) + yield client + await client.cleanup() + await _user_fixture_teardown(test_cli.app, test_user) diff --git a/tests/test_admin_api/test_guilds.py b/tests/test_admin_api/test_guilds.py index cdb4110..846fd75 100644 --- a/tests/test_admin_api/test_guilds.py +++ b/tests/test_admin_api/test_guilds.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/test_admin_api/test_instance_invites.py b/tests/test_admin_api/test_instance_invites.py index e9149c6..6bd423a 100644 --- a/tests/test_admin_api/test_instance_invites.py +++ b/tests/test_admin_api/test_instance_invites.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/test_admin_api/test_users.py b/tests/test_admin_api/test_users.py index 814cd29..6fb7cd8 100644 --- a/tests/test_admin_api/test_users.py +++ b/tests/test_admin_api/test_users.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/test_channels.py b/tests/test_channels.py index 0a7203b..4d2a70f 100644 --- a/tests/test_channels.py +++ b/tests/test_channels.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/test_embeds.py b/tests/test_embeds.py index 3ec0448..6e76732 100644 --- a/tests/test_embeds.py +++ b/tests/test_embeds.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/test_gateway.py b/tests/test_gateway.py index 073c1e0..f6d374f 100644 --- a/tests/test_gateway.py +++ b/tests/test_gateway.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/test_guild.py b/tests/test_guild.py index b5c9e97..f776ad6 100644 --- a/tests/test_guild.py +++ b/tests/test_guild.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/test_invites.py b/tests/test_invites.py index 7f4b8f7..dbfeec6 100644 --- a/tests/test_invites.py +++ b/tests/test_invites.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/test_main.py b/tests/test_main.py index 729b37d..ab72813 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/test_messages.py b/tests/test_messages.py index a92b58d..874a514 100644 --- a/tests/test_messages.py +++ b/tests/test_messages.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/test_no_tracking.py b/tests/test_no_tracking.py index aefc4f5..e9a93dd 100644 --- a/tests/test_no_tracking.py +++ b/tests/test_no_tracking.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/test_ratelimits.py b/tests/test_ratelimits.py index bd675d0..8c22cae 100644 --- a/tests/test_ratelimits.py +++ b/tests/test_ratelimits.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/test_reactions.py b/tests/test_reactions.py new file mode 100644 index 0000000..f98bf15 --- /dev/null +++ b/tests/test_reactions.py @@ -0,0 +1,45 @@ +""" + +Litecord +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +""" + +import pytest +import urllib.parse + +pytestmark = pytest.mark.asyncio + + +async def test_reaction_flow(test_cli_user): + guild = await test_cli_user.create_guild() + channel = await test_cli_user.create_guild_channel(guild_id=guild.id) + message = await test_cli_user.create_message( + guild_id=guild.id, channel_id=channel.id + ) + + reaction = urllib.parse.quote("\N{THINKING FACE}") + + resp = await test_cli_user.put( + f"/api/v6/channels/{channel.id}/messages/{message.id}/reactions/{reaction}/@me" + ) + assert resp.status_code == 204 + + resp = await test_cli_user.get( + f"/api/v6/channels/{channel.id}/messages/{message.id}/reactions/{reaction}" + ) + assert resp.status_code == 200 + rjson = await resp.json + assert len(rjson) == 1 diff --git a/tests/test_user.py b/tests/test_user.py index 9e0c77a..470ca75 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/test_webhooks.py b/tests/test_webhooks.py index e73c615..f253df6 100644 --- a/tests/test_webhooks.py +++ b/tests/test_webhooks.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/test_websocket.py b/tests/test_websocket.py index f9a6153..ee8d3fe 100644 --- a/tests/test_websocket.py +++ b/tests/test_websocket.py @@ -1,7 +1,7 @@ """ Litecord -Copyright (C) 2018-2019 Luna Mendes +Copyright (C) 2018-2021 Luna Mendes and Litecord Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,22 +18,172 @@ along with this program. If not, see . """ import json +import zlib +import asyncio +import urllib.parse +import collections +from typing import Optional import pytest import websockets +from logbook import Logger +from wsproto import WSConnection, ConnectionType +from wsproto.connection import ConnectionState +from wsproto.events import ( + Request, + Message, + AcceptConnection, + CloseConnection, + Ping, +) from litecord.gateway.opcodes import OP from litecord.gateway.websocket import decode_etf - -async def _json(conn): - frame = await conn.recv() - return json.loads(frame) +# Z_SYNC_FLUSH suffix +ZLIB_SUFFIX = b"\x00\x00\xff\xff" -async def _etf(conn): - frame = await conn.recv() - return decode_etf(frame) +log = Logger("test_websocket") + +RcvdWrapper = collections.namedtuple("RcvdWrapper", "code reason") + + +class AsyncWebsocket: + """websockets-compatible websocket object""" + + def __init__(self, url): + self.url = url + self.ws = WSConnection(ConnectionType.CLIENT) + self.reader, self.writer = None, None + + async def send(self, data): + assert self.writer is not None + + # wrap all strings in Message + if isinstance(data, str): + data = Message(data=data) + + log.debug("sending {} event", type(data)) + + self.writer.write(self.ws.send(data)) + await self.writer.drain() + + async def recv(self, *, expect=Message, process_event: bool = True): + + # this loop is only done so we reply to pings while also being + # able to receive any other event in the middle. + # + # CloseConnection does not lead us to reading other events, so + # that's why it's left out. + + while True: + # if there's already an unprocessed event we can try getting + # it from wsproto first + event = None + for event in self.ws.events(): + break + + if event is None: + data = await self.reader.read(4096) + assert data # We expect the WebSocket to be closed correctly + self.ws.receive_data(data) + continue + + # if we get a ping, reply with pong immediately + # and fetch the next event + if isinstance(event, Ping): + await self.send(event.response()) + continue + + break + + if isinstance(event, CloseConnection): + assert self.ws.state is ConnectionState.REMOTE_CLOSING + await self.send(event.response()) + if process_event: + raise websockets.ConnectionClosed( + RcvdWrapper(event.code, event.reason), None + ) + + if expect is not None and not isinstance(event, expect): + raise AssertionError( + f"Expected {expect!r} websocket event, got {type(event)!r}" + ) + + # this keeps compatibility with code written for aaugustin/websockets + if expect is Message and process_event: + return event.data + + return event + + async def close(self, close_code: int, close_reason: str): + log.info("closing connection") + event = CloseConnection(code=close_code, reason=close_reason) + await self.send(event) + self.writer.close() + await self.writer.wait_closed() + self.ws.receive_data(None) + + async def connect(self): + parsed = urllib.parse.urlparse(self.url) + if parsed.scheme == "wss": + port = 443 + elif parsed.scheme == "ws": + port = 80 + else: + raise AssertionError("Invalid url scheme") + + host, *rest = parsed.netloc.split(":") + if rest: + port = rest[0] + + log.info("connecting to {!r} {}", host, port) + self.reader, self.writer = await asyncio.open_connection(host, port) + + path = parsed.path or "/" + target = f"{path}?{parsed.query}" if parsed.query else path + await self.send(Request(host=parsed.netloc, target=target)) + await self.recv(expect=AcceptConnection) + + +async def _recv(conn, *, zlib_stream: bool): + if zlib_stream: + try: + conn._zlib_context + except AttributeError: + conn._zlib_context = zlib.decompressobj() + + # inspired by + # https://discord.com/developers/docs/topics/gateway#transport-compression-transport-compression-example + zlib_buffer = bytearray() + while True: + # keep receiving frames until we find the zlib prefix inside + # we set process_event to false so that we get the entire event + # instead of only data + event = await conn.recv(process_event=False) + zlib_buffer.extend(event.data) + if not event.message_finished: + continue + + if len(zlib_buffer) < 4 or zlib_buffer[-4:] != ZLIB_SUFFIX: + raise RuntimeError("Finished compressed message without ZLIB suffix") + + # NOTE: the message is utf-8 encoded. + msg = conn._zlib_context.decompress(zlib_buffer) + return msg + else: + return await conn.recv() + + +async def _json(conn, *, zlib_stream: bool = False): + data = await _recv(conn, zlib_stream=zlib_stream) + return json.loads(data) + + +async def _etf(conn, *, zlib_stream: bool = False): + data = await _recv(conn, zlib_stream=zlib_stream) + return decode_etf(data) async def _json_send(conn, data): @@ -49,6 +199,28 @@ async def _close(conn): await conn.close(1000, "test end") +async def extract_and_verify_ready(conn, **kwargs): + ready = await _json(conn, **kwargs) + assert ready["op"] == OP.DISPATCH + assert ready["t"] == "READY" + + data = ready["d"] + + # NOTE: change if default gateway changes + assert data["v"] == 6 + + # make sure other fields exist and are with + # proper types. + assert isinstance(data["user"], dict) + assert isinstance(data["private_channels"], list) + assert isinstance(data["guilds"], list) + assert isinstance(data["session_id"], str) + assert isinstance(data["_trace"], list) + + if "shard" in data: + assert isinstance(data["shard"], list) + + async def get_gw(test_cli, version: int) -> str: """Get the Gateway URL.""" gw_resp = await test_cli.get(f"/api/v{version}/gateway") @@ -56,7 +228,9 @@ async def get_gw(test_cli, version: int) -> str: return gw_json["url"] -async def gw_start(test_cli, *, version: int = 6, etf=False): +async def gw_start( + test_cli, *, version: int = 6, etf=False, compress: Optional[str] = None +): """Start a websocket connection""" gw_url = await get_gw(test_cli, version) @@ -65,7 +239,11 @@ async def gw_start(test_cli, *, version: int = 6, etf=False): else: gw_url = f"{gw_url}?v={version}&encoding=json" - return await websockets.connect(gw_url) + compress = f"&compress={compress}" if compress else "" + + ws = AsyncWebsocket(f"{gw_url}{compress}") + await ws.connect() + return ws @pytest.mark.asyncio @@ -120,8 +298,6 @@ async def test_broken_identify(test_cli_user): raise AssertionError("Received a JSON message but expected close") except websockets.ConnectionClosed as exc: assert exc.code == 4002 - finally: - await _close(conn) @pytest.mark.asyncio @@ -136,27 +312,8 @@ async def test_ready_fields(test_cli_user): ) try: - ready = await _json(conn) - assert isinstance(ready, dict) - assert ready["op"] == OP.DISPATCH - assert ready["t"] == "READY" + await extract_and_verify_ready(conn) - data = ready["d"] - assert isinstance(data, dict) - - # NOTE: change if default gateway changes - assert data["v"] == 6 - - # make sure other fields exist and are with - # proper types. - assert isinstance(data["user"], dict) - assert isinstance(data["private_channels"], list) - assert isinstance(data["guilds"], list) - assert isinstance(data["session_id"], str) - assert isinstance(data["_trace"], list) - - if "shard" in data: - assert isinstance(data["shard"], list) finally: await _close(conn) @@ -301,3 +458,32 @@ async def test_resume(test_cli_user): assert isinstance(msg, dict) assert isinstance(msg["op"], int) assert msg["op"] == OP.INVALID_SESSION + + +@pytest.mark.asyncio +async def test_ready_bot(test_cli_bot): + conn = await gw_start(test_cli_bot.cli) + await _json(conn) # ignore hello + await _json_send( + conn, {"op": OP.IDENTIFY, "d": {"token": test_cli_bot.user["token"]}} + ) + + try: + await extract_and_verify_ready(conn) + finally: + await _close(conn) + + +@pytest.mark.asyncio +async def test_ready_bot_zlib_stream(test_cli_bot): + conn = await gw_start(test_cli_bot.cli, compress="zlib-stream") + await _json(conn, zlib_stream=True) # ignore hello + await _json_send( + conn, + {"op": OP.IDENTIFY, "d": {"token": test_cli_bot.user["token"]}}, + ) + + try: + await extract_and_verify_ready(conn, zlib_stream=True) + finally: + await _close(conn) diff --git a/tox.ini b/tox.ini index ed53a2f..43fde9a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,22 +1,22 @@ [tox] -envlist = py3.9 +envlist = py3.10 isolated_build = true [testenv] ignore_errors = true deps = - pytest==6.2.5 - pytest-asyncio==0.15.1 - pytest-cov==2.12.1 - flake8==3.9.2 - black==21.6b0 - mypy==0.910 + pytest==7.1.2 + pytest-asyncio==0.19.0 + pytest-cov==3.0.0 + flake8==5.0.4 + black==22.6.0 + mypy==0.971 pytest-instafail==0.4.2 commands = python3 ./manage.py migrate black --check litecord run.py tests manage flake8 litecord run.py tests manage - pytest {posargs:tests} + pytest --asyncio-mode=auto {posargs:tests} [flake8] max-line-length = 88