disagreement 0.2.0rc1__py3-none-any.whl → 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- disagreement/__init__.py +2 -4
- disagreement/audio.py +42 -5
- disagreement/cache.py +43 -4
- disagreement/caching.py +121 -0
- disagreement/client.py +1682 -1535
- disagreement/enums.py +10 -3
- disagreement/error_handler.py +5 -1
- disagreement/errors.py +1341 -3
- disagreement/event_dispatcher.py +3 -5
- disagreement/ext/__init__.py +1 -0
- disagreement/ext/app_commands/__init__.py +0 -2
- disagreement/ext/app_commands/commands.py +0 -2
- disagreement/ext/app_commands/context.py +0 -2
- disagreement/ext/app_commands/converters.py +2 -4
- disagreement/ext/app_commands/decorators.py +5 -7
- disagreement/ext/app_commands/handler.py +1 -3
- disagreement/ext/app_commands/hybrid.py +0 -2
- disagreement/ext/commands/__init__.py +63 -61
- disagreement/ext/commands/cog.py +0 -2
- disagreement/ext/commands/converters.py +16 -5
- disagreement/ext/commands/core.py +728 -563
- disagreement/ext/commands/decorators.py +294 -219
- disagreement/ext/commands/errors.py +0 -2
- disagreement/ext/commands/help.py +0 -2
- disagreement/ext/commands/view.py +1 -3
- disagreement/gateway.py +632 -586
- disagreement/http.py +1362 -1041
- disagreement/interactions.py +0 -2
- disagreement/models.py +2682 -2263
- disagreement/shard_manager.py +0 -2
- disagreement/ui/view.py +167 -165
- disagreement/voice_client.py +263 -162
- {disagreement-0.2.0rc1.dist-info → disagreement-0.4.0.dist-info}/METADATA +33 -6
- disagreement-0.4.0.dist-info/RECORD +55 -0
- disagreement-0.2.0rc1.dist-info/RECORD +0 -54
- {disagreement-0.2.0rc1.dist-info → disagreement-0.4.0.dist-info}/WHEEL +0 -0
- {disagreement-0.2.0rc1.dist-info → disagreement-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {disagreement-0.2.0rc1.dist-info → disagreement-0.4.0.dist-info}/top_level.txt +0 -0
disagreement/shard_manager.py
CHANGED
disagreement/ui/view.py
CHANGED
@@ -1,165 +1,167 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import asyncio
|
4
|
-
import uuid
|
5
|
-
from typing import Any, Callable, Coroutine, Dict, List, Optional, TYPE_CHECKING
|
6
|
-
|
7
|
-
from ..models import ActionRow
|
8
|
-
from .item import Item
|
9
|
-
|
10
|
-
if TYPE_CHECKING:
|
11
|
-
from ..client import Client
|
12
|
-
from ..interactions import Interaction
|
13
|
-
|
14
|
-
|
15
|
-
class View:
|
16
|
-
"""Represents a container for UI components that can be sent with a message.
|
17
|
-
|
18
|
-
Args:
|
19
|
-
timeout (Optional[float]): The number of seconds to wait for an interaction before the view times out.
|
20
|
-
Defaults to 180.
|
21
|
-
"""
|
22
|
-
|
23
|
-
def __init__(self, *, timeout: Optional[float] = 180.0):
|
24
|
-
self.timeout = timeout
|
25
|
-
self.id = str(uuid.uuid4())
|
26
|
-
self.__children: List[Item] = []
|
27
|
-
self.__stopped = asyncio.Event()
|
28
|
-
self._client: Optional[Client] = None
|
29
|
-
self._message_id: Optional[str] = None
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
def
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
rows
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
rows
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
self.
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import asyncio
|
4
|
+
import uuid
|
5
|
+
from typing import Any, Callable, Coroutine, Dict, List, Optional, TYPE_CHECKING
|
6
|
+
|
7
|
+
from ..models import ActionRow
|
8
|
+
from .item import Item
|
9
|
+
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from ..client import Client
|
12
|
+
from ..interactions import Interaction
|
13
|
+
|
14
|
+
|
15
|
+
class View:
|
16
|
+
"""Represents a container for UI components that can be sent with a message.
|
17
|
+
|
18
|
+
Args:
|
19
|
+
timeout (Optional[float]): The number of seconds to wait for an interaction before the view times out.
|
20
|
+
Defaults to 180.
|
21
|
+
"""
|
22
|
+
|
23
|
+
def __init__(self, *, timeout: Optional[float] = 180.0):
|
24
|
+
self.timeout = timeout
|
25
|
+
self.id = str(uuid.uuid4())
|
26
|
+
self.__children: List[Item] = []
|
27
|
+
self.__stopped = asyncio.Event()
|
28
|
+
self._client: Optional[Client] = None
|
29
|
+
self._message_id: Optional[str] = None
|
30
|
+
|
31
|
+
# The below is a bit of a hack to support items defined as class members
|
32
|
+
# e.g. button = Button(...)
|
33
|
+
for item in self.__class__.__dict__.values():
|
34
|
+
if isinstance(item, Item):
|
35
|
+
self.add_item(item)
|
36
|
+
|
37
|
+
@property
|
38
|
+
def children(self) -> List[Item]:
|
39
|
+
return self.__children
|
40
|
+
|
41
|
+
def add_item(self, item: Item):
|
42
|
+
"""Adds an item to the view."""
|
43
|
+
if not isinstance(item, Item):
|
44
|
+
raise TypeError("Only instances of 'Item' can be added to a View.")
|
45
|
+
|
46
|
+
if len(self.__children) >= 25:
|
47
|
+
raise ValueError("A view can only have a maximum of 25 components.")
|
48
|
+
|
49
|
+
if self.timeout is None and item.custom_id is None:
|
50
|
+
raise ValueError(
|
51
|
+
"All components in a persistent view must have a 'custom_id'."
|
52
|
+
)
|
53
|
+
|
54
|
+
item._view = self
|
55
|
+
self.__children.append(item)
|
56
|
+
|
57
|
+
@property
|
58
|
+
def message_id(self) -> Optional[str]:
|
59
|
+
return self._message_id
|
60
|
+
|
61
|
+
@message_id.setter
|
62
|
+
def message_id(self, value: str):
|
63
|
+
self._message_id = value
|
64
|
+
|
65
|
+
def to_components(self) -> List[ActionRow]:
|
66
|
+
"""Converts the view's children into a list of ActionRow components.
|
67
|
+
|
68
|
+
This retains the original, simple layout behaviour where each item is
|
69
|
+
placed in its own :class:`ActionRow` to ensure backward compatibility.
|
70
|
+
"""
|
71
|
+
|
72
|
+
rows: List[ActionRow] = []
|
73
|
+
|
74
|
+
for item in self.children:
|
75
|
+
rows.append(ActionRow(components=[item]))
|
76
|
+
|
77
|
+
return rows
|
78
|
+
|
79
|
+
def layout_components_advanced(self) -> List[ActionRow]:
|
80
|
+
"""Group compatible components into rows following Discord rules."""
|
81
|
+
|
82
|
+
rows: List[ActionRow] = []
|
83
|
+
|
84
|
+
for item in self.children:
|
85
|
+
if item.custom_id is None:
|
86
|
+
item.custom_id = (
|
87
|
+
f"{self.id}:{item.__class__.__name__}:{len(self.__children)}"
|
88
|
+
)
|
89
|
+
|
90
|
+
target_row = item.row
|
91
|
+
if target_row is not None:
|
92
|
+
if not 0 <= target_row <= 4:
|
93
|
+
raise ValueError("Row index must be between 0 and 4.")
|
94
|
+
|
95
|
+
while len(rows) <= target_row:
|
96
|
+
if len(rows) >= 5:
|
97
|
+
raise ValueError("A view can have at most 5 action rows.")
|
98
|
+
rows.append(ActionRow())
|
99
|
+
|
100
|
+
rows[target_row].add_component(item)
|
101
|
+
continue
|
102
|
+
|
103
|
+
placed = False
|
104
|
+
for row in rows:
|
105
|
+
try:
|
106
|
+
row.add_component(item)
|
107
|
+
placed = True
|
108
|
+
break
|
109
|
+
except ValueError:
|
110
|
+
continue
|
111
|
+
|
112
|
+
if not placed:
|
113
|
+
if len(rows) >= 5:
|
114
|
+
raise ValueError("A view can have at most 5 action rows.")
|
115
|
+
new_row = ActionRow([item])
|
116
|
+
rows.append(new_row)
|
117
|
+
|
118
|
+
return rows
|
119
|
+
|
120
|
+
def to_components_payload(self) -> List[Dict[str, Any]]:
|
121
|
+
"""Converts the view's children into a list of component dictionaries
|
122
|
+
that can be sent to the Discord API."""
|
123
|
+
return [row.to_dict() for row in self.to_components()]
|
124
|
+
|
125
|
+
async def _dispatch(self, interaction: Interaction):
|
126
|
+
"""Called by the client to dispatch an interaction to the correct item."""
|
127
|
+
if self.timeout is not None:
|
128
|
+
self.__stopped.set() # Reset the timeout on each interaction
|
129
|
+
self.__stopped.clear()
|
130
|
+
|
131
|
+
if interaction.data:
|
132
|
+
custom_id = interaction.data.custom_id
|
133
|
+
for child in self.children:
|
134
|
+
if child.custom_id == custom_id:
|
135
|
+
if child.callback:
|
136
|
+
await child.callback(self, interaction)
|
137
|
+
break
|
138
|
+
|
139
|
+
async def wait(self) -> bool:
|
140
|
+
"""Waits until the view has stopped interacting."""
|
141
|
+
return await self.__stopped.wait()
|
142
|
+
|
143
|
+
def stop(self):
|
144
|
+
"""Stops the view from listening to interactions."""
|
145
|
+
if not self.__stopped.is_set():
|
146
|
+
self.__stopped.set()
|
147
|
+
|
148
|
+
async def on_timeout(self):
|
149
|
+
"""Called when the view times out."""
|
150
|
+
pass
|
151
|
+
|
152
|
+
async def _start(self, client: Client):
|
153
|
+
"""Starts the view's internal listener."""
|
154
|
+
self._client = client
|
155
|
+
if self.timeout is not None:
|
156
|
+
asyncio.create_task(self._timeout_task())
|
157
|
+
|
158
|
+
async def _timeout_task(self):
|
159
|
+
"""The task that waits for the timeout and then stops the view."""
|
160
|
+
try:
|
161
|
+
await asyncio.wait_for(self.wait(), timeout=self.timeout)
|
162
|
+
except asyncio.TimeoutError:
|
163
|
+
self.stop()
|
164
|
+
await self.on_timeout()
|
165
|
+
if self._client and self._message_id:
|
166
|
+
# Remove the view from the client's listeners
|
167
|
+
self._client._views.pop(self._message_id, None)
|