Adapters

These adapters are used to supply data to a TagScript script, most prominently when using the seed_variables parameter to provide seed variables to the process() method of a given interpreter instance. These adapters are also used internally when a script contains a AssignmentBlock.

Their stored values are accessed through variable blocks in TagScript.

Example: How to use an IntAdapter
 1from ya_tagscript import TagScriptInterpreter, adapters, blocks
 2
 3used_blocks = [
 4    blocks.StrictVariableGetterBlock(),
 5]
 6interpreter = TagScriptInterpreter(used_blocks)
 7
 8script = "His power level is over {level}!!"
 9
10seeds = {
11    "level": adapters.IntAdapter(9000),
12}
13
14response = interpreter.process(script, seed_variables=seeds)
15print(response.body)  # His power level is over 9000!!

Reference

Basic adapters

These adapters are used to provide simple values to the interpreter.

class ya_tagscript.adapters.IntAdapter(integer: int)[source]

Bases: AdapterABC

An adapter for integers

class ya_tagscript.adapters.FunctionAdapter(function: Callable[[], Any])[source]

Bases: AdapterABC

An adapter for a simple, no-arg function

Caution

The provided function CANNOT take ANY arguments.

class ya_tagscript.adapters.ObjectAdapter(base: object)[source]

Bases: AdapterABC

An adapter for any sort of Python object

Caution

The following things are unsupported and will be rejected

  • Methods

  • Private attributes (names starting with _)

  • Nested attributes (obj.a.b)

    • obj.a is accepted

    • obj.a.b is not accepted

  • Float attributes will be truncated into integer values (12.97 -> 12)

class ya_tagscript.adapters.StringAdapter(string: str, *, should_escape: bool = False)[source]

Bases: AdapterABC

An adapter for strings

Retrieving partial substrings with parameters

You can optionally use parameters to limit what parts of the string should be retrieved.

If you provide a single number n as the parameter, the n-th word of the string is returned (split by spaces). The first word is at index 1, and so on (1-indexed).

Examples:

# Assume my_string_variable holds "Hello there. General Kenobi."
{my_string_variable(2)}
# there.

{my_string_variable(3)}
# General

If you provide a single number followed (or preceded) by a plus, all words after (or before) are returned (split by spaces).

Examples:

# Assume my_string_variable holds "Hello there. General Kenobi."
{my_string_variable(3+)}
# General Kenobi.

{my_string_variable(+2)}
# Hello there.

You can define the characters to split the string on by passing a payload. The string will then be split at occurrences of those characters.

Examples:

# Assume my_string_variable holds "Hello there. General Kenobi."
{my_string_variable(2):.}
# General Kenobi

{my_string_variable(3):en}
# obi.

Discord adapters

These adapters connect the more complex Discord-specific types to the interpreter, e.g. discord.Member.

class ya_tagscript.adapters.AttributeAdapter(base: Any)[source]

Bases: AdapterABC

A basic Discord object adapter

Attributes:

  • id: int — The object’s ID

  • created_at: datetime — Represents the object’s creation time

  • timestamp: int — The seconds-based timestamp of the object’s created_at attribute

  • name: str — The object’s name or the stringified version of the object if no name exists

class ya_tagscript.adapters.ChannelAdapter(channel: Any)[source]

Bases: AttributeAdapter

A discord.TextChannel adapter

Note

Only discord.TextChannel instances are fully supported. The constructor accepts Any to avoid type checking issues when creating this adapter with the discord.ext.commands.Context.channel attribute, which could be any kind of channel. This loose typing allows the construction with that attribute but doesn’t set any of the discord.TextChannel-specific attributes.

Attributes:

(from base AttributeAdapter)

  • id: int — The channel’s ID

  • created_at: datetime — Represents the channel’s creation time

  • timestamp: int — The seconds-based timestamp of the channel’s created_at attribute

  • name: str — The channel’s name

(discord.TextChannel-specific)

  • nsfw: bool — Whether this discord.TextChannel is marked as NSFW and is therefore age-gated

  • mention: str — The mention string for this channel

  • topic: str — The channel’s topic or an empty string if no topic is set

  • slowmode: int — The slowmode delay of the channel in seconds (0 represents a disabled slowmode)

  • position: int — The position of the channel in the channel list

Changed in version 1.3: topic now falls back to an empty string

class ya_tagscript.adapters.GuildAdapter(guild: Guild)[source]

Bases: AttributeAdapter

A discord.Guild adapter

Attributes:

(from base AttributeAdapter)

  • id: int — The guild’s ID

  • created_at: datetime — Represents the guild’s creation time

  • timestamp: int — The seconds-based timestamp of the guild’s created_at attribute

  • name: str — The guild’s name

(discord.Guild-specific)

  • icon: tuple[str, Literal[False]] — The guild’s icon. The first tuple element contains the icon’s URL or is empty. The False instructs the adapter to not escape the contents of this attribute.

  • member_count: int | None — The number of members in this guild (alias: members) (Can be None under some circumstances)

  • members: int | None — The number of members in this guild (alias: member_count) (Can be None under some circumstances)

  • bots: int — The number of bots in this guild

  • humans: int — The number of human users in this guild

  • description: str — The guild’s description

  • random: discord.Member — Returns a randomly chosen member of the guild

class ya_tagscript.adapters.MemberAdapter(member: Member | User)[source]

Bases: AttributeAdapter

A discord.Member and discord.User adapter

Attributes:

(from base AttributeAdapter)

  • id: int — The user’s ID

  • created_at: datetime — Represents the user’s creation time

  • timestamp: int — The seconds-based timestamp of the user’s created_at attribute

  • name: str — The user’s name

(discord.Member or discord.User-specific)

  • color: discord.Colour — The colour the user’s name is shown in (depends on their top role) (alias: colour)

  • colour: discord.Colour — The colour the user’s name is shown in (depends on their top role) (alias: color)

  • global_name: str — The user’s global nickname (falls back to name if the user has no global nickname set)

  • nick: str — The user’s guild-specific nickname (falls back to global_name if no guild-specific nickname is set, or to name if no global nickname is set either)

  • avatar tuple[str, Literal[False]] — The user’s avatar. The first tuple element contains the avatar’s URL. The False instructs the adapter to not escape the contents of this attribute.

  • discriminator: str — The user’s discriminator

  • joined_at: datetime — The user’s time of joining this guild. If the user has left the guild, this falls back to the user’s creation time.

  • joinstamp: int — The seconds-based timestamp of the user’s joined_at attribute

  • mention: str — The mention string for this user

  • bot: bool — Whether this user is a bot account

  • top_role: discord.Role — The user’s topmost role

  • roleids: str — A space-separated list of the IDs of each role of this user.

Note

This adapter also supports discord.User as a convenience matter. For example, the author attribute of the discord.ext.commands.Context could be a Member or a User, depending on whether the command was used in a guild or not.

Some attributes that don’t make sense on non-discord.Member users fall back to sensible defaults:

  • joined_at falls back to the value of created_at

  • nick falls back to the value of global_name

  • top_role falls back to an empty string

  • roleids falls back to an empty string

Changed in version 1.2: Now supports passing a discord.User as well, with fallback values as described above.

Changed in version 1.3:

  • For members without nicknames, nick now falls back to global_name if possible, or name if the member also has no global nickname.

  • For users without global nicknames, global_name now falls back to name.

Example

Using an adapter for a discord.Member in a tiny Discord bot[1]

For this example, assume the invoking user has the ID 123.

Using a MemberAdapter with a discord.py bot
 1import discord
 2from discord.ext import commands
 3
 4from ya_tagscript import TagScriptInterpreter, adapters, blocks
 5
 6intents = discord.Intents.default()
 7intents.message_content = True
 8
 9bot = commands.Bot(command_prefix="$", intents=intents)
10
11used_blocks = [
12    blocks.StrictVariableGetterBlock(),
13]
14interpreter = TagScriptInterpreter(blocks=used_blocks)
15script = "{user(id)}"
16
17
18@bot.command()
19@commands.guild_only()
20async def test(ctx: commands.Context):
21    if isinstance(ctx.author, discord.User):
22        return await ctx.send("Guilds only, friend!")
23
24    seeds = {
25        "user": adapters.MemberAdapter(ctx.author),
26    }
27    response = interpreter.process(script, seed_variables=seeds)
28    print(response.body)  # 123
29    return await ctx.send(response.body)  # sends message "123" to the invoking channel
30
31
32bot.run("token")  # use your own bot's token

Footnotes