diff options
Diffstat (limited to '')
| -rw-r--r-- | bot/seasons/halloween/__init__.py | 2 | ||||
| -rw-r--r-- | bot/seasons/halloween/candy_collection.py | 48 | ||||
| -rw-r--r-- | bot/seasons/halloween/hacktoberstats.py | 63 | ||||
| -rw-r--r-- | bot/seasons/halloween/halloween_facts.py | 17 | ||||
| -rw-r--r-- | bot/seasons/halloween/halloweenify.py | 11 | ||||
| -rw-r--r-- | bot/seasons/halloween/monstersurvey.py | 26 | ||||
| -rw-r--r-- | bot/seasons/halloween/scarymovie.py | 19 | ||||
| -rw-r--r-- | bot/seasons/halloween/spookyavatar.py | 17 | ||||
| -rw-r--r-- | bot/seasons/halloween/spookygif.py | 10 | ||||
| -rw-r--r-- | bot/seasons/halloween/spookyreact.py | 11 | ||||
| -rw-r--r-- | bot/seasons/halloween/spookysound.py | 16 | ||||
| -rw-r--r-- | bot/utils/halloween/spookifications.py | 17 | 
12 files changed, 138 insertions, 119 deletions
| diff --git a/bot/seasons/halloween/__init__.py b/bot/seasons/halloween/__init__.py index 4b371f14..74c962ed 100644 --- a/bot/seasons/halloween/__init__.py +++ b/bot/seasons/halloween/__init__.py @@ -3,6 +3,8 @@ from bot.seasons import SeasonBase  class Halloween(SeasonBase): +    """Halloween Seasonal event attributes.""" +      name = "halloween"      bot_name = "Spookybot"      greeting = "Happy Halloween!" diff --git a/bot/seasons/halloween/candy_collection.py b/bot/seasons/halloween/candy_collection.py index 80f30a1b..1bfbc00a 100644 --- a/bot/seasons/halloween/candy_collection.py +++ b/bot/seasons/halloween/candy_collection.py @@ -21,6 +21,8 @@ ADD_SKULL_EXISTING_REACTION_CHANCE = 20  # 5%  class CandyCollection: +    """Candy collection game Cog.""" +      def __init__(self, bot):          self.bot = bot          with open(json_location) as candy: @@ -32,9 +34,7 @@ class CandyCollection:              self.get_candyinfo[userid] = userinfo      async def on_message(self, message): -        """ -        Randomly adds candy or skull to certain messages -        """ +        """Randomly adds candy or skull reaction to non-bot messages in the Event channel."""          # make sure its a human message          if message.author.bot: @@ -55,9 +55,7 @@ class CandyCollection:              return await message.add_reaction('\N{CANDY}')      async def on_reaction_add(self, reaction, user): -        """ -        Add/remove candies from a person if the reaction satisfies criteria -        """ +        """Add/remove candies from a person if the reaction satisfies criteria."""          message = reaction.message          # check to ensure the reactor is human @@ -105,8 +103,10 @@ class CandyCollection:      async def reacted_msg_chance(self, message):          """ -        Randomly add a skull or candy to a message if there is a reaction there already -        (higher probability) +        Randomly add a skull or candy reaction to a message if there is a reaction there already. + +        This event has a higher probability of occurring than a reaction add to a message without an +        existing reaction.          """          if random.randint(1, ADD_SKULL_EXISTING_REACTION_CHANCE) == 1: @@ -120,7 +120,8 @@ class CandyCollection:              return await message.add_reaction('\N{CANDY}')      async def ten_recent_msg(self): -        """Get the last 10 messages sent in the channel""" +        """Get the last 10 messages sent in the channel.""" +          ten_recent = []          recent_msg = max(message.id for message                           in self.bot._connection._messages @@ -137,9 +138,7 @@ class CandyCollection:          return ten_recent      async def get_message(self, msg_id): -        """ -        Get the message from it's ID. -        """ +        """Get the message from its ID."""          try:              o = discord.Object(id=msg_id + 1) @@ -156,15 +155,12 @@ class CandyCollection:              return None      async def hacktober_channel(self): -        """ -        Get #hacktoberbot channel from it's id -        """ +        """Get #hacktoberbot channel from its ID.""" +          return self.bot.get_channel(id=Hacktoberfest.channel_id)      async def remove_reactions(self, reaction): -        """ -        Remove all candy/skull reactions -        """ +        """Remove all candy/skull reactions."""          try:              async for user in reaction.users(): @@ -174,26 +170,22 @@ class CandyCollection:              pass      async def send_spook_msg(self, author, channel, candies): -        """ -        Send a spooky message -        """ +        """Send a spooky message.""" +          e = discord.Embed(colour=author.colour)          e.set_author(name="Ghosts and Ghouls and Jack o' lanterns at night; "                            f"I took {candies} candies and quickly took flight.")          await channel.send(embed=e)      def save_to_json(self): -        """ -        Save json to the file. -        """ +        """Save JSON to a local file.""" +          with open(json_location, 'w') as outfile:              json.dump(self.candy_json, outfile)      @commands.command()      async def candy(self, ctx): -        """ -        Get the candy leaderboard and save to json when this is called -        """ +        """Get the candy leaderboard and save to JSON."""          # use run_in_executor to prevent blocking          thing = functools.partial(self.save_to_json) @@ -230,5 +222,7 @@ class CandyCollection:  def setup(bot): +    """Candy Collection game Cog load.""" +      bot.add_cog(CandyCollection(bot))      log.debug("CandyCollection cog loaded") diff --git a/bot/seasons/halloween/hacktoberstats.py b/bot/seasons/halloween/hacktoberstats.py index 41cf10ee..3e2a261d 100644 --- a/bot/seasons/halloween/hacktoberstats.py +++ b/bot/seasons/halloween/hacktoberstats.py @@ -14,6 +14,8 @@ log = logging.getLogger(__name__)  class HacktoberStats: +    """Hacktoberfest statistics Cog.""" +      def __init__(self, bot):          self.bot = bot          self.link_json = Path("bot", "resources", "github_links.json") @@ -26,11 +28,13 @@ class HacktoberStats:      )      async def hacktoberstats_group(self, ctx: commands.Context, github_username: str = None):          """ -        If invoked without a subcommand or github_username, get the invoking user's stats if -        they've linked their Discord name to GitHub using .stats link +        Display an embed for a user's Hacktoberfest contributions. -        If invoked with a github_username, get that user's contributions +        If invoked without a subcommand or github_username, get the invoking user's stats if they've +        linked their Discord name to GitHub using .stats link. If invoked with a github_username, +        get that user's contributions          """ +          if not github_username:              author_id, author_mention = HacktoberStats._author_mention_from_context(ctx) @@ -51,7 +55,7 @@ class HacktoberStats:      @hacktoberstats_group.command(name="link")      async def link_user(self, ctx: commands.Context, github_username: str = None):          """ -        Link the invoking user's Github github_username to their Discord ID +        Link the invoking user's Github github_username to their Discord ID.          Linked users are stored as a nested dict:              { @@ -61,6 +65,7 @@ class HacktoberStats:                  }              }          """ +          author_id, author_mention = HacktoberStats._author_mention_from_context(ctx)          if github_username:              if str(author_id) in self.linked_accounts.keys(): @@ -83,9 +88,8 @@ class HacktoberStats:      @hacktoberstats_group.command(name="unlink")      async def unlink_user(self, ctx: commands.Context): -        """ -        Remove the invoking user's account link from the log -        """ +        """Remove the invoking user's account link from the log.""" +          author_id, author_mention = HacktoberStats._author_mention_from_context(ctx)          stored_user = self.linked_accounts.pop(author_id, None) @@ -100,7 +104,7 @@ class HacktoberStats:      def load_linked_users(self) -> typing.Dict:          """ -        Load list of linked users from local JSON file +        Load list of linked users from local JSON file.          Linked users are stored as a nested dict:              { @@ -110,6 +114,7 @@ class HacktoberStats:                  }              }          """ +          if self.link_json.exists():              logging.info(f"Loading linked GitHub accounts from '{self.link_json}'")              with open(self.link_json, 'r') as fID: @@ -123,7 +128,7 @@ class HacktoberStats:      def save_linked_users(self):          """ -        Save list of linked users to local JSON file +        Save list of linked users to local JSON file.          Linked users are stored as a nested dict:              { @@ -133,6 +138,7 @@ class HacktoberStats:                  }              }          """ +          logging.info(f"Saving linked_accounts to '{self.link_json}'")          with open(self.link_json, 'w') as fID:              json.dump(self.linked_accounts, fID, default=str) @@ -140,16 +146,15 @@ class HacktoberStats:      async def get_stats(self, ctx: commands.Context, github_username: str):          """ -        Query GitHub's API for PRs created by a GitHub user during the month of October that -        do not have an 'invalid' tag +        Query GitHub's API for PRs created by a GitHub user during the month of October. -        For example: -            !getstats heavysaturn +        PRs with the 'invalid' tag are ignored          If a valid github_username is provided, an embed is generated and posted to the channel          Otherwise, post a helpful error message          """ +          async with ctx.typing():              prs = await self.get_october_prs(github_username) @@ -160,9 +165,8 @@ class HacktoberStats:                  await ctx.send(f"No October GitHub contributions found for '{github_username}'")      def build_embed(self, github_username: str, prs: typing.List[dict]) -> discord.Embed: -        """ -        Return a stats embed built from github_username's PRs -        """ +        """Return a stats embed built from github_username's PRs.""" +          logging.info(f"Building Hacktoberfest embed for GitHub user: '{github_username}'")          pr_stats = self._summarize_prs(prs) @@ -202,8 +206,9 @@ class HacktoberStats:      @staticmethod      async def get_october_prs(github_username: str) -> typing.List[dict]:          """ -        Query GitHub's API for PRs created during the month of October by github_username -        that do not have an 'invalid' tag +        Query GitHub's API for PRs created during the month of October by github_username. + +        PRs with an 'invalid' tag are ignored          If PRs are found, return a list of dicts with basic PR information @@ -216,6 +221,7 @@ class HacktoberStats:          Otherwise, return None          """ +          logging.info(f"Generating Hacktoberfest PR query for GitHub user: '{github_username}'")          base_url = "https://api.github.com/search/issues?q="          not_label = "invalid" @@ -265,20 +271,21 @@ class HacktoberStats:      @staticmethod      def _get_shortname(in_url: str) -> str:          """ -        Extract shortname from https://api.github.com/repos/* URL +        Extract shortname from https://api.github.com/repos/* URL.          e.g. "https://api.github.com/repos/python-discord/seasonalbot"               |               V               "python-discord/seasonalbot"          """ +          exp = r"https?:\/\/api.github.com\/repos\/([/\-\_\.\w]+)"          return re.findall(exp, in_url)[0]      @staticmethod      def _summarize_prs(prs: typing.List[dict]) -> typing.Dict:          """ -        Generate statistics from an input list of PR dictionaries, as output by get_october_prs +        Generate statistics from an input list of PR dictionaries, as output by get_october_prs.          Return a dictionary containing:              { @@ -286,13 +293,14 @@ class HacktoberStats:              "top5": [(repo_shortname, ncontributions), ...]              }          """ +          contributed_repos = [pr["repo_shortname"] for pr in prs]          return {"n_prs": len(prs), "top5": Counter(contributed_repos).most_common(5)}      @staticmethod      def _build_top5str(stats: typing.List[tuple]) -> str:          """ -        Build a string from the Top 5 contributions that is compatible with a discord.Embed field +        Build a string from the Top 5 contributions that is compatible with a discord.Embed field.          Top 5 contributions should be a list of tuples, as output in the stats dictionary by          _summarize_prs @@ -301,6 +309,7 @@ class HacktoberStats:             n contribution(s) to [shortname](url)             ...          """ +          baseURL = "https://www.github.com/"          contributionstrs = []          for repo in stats['top5']: @@ -311,9 +320,8 @@ class HacktoberStats:      @staticmethod      def _contributionator(n: int) -> str: -        """ -        Return "contribution" or "contributions" based on the value of n -        """ +        """Return "contribution" or "contributions" based on the value of n.""" +          if n == 1:              return "contribution"          else: @@ -321,9 +329,8 @@ class HacktoberStats:      @staticmethod      def _author_mention_from_context(ctx: commands.Context) -> typing.Tuple: -        """ -        Return stringified Message author ID and mentionable string from commands.Context -        """ +        """Return stringified Message author ID and mentionable string from commands.Context.""" +          author_id = str(ctx.message.author.id)          author_mention = ctx.message.author.mention @@ -331,5 +338,7 @@ class HacktoberStats:  def setup(bot): +    """Hacktoberstats Cog load.""" +      bot.add_cog(HacktoberStats(bot))      log.debug("HacktoberStats cog loaded") diff --git a/bot/seasons/halloween/halloween_facts.py b/bot/seasons/halloween/halloween_facts.py index 098ee432..21c70e76 100644 --- a/bot/seasons/halloween/halloween_facts.py +++ b/bot/seasons/halloween/halloween_facts.py @@ -26,6 +26,7 @@ INTERVAL = timedelta(hours=6).total_seconds()  class HalloweenFacts: +    """A Cog for displaying interesting facts about Halloween."""      def __init__(self, bot):          self.bot = bot @@ -36,31 +37,35 @@ class HalloweenFacts:          random.shuffle(self.facts)      async def on_ready(self): +        """Get event Channel object and initialize fact task loop.""" +          self.channel = self.bot.get_channel(Hacktoberfest.channel_id)          self.bot.loop.create_task(self._fact_publisher_task())      def random_fact(self): +        """Return a random fact from the loaded facts.""" +          return random.choice(self.facts)      @commands.command(name="spookyfact", aliases=("halloweenfact",), brief="Get the most recent Halloween fact")      async def get_random_fact(self, ctx): -        """ -        Reply with the most recent Halloween fact. -        """ +        """Reply with the most recent Halloween fact.""" +          index, fact = self.random_fact()          embed = self._build_embed(index, fact)          await ctx.send(embed=embed)      @staticmethod      def _build_embed(index, fact): -        """ -        Builds a Discord embed from the given fact and its index. -        """ +        """Builds a Discord embed from the given fact and its index.""" +          emoji = random.choice(SPOOKY_EMOJIS)          title = f"{emoji} Halloween Fact #{index + 1}"          return discord.Embed(title=title, description=fact, color=PUMPKIN_ORANGE)  def setup(bot): +    """Halloween facts Cog load.""" +      bot.add_cog(HalloweenFacts(bot))      log.debug("HalloweenFacts cog loaded") diff --git a/bot/seasons/halloween/halloweenify.py b/bot/seasons/halloween/halloweenify.py index cda07472..5b710f7f 100644 --- a/bot/seasons/halloween/halloweenify.py +++ b/bot/seasons/halloween/halloweenify.py @@ -11,9 +11,7 @@ log = logging.getLogger(__name__)  class Halloweenify: -    """ -    A cog to change a invokers nickname to a spooky one! -    """ +    """A cog to change a invokers nickname to a spooky one."""      def __init__(self, bot):          self.bot = bot @@ -21,9 +19,8 @@ class Halloweenify:      @commands.cooldown(1, 300, BucketType.user)      @commands.command()      async def halloweenify(self, ctx): -        """ -        Change your nickname into a much spookier one! -        """ +        """Change your nickname into a much spookier one.""" +          async with ctx.typing():              with open(Path('bot', 'resources', 'halloween', 'halloweenify.json'), 'r') as f:                  data = load(f) @@ -51,5 +48,7 @@ class Halloweenify:  def setup(bot): +    """Halloweenify Cog load.""" +      bot.add_cog(Halloweenify(bot))      log.debug("Halloweenify cog loaded") diff --git a/bot/seasons/halloween/monstersurvey.py b/bot/seasons/halloween/monstersurvey.py index 08873f24..44400a72 100644 --- a/bot/seasons/halloween/monstersurvey.py +++ b/bot/seasons/halloween/monstersurvey.py @@ -16,8 +16,10 @@ EMOJIS = {  class MonsterSurvey:      """ -    Vote for your favorite monster! -    This command allows users to vote for their favorite listed monster. +    Vote for your favorite monster. + +    This Cog allows users to vote for their favorite listed monster. +      Users may change their vote, but only their current vote will be counted.      """ @@ -30,12 +32,18 @@ class MonsterSurvey:              self.voter_registry = json.load(jason)      def json_write(self): +        """Write voting results to a local JSON file.""" +          log.info("Saved Monster Survey Results")          with open(self.registry_location, 'w') as jason:              json.dump(self.voter_registry, jason, indent=2)      def cast_vote(self, id: int, monster: str):          """ +        Cast a user's vote for the specified monster. + +        If the user has already voted, their existing vote is removed. +          :param id: The id of the person voting          :param monster: the string key of the json that represents a monster          :return: None @@ -50,6 +58,8 @@ class MonsterSurvey:                      vr[m]['votes'].remove(id)      def get_name_by_leaderboard_index(self, n): +        """Return the monster at the specified leaderboard index.""" +          n = n - 1          vr = self.voter_registry          top = sorted(vr, key=lambda k: len(vr[k]['votes']), reverse=True) @@ -61,9 +71,7 @@ class MonsterSurvey:          aliases=('ms',)      )      async def monster_group(self, ctx: Context): -        """ -        The base voting command. If nothing is called, then it will return an embed. -        """ +        """The base voting command. If nothing is called, then it will return an embed."""          if ctx.invoked_subcommand is None:              async with ctx.typing(): @@ -95,8 +103,9 @@ class MonsterSurvey:      )      async def monster_vote(self, ctx: Context, name=None):          """ -        Casts a vote for a particular monster, or displays a list of monsters that can be voted for -        if one is not given. +        Cast a vote for a particular monster. + +        Displays a list of monsters that can be voted for if one is not specified.          """          if name is None: @@ -185,6 +194,7 @@ class MonsterSurvey:      async def monster_leaderboard(self, ctx: Context):          """          Shows the current standings. +          :param ctx:          :return:          """ @@ -214,5 +224,7 @@ class MonsterSurvey:  def setup(bot): +    """Monster survey Cog load.""" +      bot.add_cog(MonsterSurvey(bot))      log.debug("MonsterSurvey cog loaded") diff --git a/bot/seasons/halloween/scarymovie.py b/bot/seasons/halloween/scarymovie.py index b280781e..9108c76f 100644 --- a/bot/seasons/halloween/scarymovie.py +++ b/bot/seasons/halloween/scarymovie.py @@ -14,18 +14,15 @@ TMDB_TOKEN = environ.get('TMDB_TOKEN')  class ScaryMovie: -    """ -    Selects a random scary movie and embeds info into discord chat -    """ +    """Selects a random scary movie and embeds info into Discord chat."""      def __init__(self, bot):          self.bot = bot      @commands.command(name='scarymovie', alias=['smovie'])      async def random_movie(self, ctx): -        """ -        Randomly select a scary movie and display information about it. -        """ +        """Randomly select a scary movie and display information about it.""" +          async with ctx.typing():              selection = await self.select_movie()              movie_details = await self.format_metadata(selection) @@ -34,9 +31,7 @@ class ScaryMovie:      @staticmethod      async def select_movie(): -        """ -        Selects a random movie and returns a json of movie details from TMDb -        """ +        """Selects a random movie and returns a json of movie details from TMDb."""          url = 'https://api.themoviedb.org/4/discover/movie'          params = { @@ -70,9 +65,7 @@ class ScaryMovie:      @staticmethod      async def format_metadata(movie): -        """ -        Formats raw TMDb data to be embedded in discord chat -        """ +        """Formats raw TMDb data to be embedded in discord chat."""          # Build the relevant URLs.          movie_id = movie.get("id") @@ -137,5 +130,7 @@ class ScaryMovie:  def setup(bot): +    """Scary movie Cog load.""" +      bot.add_cog(ScaryMovie(bot))      log.debug("ScaryMovie cog loaded") diff --git a/bot/seasons/halloween/spookyavatar.py b/bot/seasons/halloween/spookyavatar.py index a1173740..5c13ad77 100644 --- a/bot/seasons/halloween/spookyavatar.py +++ b/bot/seasons/halloween/spookyavatar.py @@ -13,18 +13,14 @@ log = logging.getLogger(__name__)  class SpookyAvatar: - -    """ -    A cog that spookifies an avatar. -    """ +    """A cog that spookifies an avatar."""      def __init__(self, bot):          self.bot = bot      async def get(self, url): -        """ -        Returns the contents of the supplied url. -        """ +        """Returns the contents of the supplied url.""" +          async with aiohttp.ClientSession() as session:              async with session.get(url) as resp:                  return await resp.read() @@ -32,9 +28,8 @@ class SpookyAvatar:      @commands.command(name='savatar', aliases=('spookyavatar', 'spookify'),                        brief='Spookify an user\'s avatar.')      async def spooky_avatar(self, ctx, user: discord.Member = None): -        """ -        A command to print the user's spookified avatar. -        """ +        """A command to print the user's spookified avatar.""" +          if user is None:              user = ctx.message.author @@ -54,5 +49,7 @@ class SpookyAvatar:  def setup(bot): +    """Spooky avatar Cog load.""" +      bot.add_cog(SpookyAvatar(bot))      log.debug("SpookyAvatar cog loaded") diff --git a/bot/seasons/halloween/spookygif.py b/bot/seasons/halloween/spookygif.py index 1233773b..f898d28b 100644 --- a/bot/seasons/halloween/spookygif.py +++ b/bot/seasons/halloween/spookygif.py @@ -10,18 +10,14 @@ log = logging.getLogger(__name__)  class SpookyGif: -    """ -    A cog to fetch a random spooky gif from the web! -    """ +    """A cog to fetch a random spooky gif from the web."""      def __init__(self, bot):          self.bot = bot      @commands.command(name="spookygif", aliases=("sgif", "scarygif"))      async def spookygif(self, ctx): -        """ -        Fetches a random gif from the GIPHY API and responds with it. -        """ +        """Fetches a random gif from the GIPHY API and responds with it."""          async with ctx.typing():              async with aiohttp.ClientSession() as session: @@ -39,5 +35,7 @@ class SpookyGif:  def setup(bot): +    """Spooky GIF Cog load.""" +      bot.add_cog(SpookyGif(bot))      log.debug("SpookyGif cog loaded") diff --git a/bot/seasons/halloween/spookyreact.py b/bot/seasons/halloween/spookyreact.py index f63cd7e5..553bd285 100644 --- a/bot/seasons/halloween/spookyreact.py +++ b/bot/seasons/halloween/spookyreact.py @@ -17,22 +17,20 @@ SPOOKY_TRIGGERS = {  class SpookyReact: - -    """ -    A cog that makes the bot react to message triggers. -    """ +    """A cog that makes the bot react to message triggers."""      def __init__(self, bot):          self.bot = bot      async def on_message(self, ctx: discord.Message):          """ -        A command to send the seasonalbot github project +        A command to send the seasonalbot github project.          Lines that begin with the bot's command prefix are ignored          Seasonalbot's own messages are ignored          """ +          for trigger in SPOOKY_TRIGGERS.keys():              trigger_test = re.search(SPOOKY_TRIGGERS[trigger][0], ctx.content.lower())              if trigger_test: @@ -52,6 +50,7 @@ class SpookyReact:            * author is the bot            * prefix is not None          """ +          # Check for self reaction          if ctx.author == self.bot.user:              logging.debug(f"Ignoring reactions on self message. Message ID: {ctx.id}") @@ -68,5 +67,7 @@ class SpookyReact:  def setup(bot): +    """Spooky reaction Cog load.""" +      bot.add_cog(SpookyReact(bot))      log.debug("SpookyReact cog loaded") diff --git a/bot/seasons/halloween/spookysound.py b/bot/seasons/halloween/spookysound.py index 4cab1239..cff50897 100644 --- a/bot/seasons/halloween/spookysound.py +++ b/bot/seasons/halloween/spookysound.py @@ -11,9 +11,7 @@ log = logging.getLogger(__name__)  class SpookySound: -    """ -    A cog that plays a spooky sound in a voice channel on command. -    """ +    """A cog that plays a spooky sound in a voice channel on command."""      def __init__(self, bot):          self.bot = bot @@ -24,9 +22,11 @@ class SpookySound:      @commands.command(brief="Play a spooky sound, restricted to once per 2 mins")      async def spookysound(self, ctx):          """ -        Connect to the Hacktoberbot voice channel, play a random spooky sound, then disconnect. Cannot be used more than -        once in 2 minutes. +        Connect to the Hacktoberbot voice channel, play a random spooky sound, then disconnect. + +        Cannot be used more than once in 2 minutes.          """ +          if not self.channel:              await self.bot.wait_until_ready()              self.channel = self.bot.get_channel(Hacktoberfest.voice_id) @@ -39,12 +39,12 @@ class SpookySound:      @staticmethod      async def disconnect(voice): -        """ -        Helper method to disconnect a given voice client. -        """ +        """Helper method to disconnect a given voice client."""          await voice.disconnect()  def setup(bot): +    """Spooky sound Cog load.""" +      bot.add_cog(SpookySound(bot))      log.debug("SpookySound cog loaded") diff --git a/bot/utils/halloween/spookifications.py b/bot/utils/halloween/spookifications.py index 5f2369ae..390cfa49 100644 --- a/bot/utils/halloween/spookifications.py +++ b/bot/utils/halloween/spookifications.py @@ -8,17 +8,20 @@ log = logging.getLogger()  def inversion(im): -    """Inverts an image. +    """ +    Inverts the image.      Returns an inverted image when supplied with an Image object.      """ +      im = im.convert('RGB')      inv = ImageOps.invert(im)      return inv  def pentagram(im): -    """Adds pentagram to image.""" +    """Adds pentagram to the image.""" +      im = im.convert('RGB')      wt, ht = im.size      penta = Image.open('bot/resources/halloween/bloody-pentagram.png') @@ -28,10 +31,13 @@ def pentagram(im):  def bat(im): -    """Adds a bat silhoutte to the image. +    """ +    Adds a bat silhoutte to the image. + +    The bat silhoutte is of a size at least one-fifths that of the original image and may be rotated +    up to 90 degrees anti-clockwise. +    """ -    The bat silhoutte is of a size at least one-fifths that of the original -    image and may be rotated upto 90 degrees anti-clockwise."""      im = im.convert('RGB')      wt, ht = im.size      bat = Image.open('bot/resources/halloween/bat-clipart.png') @@ -49,6 +55,7 @@ def bat(im):  def get_random_effect(im):      """Randomly selects and applies an effect.""" +      effects = [inversion, pentagram, bat]      effect = choice(effects)      log.info("Spookyavatar's chosen effect: " + effect.__name__) | 
