Redjumpman 5d44bfabed [Utils] Initial Work on Predicate Utility (#1985)
* Add files via upload

* Update predicates.py

Changed sender from a discord.Member object to ctx.
Added a channel check.
Combined the same method and channel method into a validator and applied through-out.
valid_role and has_role methods now check for either an id or a name.
contained now uses string.lower() when testing for membership in a collection.

Signed-off-by: Redjumpman <redjumpman@users.noreply.github.com>
2018-10-02 16:19:40 +10:00

150 lines
5.6 KiB
Python

import discord
from collections import Iterable
class MessagePredicate:
"""A simple collection of predicates.
These predicates were made to help simplify checks in message events and
reduce boilerplate code.
For examples:
# valid yes or no response
`ctx.bot.wait_for('message', timeout=15.0, check=Predicate(ctx).confirm)`
# check if message content in under 2000 characters
`check = Predicate(ctx, length=2000).length_under
ctx.bot.wait_for('message', timeout=15.0, check=check)`
Attributes
----------
ctx
Context object.
collection : `Iterable`
Optional argument used for checking if the message content is inside the
declared collection.
length : `int`
Optional argument for comparing message lengths.
value
Optional argument that can be either a string, int, float, or object.
Used for comparison and equality.
Returns
-------
Boolean or it will raise a ValueError if you use a certain methods without an argument or
the value argument is set to an invalid type for a particular method.
"""
def __init__(self, ctx, collection: Iterable = None, length: int = None, value=None):
self.ctx = ctx
self.collection = collection
self.length = length
self.value = value
def valid_source(self, m):
return self.same(m) and self.channel(m)
def same(self, m):
"""Checks if the author of the message is the same as the command issuer."""
return self.ctx.author == m.author
def channel(self, m):
"""Verifies the message was sent from the same channel."""
return self.ctx.channel == m.channel
def cancelled(self, m):
if self.valid_source(m) and m.content.lower() == f"{self.ctx.prefix}cancel":
raise RuntimeError
def confirm(self, m):
"""Checks if the author of the message is the same as the command issuer."""
return self.valid_source(m) and m.content.lower() in ("yes", "no", "y", "n")
def valid_int(self, m):
"""Returns true if the message content is an integer."""
return self.valid_source(m) and m.content.isdigit()
def valid_float(self, m):
"""Returns true if the message content is a float."""
try:
return self.valid_source(m) and float(m.content) >= 1
except ValueError:
return False
def positive(self, m):
"""Returns true if the message content is an integer and is positive"""
return self.valid_source(m) and m.content.isdigit() and int(m.content) >= 0
def valid_role(self, m):
"""Returns true if the message content is an existing role on the server."""
if self.valid_source(m):
if discord.utils.get(self.ctx.guild.roles, name=m.content) is not None:
return True
elif discord.utils.get(self.ctx.guild.roles, id=m.content) is not None:
return True
else:
return False
else:
return False
def has_role(self, m):
"""Returns true if the message content is a role the message sender has."""
if self.valid_source(m):
if discord.utils.get(self.ctx.roles, name=m.content) is not None:
return True
elif discord.utils.get(self.ctx.roles, id=m.content) is not None:
return True
else:
return False
else:
return False
def equal(self, m):
"""Returns true if the message content is equal to the value set."""
return self.valid_source(m) and m.content.lower() == self.value.lower()
def greater(self, m):
"""Returns true if the message content is greater than the value set."""
try:
return self.valid_int(m) or self.valid_float(m) and float(m.content) > int(self.value)
except TypeError:
raise ValueError("Value argument in Predicate() must be an integer or float.")
def less(self, m):
"""Returns true if the message content is less than the value set."""
try:
return self.valid_int(m) or self.valid_float(m) and float(m.content) < int(self.value)
except TypeError:
raise ValueError("Value argument in Predicate() must be an integer or float.")
def member(self, m):
"""Returns true if the message content is the name of a member in the server."""
return (
self.valid_source(m)
and discord.utils.get(self.ctx.guild.members, name=m.content) is not None
)
def length_less(self, m):
"""Returns true if the message content length is less than the provided length."""
try:
return self.valid_source(m) and len(m.content) <= self.length
except TypeError:
raise ValueError("A length must be specified in Predicate().")
def length_greater(self, m):
"""Returns true if the message content length is greater than or equal
to the provided length."""
try:
return self.valid_source(m) and len(m.content) >= self.length
except TypeError:
raise ValueError("A length must be specified in Predicate().")
def contained(self, m):
"""Returns true if the message content is a member of the provided collection."""
try:
return self.valid_source(m) and m.content.lower() in self.collection
except TypeError:
raise ValueError("An iterable was not specified in Predicate().")