AdvancedTagScript 3.3.0__tar.gz → 3.3.2__tar.gz

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.
Files changed (64) hide show
  1. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/AdvancedTagScript.egg-info/PKG-INFO +1 -1
  2. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/PKG-INFO +1 -1
  3. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/__init__.py +1 -1
  4. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/adapter/discordadapters.py +15 -17
  5. advancedtagscript-3.3.2/TagScriptEngine/adapter/redbotadapters.py +232 -0
  6. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/assign.py +11 -5
  7. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/utils.py +0 -2
  8. advancedtagscript-3.3.0/TagScriptEngine/adapter/redbotadapters.py +0 -161
  9. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/AdvancedTagScript.egg-info/SOURCES.txt +0 -0
  10. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/AdvancedTagScript.egg-info/dependency_links.txt +0 -0
  11. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/AdvancedTagScript.egg-info/requires.txt +0 -0
  12. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/AdvancedTagScript.egg-info/top_level.txt +0 -0
  13. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/LICENSE +0 -0
  14. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/MANIFEST.in +0 -0
  15. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/README.md +0 -0
  16. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/_warnings.py +0 -0
  17. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/adapter/__init__.py +0 -0
  18. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/adapter/functionadapter.py +0 -0
  19. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/adapter/intadapter.py +0 -0
  20. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/adapter/objectadapter.py +0 -0
  21. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/adapter/stringadapter.py +0 -0
  22. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/__init__.py +0 -0
  23. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/allowedmentions.py +0 -0
  24. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/breakblock.py +0 -0
  25. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/case.py +0 -0
  26. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/command.py +0 -0
  27. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/control.py +0 -0
  28. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/cooldown.py +0 -0
  29. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/count.py +0 -0
  30. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/cycleblock.py +0 -0
  31. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/embedblock.py +0 -0
  32. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/fiftyfifty.py +0 -0
  33. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/helpers.py +0 -0
  34. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/joinblock.py +0 -0
  35. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/listblock.py +0 -0
  36. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/loosevariablegetter.py +0 -0
  37. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/mathblock.py +0 -0
  38. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/ordblock.py +0 -0
  39. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/randomblock.py +0 -0
  40. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/range.py +0 -0
  41. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/redirect.py +0 -0
  42. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/replaceblock.py +0 -0
  43. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/require_blacklist.py +0 -0
  44. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/shortcutredirect.py +0 -0
  45. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/stopblock.py +0 -0
  46. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/strf.py +0 -0
  47. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/strictvariablegetter.py +0 -0
  48. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/substr.py +0 -0
  49. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/block/urlencodeblock.py +0 -0
  50. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/exceptions.py +0 -0
  51. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/interface/__init__.py +0 -0
  52. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/interface/adapter.py +0 -0
  53. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/interface/block.py +0 -0
  54. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/interpreter.py +0 -0
  55. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/py.typed +0 -0
  56. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/TagScriptEngine/verb.py +0 -0
  57. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/pyproject.toml +0 -0
  58. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/setup.cfg +0 -0
  59. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/setup.py +0 -0
  60. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/tests/test_adapters.py +0 -0
  61. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/tests/test_basic.py +0 -0
  62. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/tests/test_edgecase.py +0 -0
  63. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/tests/test_escapes.py +0 -0
  64. {advancedtagscript-3.3.0 → advancedtagscript-3.3.2}/tests/test_verbs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AdvancedTagScript
3
- Version: 3.3.0
3
+ Version: 3.3.2
4
4
  Summary: An easy drop in user-provided Templating system.
5
5
  Home-page: https://github.com/cool-aid-man/TagScriptEngine
6
6
  Author: cool-aid-man, inthedark.org, PhenoM4n4n
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AdvancedTagScript
3
- Version: 3.3.0
3
+ Version: 3.3.2
4
4
  Summary: An easy drop in user-provided Templating system.
5
5
  Home-page: https://github.com/cool-aid-man/TagScriptEngine
6
6
  Author: cool-aid-man, inthedark.org, PhenoM4n4n
@@ -181,7 +181,7 @@ __all__: Tuple[str, ...] = (
181
181
  )
182
182
 
183
183
 
184
- __version__: Final[str] = "3.3.0"
184
+ __version__: Final[str] = "3.3.2"
185
185
 
186
186
 
187
187
  class VersionNamedTuple(NamedTuple):
@@ -103,7 +103,6 @@ class DiscordAttributeAdapter(
103
103
  ]
104
104
  ):
105
105
  """
106
- .. versionadded:: 3.2.0
107
106
  """
108
107
 
109
108
  def __init__(
@@ -191,7 +190,6 @@ class UserAdapter(DiscordAttributeAdapter):
191
190
  avatar_decoration
192
191
  A link to the user's avatar decoration.
193
192
 
194
- .. versionadded:: 3.2.0
195
193
  """
196
194
 
197
195
  def update_attributes(self) -> None:
@@ -260,16 +258,26 @@ class MemberAdapter(DiscordAttributeAdapter):
260
258
  If the user has boosted, this will be the UTC timestamp of when they did,
261
259
  if not this will be empty.
262
260
  timed_out
263
- If the user is timed out, this will be the UTC timestamp of when they'll be untimed-out,
264
- if not timed out this will be empty.
261
+ If the user is currently timed out, the datetime of when the timeout ends;
262
+ otherwise ``False``.
265
263
  banner
266
- The users banner url
264
+ The user's banner url, if available. A banner is not delivered over the
265
+ gateway, so the bare engine only sees it when the member was retrieved
266
+ via an explicit REST fetch - otherwise this is empty for cached members.
267
+ The Tags cog resolves it lazily (fetching only when a tag uses ``banner``,
268
+ with caching and a per-user cooldown), so there it is populated on demand.
267
269
  """
268
270
 
269
271
  def update_attributes(self) -> None:
270
272
  object: discord.Member = cast(discord.Member, self.object)
271
273
  avatar_url: str = object.display_avatar.url
272
274
  joined_at: datetime.datetime = getattr(object, "joined_at", self.object.created_at)
275
+ # So ``timed_out_until`` must be compared against the current time.
276
+ # And Returns ``False`` when the member isn't currently timed out.
277
+ timed_out_until: Any = getattr(object, "timed_out_until", None)
278
+ is_timed_out: bool = bool(timed_out_until) and timed_out_until > discord.utils.utcnow()
279
+ # ``Member.banner``/``display_banner`` is now explicitly fetched.
280
+ banner: Any = getattr(object, "display_banner", None) or getattr(object, "banner", None)
273
281
  additional_attributes: Dict[str, Any] = {
274
282
  "color": object.color,
275
283
  "colour": object.color,
@@ -282,8 +290,8 @@ class MemberAdapter(DiscordAttributeAdapter):
282
290
  "bot": object.bot,
283
291
  "top_role": getattr(object, "top_role", ""),
284
292
  "boost": getattr(object, "premium_since", ""),
285
- "timed_out": getattr(object, "timed_out_until", ""),
286
- "banner": object.banner.url if object.banner else "",
293
+ "timed_out": timed_out_until if is_timed_out else False,
294
+ "banner": banner.url if banner else "",
287
295
  }
288
296
  if roleids := getattr(self.object, "_roles", None):
289
297
  additional_attributes["roleids"] = " ".join(str(r) for r in roleids)
@@ -315,7 +323,6 @@ class DMChannelAdapter(DiscordAttributeAdapter):
315
323
  jump_url
316
324
  A link to the channel.
317
325
 
318
- .. versionadded:: 3.2.0
319
326
  """
320
327
 
321
328
  def update_attributes(self) -> None:
@@ -359,9 +366,6 @@ class ChannelAdapter(DiscordAttributeAdapter):
359
366
  If no category channel, this will return empty.
360
367
  jump_url
361
368
  A link to the channel.
362
-
363
- .. versionchanged:: 3.2.0
364
- Added ``jump_url`` as a parameter.
365
369
  """
366
370
 
367
371
  def update_attributes(self) -> None:
@@ -429,10 +433,6 @@ class GuildAdapter(DiscordAttributeAdapter):
429
433
  A link to the server's invite splash.
430
434
  banner
431
435
  A link to the server's banner.
432
-
433
- .. versionchanged:: 3.2.0
434
- Added ``mfa``, ``boosters``, ``boost_level``,
435
- ``discovery_splash``, ``invite_splash`` & ``banner``.
436
436
  """
437
437
 
438
438
  def update_attributes(self) -> None:
@@ -509,7 +509,6 @@ class RoleAdapter(DiscordAttributeAdapter):
509
509
  position
510
510
  The role's position.
511
511
 
512
- .. versionadded:: 3.2.0
513
512
  """
514
513
 
515
514
  def update_attributes(self) -> None:
@@ -546,7 +545,6 @@ class DiscordObjectAdapter(Adapter):
546
545
  timestamp
547
546
  The object's creation date as a UTC timestamp.
548
547
 
549
- .. versionadded:: 3.2.0
550
548
  """
551
549
 
552
550
  __slots__: Tuple[str, ...] = ("object", "_attributes", "_methods")
@@ -0,0 +1,232 @@
1
+ from __future__ import annotations
2
+
3
+ import datetime
4
+ from typing import Any, Optional, Tuple, cast
5
+
6
+ import discord
7
+
8
+ from ..verb import Verb
9
+ from ..interface import SimpleAdapter
10
+ from ..utils import escape_content
11
+
12
+ try:
13
+ import redbot # noqa: F401
14
+ except ModuleNotFoundError:
15
+ _has_redbot = False
16
+ else:
17
+ _has_redbot = True
18
+
19
+ from redbot.core.bot import Red
20
+ from redbot.core.commands import Command
21
+ from redbot.core.utils.chat_formatting import humanize_number, humanize_list
22
+
23
+
24
+ __all__: Tuple[str, ...] = ("RedCommandAdapter", "RedBotAdapter")
25
+
26
+
27
+ class RedCommandAdapter(SimpleAdapter["Command"]):
28
+ """
29
+ The ``{commandinfo}`` block reads a command's metadata and returns it as
30
+ text. Unlike the :ref:`Command Block`, it does **not** run the command.
31
+ See the attribute list below.
32
+
33
+ **Usage:** ``{commandinfo([attribute]):<command>}``
34
+
35
+ **Payload:** command (supplied by the block)
36
+
37
+ **Parameter:** attribute, None
38
+
39
+ Attributes
40
+ ----------
41
+ name
42
+ The command's name.
43
+ qualified_name
44
+ The command's full name, including any parent groups.
45
+ cog_name
46
+ The name of the cog the command belongs to.
47
+ description
48
+ The command's description. Most commands leave this unset, so it falls
49
+ back to the help text's first line (``short_doc``) when empty.
50
+ short_doc
51
+ The first line of the command's help text.
52
+ help
53
+ The command's full help text (its docstring).
54
+ aliases
55
+ The command's aliases, or ``None`` if it has none.
56
+ signature
57
+ The command's argument signature. Empty for commands that take no
58
+ arguments.
59
+ """
60
+
61
+ def __init__(self, base: Command, *, signature: Optional[str] = None) -> None:
62
+ if not _has_redbot:
63
+ raise ImportError(
64
+ "A Red-DiscordBot instance is required to use this.", name="redbot"
65
+ )
66
+ self.signature: Optional[str] = signature
67
+ super().__init__(base=base)
68
+
69
+ def update_attributes(self) -> None:
70
+ command: Command = self.object
71
+ # As no command sets ``description`` so the docstring goes to ``help`` (and ``short_doc`` is its first line).
72
+ short_doc: str = getattr(command, "short_doc", "") or ""
73
+ description: str = getattr(command, "description", "") or short_doc
74
+ self._attributes.update(
75
+ {
76
+ "name": command.name,
77
+ "cog_name": getattr(command, "cog_name", None),
78
+ "description": description,
79
+ "short_doc": short_doc,
80
+ "help": getattr(command, "help", None),
81
+ "aliases": humanize_list(list(getattr(command, "aliases", []))) or "None",
82
+ "qualified_name": command.qualified_name,
83
+ "signature": self.signature,
84
+ }
85
+ )
86
+
87
+ def get_value(self, ctx: Verb) -> str:
88
+ should_escape: bool = False
89
+ if ctx.parameter is None:
90
+ return_value: str = self.object.qualified_name
91
+ else:
92
+ try:
93
+ value: Any = self._attributes[ctx.parameter]
94
+ except KeyError:
95
+ return # type: ignore
96
+ if isinstance(value, tuple):
97
+ value, should_escape = value
98
+ return_value: str = str(value) if value is not None else None # type: ignore
99
+ return escape_content(return_value) if should_escape else return_value
100
+
101
+
102
+ class RedBotAdapter(SimpleAdapter["Red"]):
103
+ """
104
+ The ``{bot}`` block with no parameters returns the bot's name & discriminator,
105
+ but passing the attributes listed below to the block payload will return that attribute instead.
106
+
107
+ **Usage:** ``{bot([attribute])}``
108
+
109
+ **Payload:** None
110
+
111
+ **Parameter:** attribute, None
112
+
113
+ Attributes
114
+ ----------
115
+ id
116
+ The bot's Discord ID.
117
+ name
118
+ The bot's username.
119
+ discriminator
120
+ The bot's discriminator.
121
+ nick
122
+ The bot's global display name. This is not a per-server nickname: the
123
+ bot user has no guild context here, so a server-specific nick is not
124
+ available through this block.
125
+ created_at
126
+ The bot's creation date.
127
+ timestamp
128
+ The bot's creation date as a UTC timestamp.
129
+ mention
130
+ A formatted text that pings the bot.
131
+ avatar
132
+ A link to the bot's avatar, which can be used in embeds.
133
+ verified
134
+ If the bot is verified or not.
135
+ shard_count (*)
136
+ The bot's total shard count.
137
+ servers (*)
138
+ Total server/guild count of the bot.
139
+ channels (*)
140
+ Total number of channels visible to the bot.
141
+ visible_users (*)
142
+ Total number of users visible to the bot.
143
+ total_users (*)
144
+ The bot's total user count.
145
+ unique_users (*)
146
+ The bot's unique user count.
147
+ percentage_chunked (*)
148
+ Percentage of the bot's members that are cached/chunked (rounded to two
149
+ decimals); ``0`` when no member counts are available.
150
+
151
+ Attributes marked ``(*)`` are owner-only and return nothing for other users.
152
+ """
153
+
154
+ # Bot-Owner Only attributes since these require iterating the whole guild/member cache.
155
+ OWNER_ATTRIBUTES: Tuple[str, ...] = (
156
+ "shard_count",
157
+ "servers",
158
+ "channels",
159
+ "visible_users",
160
+ "total_users",
161
+ "unique_users",
162
+ "percentage_chunked",
163
+ )
164
+
165
+ def __init__(self, base: Red, *, owner: bool = True) -> None:
166
+ if not _has_redbot:
167
+ raise ImportError("A Red-DiscordBot instance is required to use this.")
168
+ self.is_owner: bool = owner
169
+ super().__init__(base=base)
170
+
171
+ def update_attributes(self) -> None:
172
+ self.user: discord.ClientUser = cast(discord.ClientUser, self.object.user)
173
+ created_at: datetime.datetime = getattr(
174
+ self.user, "created_at", None
175
+ ) or discord.utils.snowflake_time(self.user.id)
176
+ self._attributes.update(
177
+ {
178
+ "id": self.user.id,
179
+ "name": self.user.name,
180
+ "discriminator": self.user.discriminator,
181
+ "nick": self.user.display_name,
182
+ "mention": self.user.mention,
183
+ "avatar": (self.user.display_avatar.url, False),
184
+ "created_at": created_at,
185
+ "timestamp": int(created_at.timestamp()),
186
+ "verified": self.user.verified,
187
+ }
188
+ )
189
+
190
+ def _compute_owner_attribute(self, name: str) -> Any:
191
+ bot: Red = self.object
192
+ if name == "shard_count":
193
+ # ``shard_count`` is None on an unsharded bot.
194
+ return humanize_number(bot.shard_count or 1)
195
+ if name == "servers":
196
+ return humanize_number(len(bot.guilds))
197
+ if name == "channels":
198
+ return humanize_number(sum(len(g.channels) for g in bot.guilds))
199
+ if name == "unique_users":
200
+ return humanize_number(len(bot.users))
201
+ visible_users: int = sum(len(g.members) for g in bot.guilds)
202
+ if name == "visible_users":
203
+ return humanize_number(visible_users)
204
+ total_users: int = sum(g.member_count or 0 for g in bot.guilds)
205
+ if name == "total_users":
206
+ return humanize_number(total_users)
207
+ if name == "percentage_chunked":
208
+ # Guard against a bot in no guilds / with no counted members.
209
+ return round(visible_users / total_users * 100, 2) if total_users else 0
210
+ return None
211
+
212
+ def get_value(self, ctx: Verb) -> str:
213
+ should_escape: bool = False
214
+ if ctx.parameter is None:
215
+ return_value: str = "{0.name}#{0.discriminator}".format(self.user)
216
+ else:
217
+ parameter: str = ctx.parameter
218
+ if parameter in self.OWNER_ATTRIBUTES:
219
+ # Owner-only: hidden from non-owners, computed on demand (and
220
+ # cached in ``_attributes``) the first time an owner asks for it.
221
+ if not self.is_owner:
222
+ return # type: ignore
223
+ if parameter not in self._attributes:
224
+ self._attributes[parameter] = self._compute_owner_attribute(parameter)
225
+ try:
226
+ value: Any = self._attributes[parameter]
227
+ except KeyError:
228
+ return # type: ignore
229
+ if isinstance(value, tuple):
230
+ value, should_escape = value
231
+ return_value: str = str(value) if value is not None else None # type: ignore
232
+ return escape_content(return_value) if should_escape else return_value
@@ -55,8 +55,10 @@ class AssignmentBlock(verb_required_block(False, parameter=True)): # type: igno
55
55
  - You can name variables with **anything** ``except`` existing block names or aliases.
56
56
  - They will ``not`` reference the value in payload, if the name is same as an existing block name or alias.
57
57
 
58
- ----
59
-
58
+ .. raw:: html
59
+
60
+ <hr>
61
+
60
62
  .. important:: How Argument Parsing Works - In Detail
61
63
 
62
64
  - A variable is essentially a string that can be treated as a sequence of elements (words, numbers, etc.) when accessed.
@@ -66,8 +68,10 @@ class AssignmentBlock(verb_required_block(False, parameter=True)): # type: igno
66
68
  to extract ``specific`` parts. Let's take a look at **how** it works.
67
69
  - Parsing out of bounds index will return the whole string.
68
70
 
69
- ----
70
-
71
+ .. raw:: html
72
+
73
+ <hr>
74
+
71
75
  .. rubric:: **Basic Argument Parsing**
72
76
 
73
77
  Example
@@ -148,7 +152,9 @@ class AssignmentBlock(verb_required_block(False, parameter=True)): # type: igno
148
152
  - ``-n`` → nth element from end
149
153
  - ``-n+`` → nth element from end → then forward to end (index resolved first)
150
154
 
151
- -----
155
+ .. raw:: html
156
+
157
+ <hr>
152
158
 
153
159
  .. rubric:: **Advanced Argument Parsing**
154
160
 
@@ -33,8 +33,6 @@ def truncate(text: str, *, max: int = 2000, var: str = "...") -> str:
33
33
  -------
34
34
  str
35
35
  The truncated content.
36
-
37
- .. versionadded:: 3.2.0
38
36
  """
39
37
  if len(text) <= max:
40
38
  return text
@@ -1,161 +0,0 @@
1
- import datetime
2
- from typing import Any, Dict, Optional, Tuple, cast
3
-
4
- import discord
5
-
6
- from ..verb import Verb
7
- from ..interface import SimpleAdapter
8
- from ..utils import escape_content
9
-
10
- try:
11
- import redbot # noqa: F401
12
- except ModuleNotFoundError:
13
- _has_redbot = False
14
- else:
15
- _has_redbot = True
16
-
17
- from redbot.core.bot import Red
18
- from redbot.core.commands import Command
19
- from redbot.core.utils.chat_formatting import humanize_number, humanize_list
20
-
21
-
22
- __all__: Tuple[str, ...] = ("RedCommandAdapter", "RedBotAdapter")
23
-
24
-
25
- class RedCommandAdapter(SimpleAdapter["Command"]):
26
- if not _has_redbot:
27
- raise ImportError("A Red-DiscordBot instance is required to use this.", name="redbot")
28
-
29
- def __init__(self, base: Command, *, signature: Optional[str] = None) -> None:
30
- super().__init__(base=base)
31
- self.signature: Optional[str] = signature
32
-
33
- def update_attributes(self) -> None:
34
- command: Command = self.object
35
- self._attributes.update(
36
- {
37
- "name": command.name,
38
- "cog_name": getattr(command, "cog_name", None),
39
- "description": getattr(command, "description", None),
40
- "aliases": humanize_list(list(getattr(command, "aliases", []))) or "None",
41
- "qualified_name": command.qualified_name,
42
- "signature": self.signature,
43
- }
44
- )
45
-
46
- def get_value(self, ctx: Verb) -> str:
47
- should_escape: bool = False
48
- if ctx.parameter is None:
49
- return_value: str = self.object.qualified_name
50
- else:
51
- try:
52
- value: Any = self._attributes[ctx.parameter]
53
- except KeyError:
54
- return # type: ignore
55
- if isinstance(value, tuple):
56
- value, should_escape = value
57
- return_value: str = str(value) if value is not None else None # type: ignore
58
- return escape_content(return_value) if should_escape else return_value
59
-
60
-
61
- class RedBotAdapter(SimpleAdapter["Red"]):
62
- """
63
- The ``{bot}`` block with no parameters returns the bot's name & discriminator,
64
- but passing the attributes listed below to the block payload will return that attribute instead.
65
-
66
- **Usage:** ``{bot([attribute])}``
67
-
68
- **Payload:** None
69
-
70
- **Parameter:** attribute, None
71
-
72
- Attributes
73
- ----------
74
- id
75
- The bot's Discord ID.
76
- name
77
- The bot's username.
78
- discriminator
79
- The bot's discriminator.
80
- nick
81
- The bot's nickname, if they have one, else their username.
82
- created_at
83
- The bot's creation date.
84
- timestamp
85
- The bot's creation date as a UTC timestamp.
86
- mention
87
- A formatted text that pings the bot.
88
- verified
89
- If the bot is verified or not.
90
- shard_count (*)
91
- The bot's total shard count.
92
- servers (*)
93
- Total server/guild count of the bot.
94
- channels (*)
95
- Total number of channels visible to the bot.
96
- visible_users (*)
97
- Total number of users visible to the bot.
98
- total_users (*)
99
- The bot's total user count.
100
- unique_users (*)
101
- The bot's unique user count.
102
- percentage_chunked (*)
103
- Percentage of chunked guilds the bot has.
104
-
105
- .. warning::
106
- Attributes denoting ``(*)`` can only be used by the bot owner.
107
- """
108
-
109
- if not _has_redbot:
110
- raise ImportError("A Red-DiscordBot instance is required to use this.")
111
-
112
- def __init__(self, base: Red, *, owner: bool = True) -> None:
113
- super().__init__(base=base)
114
- self.is_owner: bool = owner
115
-
116
- def update_attributes(self) -> None:
117
- self.user: discord.ClientUser = cast(discord.ClientUser, self.object.user)
118
- created_at: datetime.datetime = getattr(
119
- self.user, "created_at", None
120
- ) or discord.utils.snowflake_time(self.user.id)
121
- self._attributes.update(
122
- {
123
- "id": self.user.id,
124
- "name": self.user.name,
125
- "discriminator": self.user.discriminator,
126
- "nick": self.user.display_name,
127
- "mention": self.user.display_avatar.url,
128
- "created_at": created_at,
129
- "timestamp": int(created_at.timestamp()),
130
- "verified": self.user.verified,
131
- }
132
- )
133
- if self.is_owner:
134
- visible_users: int = sum(len(g.members) for g in self.object.guilds)
135
- total_users: int = sum(
136
- g.member_count if g.member_count else 0 for g in self.object.guilds
137
- )
138
- owner_attributes: Dict[str, Any] = {
139
- "shard_count": humanize_number(self.object.bot.shard_count),
140
- "servers": humanize_number(len(self.object.guilds)),
141
- "channels": humanize_number(sum(len(g.channels) for g in self.object.guilds)),
142
- "visible_users": humanize_number(visible_users),
143
- "total_users": humanize_number(total_users),
144
- "unique_users": humanize_number(len(self.object.users)),
145
- "percentage_chunked": visible_users / total_users * 100,
146
- }
147
- self._attributes.update(owner_attributes)
148
-
149
- def get_value(self, ctx: Verb) -> str:
150
- should_escape: bool = False
151
- if ctx.parameter is None:
152
- return_value: str = "{0.name}#{0.discriminator}".format(self.user)
153
- else:
154
- try:
155
- value: Any = self._attributes[ctx.parameter]
156
- except KeyError:
157
- return # type: ignore
158
- if isinstance(value, tuple):
159
- value, should_escape = value
160
- return_value: str = str(value) if value is not None else None # type: ignore
161
- return escape_content(return_value) if should_escape else return_value