kioku-space

As a personal memory space.

How to Skip Cell Execution in Jupyter Notebook

In this article, I’ll show you how to skip the execution of cells in Jupyter Notebook based on certain conditions.
The methods described here are applicable to Google Colaboratory and Kaggle Notebooks.

To skip cell execution, create a custom magic command as follows:

  1. First, create a skip magic command that does nothing.

    from IPython.core.magic import register_cell_magic
    
    @register_cell_magic
    def skip(line, cell):
        return
  2. To skip a cell, simply add %%skip at the top line of the cell.

Building a Discord Chatbot with Python (9) - Adding Interactive Buttons to Chat Messages

In this installment, we’ll dive deeply into how to add interactive buttons to your chat messages in Discord. Additionally, we’ll explore the variety of responses you can trigger when these buttons are pressed.

Note
Given that this article aims to be a comprehensive guide on Discord bot interactions, it’s a bit longer than our previous posts.

Discord provides a framework for adding “message components” (or simply “components”), which are interactive elements you can place within chat messages.
(See: Message Components)

Building a Discord Chatbot with Python (8) - Adding Options to Bot Commands

Continuing from our last session, we’ll be using discord.ext.commands to add options to our chatbot commands.
(Reference: Documentation)

We’ll add a new ‘category’ option to the ‘quiz’ feature, allowing for quizzes in various categories.
Additionally, we’ll introduce a ’timeout’ option to adjust the time limit for answering questions.

In our previous article, we refactored the code using discord.py’s extension, discord.ext.commands.

The code for the ‘quiz’ feature, found in commands/quiz.py, is as follows:

Building a Discord Chatbot with Python (7) - Refactoring Code Using Discord.py's Extension

In this article, we’ll leverage the discord.ext.commands extension in discord.py
to refactor our somewhat complex on_message function.

The code up to our last session is as follows:
We added !omikuji and !quiz commands, which made the on_message function somewhat bloated.

import asyncio
import json
import random

import discord


class MyClient(discord.Client):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        quiz_file = 'python_problems.en.json'
        with open(quiz_file) as f:
            self.quiz_list = json.load(f)

    async def on_ready(self):
        """Triggered when connecting to Discord."""
        print(f'Connected as {self.user}.')

    async def on_message(self, message: discord.Message):
        """Triggered when receiving a message."""
        # Ignore messages sent by the bot itself
        if message.author == self.user:
            return

        print(f'Received a message from {message.author}: {message.content}')

        if message.content == '!omikuji':
            choice = random.choice([
                "Great Blessing", "Blessing", "Small Blessing",
                "Misfortune", "Great Misfortune"
            ])
            await message.channel.send(
                f"Your fortune for today is: **{choice}**!"
            )

        if message.content == '!quiz':
            def quiz_reply_check(m: discord.Message):
                """Function to validate quiz replies."""
                return m.author == message.author and m.content.isdigit()

            quiz = random.choice(self.quiz_list)
            quiz_str = (
                f'Q: {quiz["question"]}\n\n' +
                '\n'.join([
                    f'[{i+1}] {c}' for (i, c) in enumerate(quiz["choices"])
                ])
            )
            await message.channel.send(quiz_str)
            try:
                reply_message = await self.wait_for(
                    'message', check=quiz_reply_check, timeout=30
                )
                if reply_message.content == str(quiz['answer_num']):
                    result = "😀 Correct!"
                else:
                    result = \
                        f"😢 Sorry, the correct answer is {quiz['answer_num']}."
            except asyncio.TimeoutError:
                result = \
                    f"😢 Time's up! The correct answer is {quiz['answer_num']}."

            await message.channel.send(result)


with open('.discord_token') as f:
    token = f.read().strip()

intents = discord.Intents.default()
intents.message_content = True
client = MyClient(intents=intents)
client.run(token)

As we add more commands like before, repetitive logic increases, and our on_message becomes bulky.

Building a Discord Chatbot with Python (6) - Adding a 'Quiz' Feature

In this post, we’ll introduce a method to wait for user replies and leverage it to add a new ‘Quiz’ feature to our chatbot.

Previously, we delved into how to reply to user messages.
We then employed this mechanism to incorporate a ‘fortune-telling’ feature.

import discord
import random


class MyClient(discord.Client):
    async def on_ready(self):
        """Triggered when connecting to Discord."""
        print(f'Connected as {self.user}.')

    async def on_message(self, message: discord.Message):
        """Triggered when receiving a message."""
        # Ignore messages sent by the bot itself
        if message.author == self.user:
            return

        print(f'Received a message from {message.author}: {message.content}')

        if message.content == '!omikuji':
            choice = random.choice([
                "Great Blessing", "Blessing", "Small Blessing",
                "Misfortune", "Great Misfortune"
            ])
            await message.channel.send(
                f"Your fortune for today is: **{choice}**!"
            )


with open('.discord_token') as f:
    token = f.read().strip()

intents = discord.Intents.default()
intents.message_content = True
client = MyClient(intents=intents)
client.run(token)

Till now, our chatbot has been capable of a one-round communication, responding to a user’s message.

Building a Discord Chatbot with Python (5) - Adding a 'Fortune Telling' Feature

In this article, we’ll expand our chatbot by enabling it to respond to user messages.
We’ll also introduce a fun ‘Fortune Telling’ feature to our chatbot.

As of our previous session, our chatbot can now receive user messages in a chat.
Here’s what our chatbot.py script currently looks like:

import discord


class MyClient(discord.Client):
    async def on_ready(self):
        """Triggered when connecting to Discord."""
        print(f'Connected as {self.user}.')

    async def on_message(self, message: discord.Message):
        """Triggered when receiving a message."""
        print(f'Received a message from {message.author}: {message.content}')


with open('.discord_token') as f:
    token = f.read().strip()

intents = discord.Intents.default()
intents.message_content = True
client = MyClient(intents=intents)
client.run(token)

Let’s now enable our chatbot to reply to user messages within the on_message method.
But there’s something we should be wary of: