transformer_discord_notifier.discord

class transformer_discord_notifier.discord.DiscordClient(token: Optional[str] = None, channel: Optional[Union[str, int]] = None)[source]

A blocking wrapper around the asyncio Discord.py client.

_load_credentials() → None[source]

Try to load missing Discord configs (token, channel) from environment variables.

_find_default_channel(name: Optional[str] = None, default_name: str = 'default') → int[source]

Try to find a writable text channel.

Follow the following algorithm:

  1. if name is being provided, search for this channel first

  2. if not found, search for self._discord_channel, then channel that can be configured on instance creation or by loading environment variables. Check first for a channel with the given name as string, then fall back to an integer channel id.

  3. if still not found, search for a channel with a given default name, like “default” or “Allgemein”. As this seems to depend on the language, it might not find one.

If after all this still no channel has been found, either because no channel with the given names/id exists, or because the Discord token gives no acces to guilds/channels which we have access to, we throw a RuntimeError. We now can’t use this callback handler.

Parameters
  • name (Optional[str], optional) – channel name to search for first, by default None

  • default_name (str, optional) – alternative default Discord channel name, by default “default”

Returns

int – channel id

Raises
  • RuntimeError – raised if no guild Discord server found (i.e. Discord bot has no permissions / was not yet invited to a Discord server)

  • RuntimeError – raised if channel could not be found

init()[source]

Initialize Discord bot for accessing Discord/writing messages.

It loads the credentials, starts the asyncio Discord bot in a separate thread and after connecting searches for our target channel.

Raises

RuntimeError – raised on error while initializing the Discord bot, like invalid token or channel not found, etc.

_quit_client()[source]

Internal. Try to properly quit the Discord client if neccessary, and close the asyncio loop if required.

quit()[source]

Shutdown the Discord bot.

Tries to close the Discord bot safely, closes the asyncio loop, waits for the background thread to stop (deamonized, so on program exit it will quit anyway).

send_message(text: str = '', embed: Optional[discord.embeds.Embed] = None) → Optional[int][source]

Sends a message to our Discord channel. Returns the message id.

Parameters
  • text (str, optional) – text message to send, by default “”

  • embed (Optional[discord.Embed], optional) – embed object to attach to message, by default None

Returns

Optional[int] – message id if text and embed were both not None, None if nothing was sent

get_message_by_id(msg_id: int) → Optional[discord.message.Message][source]

Try to retrieve a Discord message by its id.

Parameters

msg_id (int) – message id of message sent in Discord channel

Returns

Optional[discord.Message]None if message could not be found by msg_id, else return the message object

update_or_send_message(msg_id: Optional[int] = None, **fields) → Optional[int][source]

Wrapper for send_message() to updated an existing message, identified by msg_id or simply send a new message if no prior message found.

Parameters
  • msg_id (Optional[int], optional) – message id of prior message sent in channel, if not provided then send a new message.

  • text (str, optional) – text message, if set to None it will remove prior message content

  • embed (Optional[discord.Embed], optional) – Discord embed, set to None to delete existing embed

Returns

Optional[int] – message id of updated or newly sent message, None if nothing was sent

delete_later(msg_id: int, delay: Union[int, float] = 5) → bool[source]

Runs a delayed message deletion function.

Parameters
  • msg_id (int) – message id of message sent in Discord channel

  • delay (Union[int, float], optional) – delay in seconds for then to delete the message, by default 5

Returns

boolTrue if message deletion is queued, False if message could not be found in channel

static build_embed(kvs: Dict[str, Any], title: Optional[str] = None, footer: Optional[str] = None) → discord.embeds.Embed[source]

Builds an rich Embed from key-values.

Parameters
  • kvs (Dict[str, Any]) – Key-Value dictionary for embed fields, non int/float values will be formatted with pprint.pformat()

  • title (Optional[str], optional) – title string, by default None

  • footer (Optional[str], optional) – footer string, by default None

Returns

discord.Embed – embed object to send via send_message()

The DiscordClient can be used standalone, but it might be easier to just extract the module code to avoid having to install all the related transformers requirements. It wraps the asyncio Discord.py client inside a background thread and makes its calls essentially blocking. This eases the usage of it in foreign code that does not uses asyncio.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from transformer_discord_notifier.discord import DiscordClient

# configuration
token = "abc123.xyz..."
channel = "Allgemein"

# create client and start background thread, to connect/login ...
# if token/channel are None, it will try to load from environment variables
client = DiscordClient(token=token, channel=channel)
client.init()

# send message
msg_id = client.send_message("test")

# update message content
msg_id = client.update_or_send_message(text="abc", msg_id=msg_id)

# delete it after 3.1 seconds,
# NOTE: this call will not block!
client.delete_later(msg_id, delay=3.1)

# quit client (cancel outstanding tasks!, quit asyncio thread)
client.quit()