AdvancedTagScript 3.3.0__py3-none-any.whl → 3.3.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.
@@ -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")
@@ -1,5 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  import datetime
2
- from typing import Any, Dict, Optional, Tuple, cast
4
+ from typing import Any, Optional, Tuple, cast
3
5
 
4
6
  import discord
5
7
 
@@ -23,20 +25,59 @@ __all__: Tuple[str, ...] = ("RedCommandAdapter", "RedBotAdapter")
23
25
 
24
26
 
25
27
  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
+ 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
+ """
28
60
 
29
61
  def __init__(self, base: Command, *, signature: Optional[str] = None) -> None:
30
- super().__init__(base=base)
62
+ if not _has_redbot:
63
+ raise ImportError(
64
+ "A Red-DiscordBot instance is required to use this.", name="redbot"
65
+ )
31
66
  self.signature: Optional[str] = signature
67
+ super().__init__(base=base)
32
68
 
33
69
  def update_attributes(self) -> None:
34
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
35
74
  self._attributes.update(
36
75
  {
37
76
  "name": command.name,
38
77
  "cog_name": getattr(command, "cog_name", None),
39
- "description": getattr(command, "description", None),
78
+ "description": description,
79
+ "short_doc": short_doc,
80
+ "help": getattr(command, "help", None),
40
81
  "aliases": humanize_list(list(getattr(command, "aliases", []))) or "None",
41
82
  "qualified_name": command.qualified_name,
42
83
  "signature": self.signature,
@@ -78,13 +119,17 @@ class RedBotAdapter(SimpleAdapter["Red"]):
78
119
  discriminator
79
120
  The bot's discriminator.
80
121
  nick
81
- The bot's nickname, if they have one, else their username.
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.
82
125
  created_at
83
126
  The bot's creation date.
84
127
  timestamp
85
128
  The bot's creation date as a UTC timestamp.
86
129
  mention
87
130
  A formatted text that pings the bot.
131
+ avatar
132
+ A link to the bot's avatar, which can be used in embeds.
88
133
  verified
89
134
  If the bot is verified or not.
90
135
  shard_count (*)
@@ -100,18 +145,28 @@ class RedBotAdapter(SimpleAdapter["Red"]):
100
145
  unique_users (*)
101
146
  The bot's unique user count.
102
147
  percentage_chunked (*)
103
- Percentage of chunked guilds the bot has.
148
+ Percentage of the bot's members that are cached/chunked (rounded to two
149
+ decimals); ``0`` when no member counts are available.
104
150
 
105
- .. warning::
106
- Attributes denoting ``(*)`` can only be used by the bot owner.
151
+ Attributes marked ``(*)`` are owner-only and return nothing for other users.
107
152
  """
108
-
109
- if not _has_redbot:
110
- raise ImportError("A Red-DiscordBot instance is required to use this.")
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
+ )
111
164
 
112
165
  def __init__(self, base: Red, *, owner: bool = True) -> None:
113
- super().__init__(base=base)
166
+ if not _has_redbot:
167
+ raise ImportError("A Red-DiscordBot instance is required to use this.")
114
168
  self.is_owner: bool = owner
169
+ super().__init__(base=base)
115
170
 
116
171
  def update_attributes(self) -> None:
117
172
  self.user: discord.ClientUser = cast(discord.ClientUser, self.object.user)
@@ -124,35 +179,51 @@ class RedBotAdapter(SimpleAdapter["Red"]):
124
179
  "name": self.user.name,
125
180
  "discriminator": self.user.discriminator,
126
181
  "nick": self.user.display_name,
127
- "mention": self.user.display_avatar.url,
182
+ "mention": self.user.mention,
183
+ "avatar": (self.user.display_avatar.url, False),
128
184
  "created_at": created_at,
129
185
  "timestamp": int(created_at.timestamp()),
130
186
  "verified": self.user.verified,
131
187
  }
132
188
  )
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)
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
148
211
 
149
212
  def get_value(self, ctx: Verb) -> str:
150
213
  should_escape: bool = False
151
214
  if ctx.parameter is None:
152
215
  return_value: str = "{0.name}#{0.discriminator}".format(self.user)
153
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)
154
225
  try:
155
- value: Any = self._attributes[ctx.parameter]
226
+ value: Any = self._attributes[parameter]
156
227
  except KeyError:
157
228
  return # type: ignore
158
229
  if isinstance(value, tuple):
@@ -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
 
TagScriptEngine/utils.py CHANGED
@@ -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,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,20 +1,20 @@
1
- TagScriptEngine/__init__.py,sha256=v1jE2WhSkANRnPWLj4UieHunkkCnO6aNEaACln7u2dI,6143
1
+ TagScriptEngine/__init__.py,sha256=QfGmahJ3D2bD2JqBcpgWcwpLTojka6t7jRH_yvJh0Xc,6144
2
2
  TagScriptEngine/_warnings.py,sha256=pfMXaEVGpIue0eqgzZ6HkLXEka1UGl61-yuH9uEnVe4,2662
3
3
  TagScriptEngine/exceptions.py,sha256=lhvskKi2AySE5pul_iAA251jdMv-92QkjodR4X-G27Y,2833
4
4
  TagScriptEngine/interpreter.py,sha256=5kF0kEqaZf5Hyu8tkmDDLEy7y-qvd6xiUJ3GwpDDh44,16638
5
5
  TagScriptEngine/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- TagScriptEngine/utils.py,sha256=Kq7_w6nuJizPYZDJIzXZ51b1ea92_7Vm_YDKbQci7F4,1697
6
+ TagScriptEngine/utils.py,sha256=b5PnxFLmz7ubb_PFd4xK79iUQwWrg2KUx-gJlep2gOM,1666
7
7
  TagScriptEngine/verb.py,sha256=nk5IenRRGuwzIY7cMyGQn7aVYvmGcNTszztAQTSHP54,5047
8
8
  TagScriptEngine/adapter/__init__.py,sha256=9ohds_8-zbVKZobQCE7xb96XrF6Be8lCSjJCJHHSuDM,1266
9
- TagScriptEngine/adapter/discordadapters.py,sha256=l_6HijmmGDRX7lhahskH6mTteJFpS7IcMEvnKPqIQhY,19005
9
+ TagScriptEngine/adapter/discordadapters.py,sha256=vOILu1tWNSpYM1s1kUcjQzM3T2fkBSSGo4xrkgOdJgA,19470
10
10
  TagScriptEngine/adapter/functionadapter.py,sha256=lQlWm0dO-41bTQ2etFpWRaGnG22V1HMy9aiB8FnFZOU,591
11
11
  TagScriptEngine/adapter/intadapter.py,sha256=jENx5ah8k0U1PjJccV0NiYFsWFU9ZXTFgz3f-qx30SA,548
12
12
  TagScriptEngine/adapter/objectadapter.py,sha256=7bW-Qd6gujq2ALdK3p0ONoCSPWCTv6srkkDNjzkvDEU,1017
13
- TagScriptEngine/adapter/redbotadapters.py,sha256=9a0EDSmelI-RJF6Mgpti1fogsNIAvNoC3F40aTKGKgk,5936
13
+ TagScriptEngine/adapter/redbotadapters.py,sha256=0TjQ6t0ONuPDEyl1rLvjj4uL0goQxB5Ts8AcRfxBA_w,8740
14
14
  TagScriptEngine/adapter/stringadapter.py,sha256=VaJzkm1b8b7w1T90DjR3gOH0DIsZlWtcFe1YG7DOqBQ,1710
15
15
  TagScriptEngine/block/__init__.py,sha256=zfoPTCTBDIuOkcjKnNL8gYIRKOi4c4gkYNwNJPvYctQ,3223
16
16
  TagScriptEngine/block/allowedmentions.py,sha256=WMGWi1Fe0U_vUBsc4uyiX1XfQjGkhpdlyvq3HhCCLd4,2219
17
- TagScriptEngine/block/assign.py,sha256=lgJY_hUIjrKPm4N9vWr_rxhrKejGrMRbBG3oasb0hAI,8657
17
+ TagScriptEngine/block/assign.py,sha256=JtYvbyB_nXm0Hf3FKawCdRCWP1V5Een1hAXwnLGOyHc,8723
18
18
  TagScriptEngine/block/breakblock.py,sha256=nt3T7fDhTxH0jpO8lu0_3oC4XwVuKKg9cmkdLsZwzL8,1288
19
19
  TagScriptEngine/block/case.py,sha256=SF4uaAWyC9AiBzoI5SPDCaRx6wrY-_0IQDI1T_mZFvk,1503
20
20
  TagScriptEngine/block/command.py,sha256=3xKo5H3K8F7BpxeHJp9I80n0QWvk_GHQCQpKnvQ7ZxQ,4309
@@ -44,8 +44,8 @@ TagScriptEngine/block/urlencodeblock.py,sha256=sWqdSBk-uTZZjebKhAFmlROvnQvLcjvyI
44
44
  TagScriptEngine/interface/__init__.py,sha256=37lAOMONKmWDLiC5Ox9Y3TNQUQbzW54oUugbQe0e9gc,341
45
45
  TagScriptEngine/interface/adapter.py,sha256=4jBBz7hc-8fsRSZ5DWOrUxrhXqS0SvJCdW57TZl8sQo,1967
46
46
  TagScriptEngine/interface/block.py,sha256=S0hWRH6uqBz_cYRIh3LGMyo63UK6gNidtf6EiLUKL0c,3653
47
- advancedtagscript-3.3.0.dist-info/licenses/LICENSE,sha256=NvdimESU3jrNgd_8E4i-eTecQ_jGegRrrWk1v2gOnHY,252
48
- advancedtagscript-3.3.0.dist-info/METADATA,sha256=Jk7KqEwJRIWH9XZrCbZCELDLF2vl121n3jMSaRc4-J0,3565
49
- advancedtagscript-3.3.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
50
- advancedtagscript-3.3.0.dist-info/top_level.txt,sha256=6lY4lZDvWxraERrit1lvDsCCDdfo9e83kk_tBemAJCo,16
51
- advancedtagscript-3.3.0.dist-info/RECORD,,
47
+ advancedtagscript-3.3.2.dist-info/licenses/LICENSE,sha256=NvdimESU3jrNgd_8E4i-eTecQ_jGegRrrWk1v2gOnHY,252
48
+ advancedtagscript-3.3.2.dist-info/METADATA,sha256=GbVFcPOX0J9V-ir-xtSyjnMjU8ms-WKlOQgIRRx5VCI,3565
49
+ advancedtagscript-3.3.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
50
+ advancedtagscript-3.3.2.dist-info/top_level.txt,sha256=6lY4lZDvWxraERrit1lvDsCCDdfo9e83kk_tBemAJCo,16
51
+ advancedtagscript-3.3.2.dist-info/RECORD,,