disagreement 0.4.1__py3-none-any.whl → 0.4.2__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 +30 -1
- disagreement/cache.py +9 -1
- disagreement/client.py +38 -12
- disagreement/event_dispatcher.py +8 -0
- disagreement/http.py +7 -3
- disagreement/models.py +72 -19
- disagreement/voice_client.py +17 -2
- {disagreement-0.4.1.dist-info → disagreement-0.4.2.dist-info}/METADATA +12 -2
- {disagreement-0.4.1.dist-info → disagreement-0.4.2.dist-info}/RECORD +12 -12
- {disagreement-0.4.1.dist-info → disagreement-0.4.2.dist-info}/WHEEL +0 -0
- {disagreement-0.4.1.dist-info → disagreement-0.4.2.dist-info}/licenses/LICENSE +0 -0
- {disagreement-0.4.1.dist-info → disagreement-0.4.2.dist-info}/top_level.txt +0 -0
disagreement/__init__.py
CHANGED
@@ -12,7 +12,7 @@ __title__ = "disagreement"
|
|
12
12
|
__author__ = "Slipstream"
|
13
13
|
__license__ = "BSD 3-Clause License"
|
14
14
|
__copyright__ = "Copyright 2025 Slipstream"
|
15
|
-
__version__ = "0.4.
|
15
|
+
__version__ = "0.4.2"
|
16
16
|
|
17
17
|
from .client import Client, AutoShardedClient
|
18
18
|
from .models import Message, User, Reaction, AuditLogEntry
|
@@ -38,6 +38,35 @@ from .logging_config import setup_logging
|
|
38
38
|
import logging
|
39
39
|
|
40
40
|
|
41
|
+
__all__ = [
|
42
|
+
"Client",
|
43
|
+
"AutoShardedClient",
|
44
|
+
"Message",
|
45
|
+
"User",
|
46
|
+
"Reaction",
|
47
|
+
"AuditLogEntry",
|
48
|
+
"VoiceClient",
|
49
|
+
"AudioSource",
|
50
|
+
"FFmpegAudioSource",
|
51
|
+
"Typing",
|
52
|
+
"DisagreementException",
|
53
|
+
"HTTPException",
|
54
|
+
"GatewayException",
|
55
|
+
"AuthenticationError",
|
56
|
+
"Forbidden",
|
57
|
+
"NotFound",
|
58
|
+
"Color",
|
59
|
+
"utcnow",
|
60
|
+
"message_pager",
|
61
|
+
"GatewayIntent",
|
62
|
+
"GatewayOpcode",
|
63
|
+
"setup_global_error_handler",
|
64
|
+
"HybridContext",
|
65
|
+
"tasks",
|
66
|
+
"setup_logging",
|
67
|
+
]
|
68
|
+
|
69
|
+
|
41
70
|
# Configure a default logger if none has been configured yet
|
42
71
|
if not logging.getLogger().hasHandlers():
|
43
72
|
setup_logging(logging.INFO)
|
disagreement/cache.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import time
|
4
|
-
from typing import TYPE_CHECKING, Dict, Generic, Optional, TypeVar
|
4
|
+
from typing import TYPE_CHECKING, Callable, Dict, Generic, Optional, TypeVar
|
5
5
|
from collections import OrderedDict
|
6
6
|
|
7
7
|
if TYPE_CHECKING:
|
@@ -40,6 +40,14 @@ class Cache(Generic[T]):
|
|
40
40
|
self._data.move_to_end(key)
|
41
41
|
return value
|
42
42
|
|
43
|
+
def get_or_fetch(self, key: str, fetch_fn: Callable[[], T]) -> T:
|
44
|
+
"""Return a cached item or fetch and store it if missing."""
|
45
|
+
value = self.get(key)
|
46
|
+
if value is None:
|
47
|
+
value = fetch_fn()
|
48
|
+
self.set(key, value)
|
49
|
+
return value
|
50
|
+
|
43
51
|
def invalidate(self, key: str) -> None:
|
44
52
|
self._data.pop(key, None)
|
45
53
|
|
disagreement/client.py
CHANGED
@@ -529,15 +529,29 @@ class Client:
|
|
529
529
|
print(f"Message: {message.content}")
|
530
530
|
"""
|
531
531
|
|
532
|
-
def decorator(
|
533
|
-
coro: Callable[..., Awaitable[None]],
|
534
|
-
) -> Callable[..., Awaitable[None]]:
|
535
|
-
if not asyncio.iscoroutinefunction(coro):
|
536
|
-
raise TypeError("Event registered must be a coroutine function.")
|
537
|
-
self._event_dispatcher.register(event_name.upper(), coro)
|
538
|
-
return coro
|
539
|
-
|
540
|
-
return decorator
|
532
|
+
def decorator(
|
533
|
+
coro: Callable[..., Awaitable[None]],
|
534
|
+
) -> Callable[..., Awaitable[None]]:
|
535
|
+
if not asyncio.iscoroutinefunction(coro):
|
536
|
+
raise TypeError("Event registered must be a coroutine function.")
|
537
|
+
self._event_dispatcher.register(event_name.upper(), coro)
|
538
|
+
return coro
|
539
|
+
|
540
|
+
return decorator
|
541
|
+
|
542
|
+
def add_listener(
|
543
|
+
self, event_name: str, coro: Callable[..., Awaitable[None]]
|
544
|
+
) -> None:
|
545
|
+
"""Register ``coro`` to listen for ``event_name``."""
|
546
|
+
|
547
|
+
self._event_dispatcher.register(event_name, coro)
|
548
|
+
|
549
|
+
def remove_listener(
|
550
|
+
self, event_name: str, coro: Callable[..., Awaitable[None]]
|
551
|
+
) -> None:
|
552
|
+
"""Remove ``coro`` from ``event_name`` listeners."""
|
553
|
+
|
554
|
+
self._event_dispatcher.unregister(event_name, coro)
|
541
555
|
|
542
556
|
async def _process_message_for_commands(self, message: "Message") -> None:
|
543
557
|
"""Internal listener to process messages for commands."""
|
@@ -1311,8 +1325,8 @@ class Client:
|
|
1311
1325
|
|
1312
1326
|
return self._messages.get(message_id)
|
1313
1327
|
|
1314
|
-
async def fetch_guild(self, guild_id: Snowflake) -> Optional["Guild"]:
|
1315
|
-
"""Fetches a guild by ID from Discord and caches it."""
|
1328
|
+
async def fetch_guild(self, guild_id: Snowflake) -> Optional["Guild"]:
|
1329
|
+
"""Fetches a guild by ID from Discord and caches it."""
|
1316
1330
|
|
1317
1331
|
if self._closed:
|
1318
1332
|
raise DisagreementException("Client is closed.")
|
@@ -1326,7 +1340,19 @@ class Client:
|
|
1326
1340
|
return self.parse_guild(guild_data)
|
1327
1341
|
except DisagreementException as e:
|
1328
1342
|
print(f"Failed to fetch guild {guild_id}: {e}")
|
1329
|
-
return None
|
1343
|
+
return None
|
1344
|
+
|
1345
|
+
async def fetch_guilds(self) -> List["Guild"]:
|
1346
|
+
"""Fetch all guilds the current user is in."""
|
1347
|
+
|
1348
|
+
if self._closed:
|
1349
|
+
raise DisagreementException("Client is closed.")
|
1350
|
+
|
1351
|
+
data = await self._http.get_current_user_guilds()
|
1352
|
+
guilds: List["Guild"] = []
|
1353
|
+
for guild_data in data:
|
1354
|
+
guilds.append(self.parse_guild(guild_data))
|
1355
|
+
return guilds
|
1330
1356
|
|
1331
1357
|
async def fetch_channel(self, channel_id: Snowflake) -> Optional["Channel"]:
|
1332
1358
|
"""Fetches a channel from Discord by its ID and updates the cache."""
|
disagreement/event_dispatcher.py
CHANGED
@@ -60,6 +60,7 @@ class EventDispatcher:
|
|
60
60
|
"GUILD_BAN_REMOVE": self._parse_guild_ban_remove,
|
61
61
|
"GUILD_ROLE_UPDATE": self._parse_guild_role_update,
|
62
62
|
"TYPING_START": self._parse_typing_start,
|
63
|
+
"VOICE_STATE_UPDATE": self._parse_voice_state_update,
|
63
64
|
}
|
64
65
|
|
65
66
|
def _parse_message_create(self, data: Dict[str, Any]) -> Message:
|
@@ -111,6 +112,13 @@ class EventDispatcher:
|
|
111
112
|
|
112
113
|
return TypingStart(data, client_instance=self._client)
|
113
114
|
|
115
|
+
def _parse_voice_state_update(self, data: Dict[str, Any]):
|
116
|
+
"""Parses raw VOICE_STATE_UPDATE data into a VoiceStateUpdate object."""
|
117
|
+
|
118
|
+
from .models import VoiceStateUpdate
|
119
|
+
|
120
|
+
return VoiceStateUpdate(data, client_instance=self._client)
|
121
|
+
|
114
122
|
def _parse_message_reaction(self, data: Dict[str, Any]):
|
115
123
|
"""Parses raw reaction data into a Reaction object."""
|
116
124
|
|
disagreement/http.py
CHANGED
@@ -839,9 +839,13 @@ class HTTPClient:
|
|
839
839
|
use_auth_header=False,
|
840
840
|
)
|
841
841
|
|
842
|
-
async def get_user(self, user_id: "Snowflake") -> Dict[str, Any]:
|
843
|
-
"""Fetches a user object for a given user ID."""
|
844
|
-
return await self.request("GET", f"/users/{user_id}")
|
842
|
+
async def get_user(self, user_id: "Snowflake") -> Dict[str, Any]:
|
843
|
+
"""Fetches a user object for a given user ID."""
|
844
|
+
return await self.request("GET", f"/users/{user_id}")
|
845
|
+
|
846
|
+
async def get_current_user_guilds(self) -> List[Dict[str, Any]]:
|
847
|
+
"""Returns the guilds the current user is in."""
|
848
|
+
return await self.request("GET", "/users/@me/guilds")
|
845
849
|
|
846
850
|
async def get_guild_member(
|
847
851
|
self, guild_id: "Snowflake", user_id: "Snowflake"
|
disagreement/models.py
CHANGED
@@ -106,14 +106,21 @@ class Message:
|
|
106
106
|
]
|
107
107
|
else:
|
108
108
|
self.components = None
|
109
|
-
self.attachments: List[Attachment] = [
|
110
|
-
Attachment(a) for a in data.get("attachments", [])
|
111
|
-
]
|
112
|
-
self.pinned: bool = data.get("pinned", False)
|
113
|
-
# Add other fields as needed, e.g., attachments, embeds, reactions, etc.
|
114
|
-
# self.mentions: List[User] = [User(u) for u in data.get("mentions", [])]
|
115
|
-
# self.mention_roles: List[str] = data.get("mention_roles", [])
|
116
|
-
# self.mention_everyone: bool = data.get("mention_everyone", False)
|
109
|
+
self.attachments: List[Attachment] = [
|
110
|
+
Attachment(a) for a in data.get("attachments", [])
|
111
|
+
]
|
112
|
+
self.pinned: bool = data.get("pinned", False)
|
113
|
+
# Add other fields as needed, e.g., attachments, embeds, reactions, etc.
|
114
|
+
# self.mentions: List[User] = [User(u) for u in data.get("mentions", [])]
|
115
|
+
# self.mention_roles: List[str] = data.get("mention_roles", [])
|
116
|
+
# self.mention_everyone: bool = data.get("mention_everyone", False)
|
117
|
+
|
118
|
+
@property
|
119
|
+
def jump_url(self) -> str:
|
120
|
+
"""Return a URL that jumps to this message in the Discord client."""
|
121
|
+
|
122
|
+
guild_or_dm = self.guild_id or "@me"
|
123
|
+
return f"https://discord.com/channels/{guild_or_dm}/{self.channel_id}/{self.id}"
|
117
124
|
|
118
125
|
@property
|
119
126
|
def clean_content(self) -> str:
|
@@ -624,14 +631,31 @@ class File:
|
|
624
631
|
self.data = data
|
625
632
|
|
626
633
|
|
627
|
-
class AllowedMentions:
|
634
|
+
class AllowedMentions:
|
628
635
|
"""Represents allowed mentions for a message or interaction response."""
|
629
636
|
|
630
|
-
def __init__(self, data: Dict[str, Any]):
|
631
|
-
self.parse: List[str] = data.get("parse", [])
|
632
|
-
self.roles: List[str] = data.get("roles", [])
|
633
|
-
self.users: List[str] = data.get("users", [])
|
634
|
-
self.replied_user: bool = data.get("replied_user", False)
|
637
|
+
def __init__(self, data: Dict[str, Any]):
|
638
|
+
self.parse: List[str] = data.get("parse", [])
|
639
|
+
self.roles: List[str] = data.get("roles", [])
|
640
|
+
self.users: List[str] = data.get("users", [])
|
641
|
+
self.replied_user: bool = data.get("replied_user", False)
|
642
|
+
|
643
|
+
@classmethod
|
644
|
+
def all(cls) -> "AllowedMentions":
|
645
|
+
"""Return an instance allowing all mention types."""
|
646
|
+
|
647
|
+
return cls(
|
648
|
+
{
|
649
|
+
"parse": ["users", "roles", "everyone"],
|
650
|
+
"replied_user": True,
|
651
|
+
}
|
652
|
+
)
|
653
|
+
|
654
|
+
@classmethod
|
655
|
+
def none(cls) -> "AllowedMentions":
|
656
|
+
"""Return an instance disallowing all mentions."""
|
657
|
+
|
658
|
+
return cls({"parse": [], "replied_user": False})
|
635
659
|
|
636
660
|
def to_dict(self) -> Dict[str, Any]:
|
637
661
|
payload: Dict[str, Any] = {"parse": self.parse}
|
@@ -2467,7 +2491,7 @@ class PresenceUpdate:
|
|
2467
2491
|
return f"<PresenceUpdate user_id='{self.user.id}' guild_id='{self.guild_id}' status='{self.status}'>"
|
2468
2492
|
|
2469
2493
|
|
2470
|
-
class TypingStart:
|
2494
|
+
class TypingStart:
|
2471
2495
|
"""Represents a TYPING_START event."""
|
2472
2496
|
|
2473
2497
|
def __init__(
|
@@ -2480,10 +2504,39 @@ class TypingStart:
|
|
2480
2504
|
self.timestamp: int = data["timestamp"]
|
2481
2505
|
self.member: Optional[Member] = (
|
2482
2506
|
Member(data["member"], client_instance) if data.get("member") else None
|
2483
|
-
)
|
2484
|
-
|
2485
|
-
def __repr__(self) -> str:
|
2486
|
-
return f"<TypingStart channel_id='{self.channel_id}' user_id='{self.user_id}'>"
|
2507
|
+
)
|
2508
|
+
|
2509
|
+
def __repr__(self) -> str:
|
2510
|
+
return f"<TypingStart channel_id='{self.channel_id}' user_id='{self.user_id}'>"
|
2511
|
+
|
2512
|
+
|
2513
|
+
class VoiceStateUpdate:
|
2514
|
+
"""Represents a VOICE_STATE_UPDATE event."""
|
2515
|
+
|
2516
|
+
def __init__(
|
2517
|
+
self, data: Dict[str, Any], client_instance: Optional["Client"] = None
|
2518
|
+
):
|
2519
|
+
self._client = client_instance
|
2520
|
+
self.guild_id: Optional[str] = data.get("guild_id")
|
2521
|
+
self.channel_id: Optional[str] = data.get("channel_id")
|
2522
|
+
self.user_id: str = data["user_id"]
|
2523
|
+
self.member: Optional[Member] = (
|
2524
|
+
Member(data["member"], client_instance) if data.get("member") else None
|
2525
|
+
)
|
2526
|
+
self.session_id: str = data["session_id"]
|
2527
|
+
self.deaf: bool = data.get("deaf", False)
|
2528
|
+
self.mute: bool = data.get("mute", False)
|
2529
|
+
self.self_deaf: bool = data.get("self_deaf", False)
|
2530
|
+
self.self_mute: bool = data.get("self_mute", False)
|
2531
|
+
self.self_stream: Optional[bool] = data.get("self_stream")
|
2532
|
+
self.self_video: bool = data.get("self_video", False)
|
2533
|
+
self.suppress: bool = data.get("suppress", False)
|
2534
|
+
|
2535
|
+
def __repr__(self) -> str:
|
2536
|
+
return (
|
2537
|
+
f"<VoiceStateUpdate guild_id='{self.guild_id}' user_id='{self.user_id}' "
|
2538
|
+
f"channel_id='{self.channel_id}'>"
|
2539
|
+
)
|
2487
2540
|
|
2488
2541
|
|
2489
2542
|
class Reaction:
|
disagreement/voice_client.py
CHANGED
@@ -259,5 +259,20 @@ class VoiceClient:
|
|
259
259
|
self._udp.close()
|
260
260
|
if self._udp_receive_thread:
|
261
261
|
self._udp_receive_thread.join(timeout=1)
|
262
|
-
if self._sink:
|
263
|
-
self._sink.close()
|
262
|
+
if self._sink:
|
263
|
+
self._sink.close()
|
264
|
+
|
265
|
+
async def __aenter__(self) -> "VoiceClient":
|
266
|
+
"""Enter the context manager by connecting to the voice gateway."""
|
267
|
+
await self.connect()
|
268
|
+
return self
|
269
|
+
|
270
|
+
async def __aexit__(
|
271
|
+
self,
|
272
|
+
exc_type: Optional[type],
|
273
|
+
exc: Optional[BaseException],
|
274
|
+
tb: Optional[BaseException],
|
275
|
+
) -> bool:
|
276
|
+
"""Exit the context manager and close the connection."""
|
277
|
+
await self.close()
|
278
|
+
return False
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: disagreement
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.2
|
4
4
|
Summary: A Python library for the Discord API.
|
5
5
|
Author-email: Slipstream <me@slipstreamm.dev>
|
6
6
|
License: BSD 3-Clause
|
@@ -46,6 +46,7 @@ A Python library for interacting with the Discord API, with a focus on bot devel
|
|
46
46
|
- Gateway and HTTP API clients
|
47
47
|
- Slash command framework
|
48
48
|
- Message component helpers
|
49
|
+
- `Message.jump_url` property for quick links to messages
|
49
50
|
- Built-in caching layer
|
50
51
|
- Experimental voice support
|
51
52
|
- Helpful error handling utilities
|
@@ -153,9 +154,10 @@ session parameter supported by ``aiohttp``.
|
|
153
154
|
Specify default mention behaviour for all outgoing messages when constructing the client:
|
154
155
|
|
155
156
|
```python
|
157
|
+
from disagreement.models import AllowedMentions
|
156
158
|
client = disagreement.Client(
|
157
159
|
token=token,
|
158
|
-
allowed_mentions=
|
160
|
+
allowed_mentions=AllowedMentions.none().to_dict(),
|
159
161
|
)
|
160
162
|
```
|
161
163
|
|
@@ -192,6 +194,14 @@ guild = await client.fetch_guild("123456789012345678")
|
|
192
194
|
roles = await client.fetch_roles(guild.id)
|
193
195
|
```
|
194
196
|
|
197
|
+
Call `Client.fetch_guilds` to list all guilds the current user has access to.
|
198
|
+
|
199
|
+
```python
|
200
|
+
guilds = await client.fetch_guilds()
|
201
|
+
for g in guilds:
|
202
|
+
print(g.name)
|
203
|
+
```
|
204
|
+
|
195
205
|
## Sharding
|
196
206
|
|
197
207
|
To run your bot across multiple gateway shards, pass ``shard_count`` when creating
|
@@ -1,21 +1,21 @@
|
|
1
|
-
disagreement/__init__.py,sha256=
|
1
|
+
disagreement/__init__.py,sha256=SEe8hwL_hzJj8c2gjFJG35OV-f-10owc4NbpdC3gnu0,1646
|
2
2
|
disagreement/audio.py,sha256=erBaupz-Hw8LR-5mGLDvhphCDAQeWk0ZBA0AMVwDUIM,4360
|
3
|
-
disagreement/cache.py,sha256=
|
3
|
+
disagreement/cache.py,sha256=9yit7gIro0nEngBQUsBLHN2gGWTZ2EYiBMrfgcu5LVM,3157
|
4
4
|
disagreement/caching.py,sha256=KEicB8fIBRwc5Ifl1CCHHnPu-NfAvqdfArjxFuV557g,3841
|
5
|
-
disagreement/client.py,sha256=
|
5
|
+
disagreement/client.py,sha256=W-8DwXxcZEAjaIZfZVKy49CZMhXDf4-WIrBnSvd4cFc,68285
|
6
6
|
disagreement/color.py,sha256=0RumZU9geS51rmmywwotmkXFc8RyQghOviRGGrHmvW4,4495
|
7
7
|
disagreement/components.py,sha256=tEYJ2RHVpIFtZuPPxZ0v8ssUw_x7ybhYBzHNsRiXXvU,5250
|
8
8
|
disagreement/enums.py,sha256=F_DHgeAnnw17ILswOuxPR6G1OimL6aeuxIEAni1XPyY,11187
|
9
9
|
disagreement/error_handler.py,sha256=rj9AiJhRLPNAaAY6Gj0KQXgKNfPsgnZUtyTljclybD8,1161
|
10
10
|
disagreement/errors.py,sha256=Zi7x_hgGXCDw5ht2HpcQDba4NQbXkBbjQIVhU9RVyhE,32236
|
11
|
-
disagreement/event_dispatcher.py,sha256=
|
11
|
+
disagreement/event_dispatcher.py,sha256=0vCLYRPSihuf1qmLBY9KFjj85bVWUxB8s7uhJvMbyy4,11745
|
12
12
|
disagreement/gateway.py,sha256=7ccRygL1gnd_w8DldsLFxreZy1iCdw6Nw65_UW8Ulz8,26831
|
13
|
-
disagreement/http.py,sha256=
|
13
|
+
disagreement/http.py,sha256=IRaEhhQvfnSX5HM_2r3OTvrMdPK-suhoi7l2Wsl3X-c,51915
|
14
14
|
disagreement/hybrid_context.py,sha256=VYCmcreTZdPBU9v-Cy48W38vgWO2t8nM2ulC6_z4HjU,1095
|
15
15
|
disagreement/i18n.py,sha256=1L4rcFuKP0XjHk9dVwbNh4BkLk2ZlxxZ_-tecGWa9S0,718
|
16
16
|
disagreement/interactions.py,sha256=moN2iQEE9ntC-Y2Q7uxUqoBBRYHegNwB00w-2UD30q4,21703
|
17
17
|
disagreement/logging_config.py,sha256=4q6baQPE6X_0lfaBTFMU1uqc03x5SbJqo2hsApdDFac,686
|
18
|
-
disagreement/models.py,sha256=
|
18
|
+
disagreement/models.py,sha256=q6txqdQ0EpUqeZbn24BYRqDl3mJ1lO2qPnnB4mnhyFU,99839
|
19
19
|
disagreement/oauth.py,sha256=TfDdCwg1J7osM9wDi61dtNBA5BrQk5DeQrrHsYycH34,2810
|
20
20
|
disagreement/permissions.py,sha256=7g5cIlg-evHXOL0-pmtT5EwqcB-stXot1HZSLz724sE,3008
|
21
21
|
disagreement/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -23,7 +23,7 @@ disagreement/rate_limiter.py,sha256=ubwR_UTPs2MotipBdtqpgwQKx0IHt2I3cdfFcXTFv7g,
|
|
23
23
|
disagreement/shard_manager.py,sha256=gE7562izYcN-5jTDWUP9kIFX5gffRjIryqNxk1mtnSM,2128
|
24
24
|
disagreement/typing.py,sha256=_1oFWfZ4HyH5Q3bnF7CO24s79z-3_B5Qb69kWiwLhhU,1242
|
25
25
|
disagreement/utils.py,sha256=mz7foTCOAmUv9n8EcdZeiFarwqB14xHOG8o0p8tFuKA,2014
|
26
|
-
disagreement/voice_client.py,sha256=
|
26
|
+
disagreement/voice_client.py,sha256=mn7wiE_HzUibaTPY-xCP7b8AkOx4ioeR7zF2YUqC7ok,9700
|
27
27
|
disagreement/ext/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
28
28
|
disagreement/ext/loader.py,sha256=9_uULvNAa-a6UiaeQhWglwgIrHEPKbf9bnWtSL1KV5Q,1408
|
29
29
|
disagreement/ext/tasks.py,sha256=b14KI-btikbrjPlD76md3Ggt6znrxPqr7TDarU4PYBg,7269
|
@@ -48,8 +48,8 @@ disagreement/ui/item.py,sha256=bm-EmQEZpe8Kt8JrRw-o0uQdccgjErORcFsBqaXOcV8,1112
|
|
48
48
|
disagreement/ui/modal.py,sha256=w0ZEVslXzx2-RWUP4jdVB54zDuT81jpueVWZ70byFnI,4137
|
49
49
|
disagreement/ui/select.py,sha256=XjWRlWkA09QZaDDLn-wDDOWIuj0Mb4VCWJEOAaExZXw,3018
|
50
50
|
disagreement/ui/view.py,sha256=UdOaoSe0NZXZMjOtM8CLCPcDHVf6Dn2yr2PHLSvoJsg,5834
|
51
|
-
disagreement-0.4.
|
52
|
-
disagreement-0.4.
|
53
|
-
disagreement-0.4.
|
54
|
-
disagreement-0.4.
|
55
|
-
disagreement-0.4.
|
51
|
+
disagreement-0.4.2.dist-info/licenses/LICENSE,sha256=zfmtgJhVFHnqT7a8LAQFthXu5bP7EEHmEL99trV66Ew,1474
|
52
|
+
disagreement-0.4.2.dist-info/METADATA,sha256=Y4OVIt8mHGWsb9fuyL51QiVXVrObftm4g7TQVEATmL0,6590
|
53
|
+
disagreement-0.4.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
54
|
+
disagreement-0.4.2.dist-info/top_level.txt,sha256=t7FY_3iaYhdB6X6y9VybJ2j7UZbVeRUe9wRgH8d5Gtk,13
|
55
|
+
disagreement-0.4.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|